Merge branch 'pagefaultgames:main' into flingImplementation
@ -31,11 +31,6 @@
|
|||||||
font-family: 'emerald';
|
font-family: 'emerald';
|
||||||
src: url('./fonts/pokemon-emerald-pro.ttf') format('truetype');
|
src: url('./fonts/pokemon-emerald-pro.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
@font-face {
|
|
||||||
font-family: 'unifont';
|
|
||||||
src: url('./fonts/unifont-15.1.05.otf') format('opentype');
|
|
||||||
size-adjust: 70%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'pkmnems';
|
font-family: 'pkmnems';
|
||||||
|
6
package-lock.json
generated
@ -8365,9 +8365,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.16.0",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
BIN
public/audio/bgm/battle_aqua_magma_boss.mp3
Normal file
BIN
public/audio/bgm/battle_aqua_magma_grunt.mp3
Normal file
BIN
public/audio/bgm/battle_flare_boss.mp3
Normal file
BIN
public/audio/bgm/battle_flare_grunt.mp3
Normal file
BIN
public/audio/bgm/battle_galactic_boss.mp3
Normal file
BIN
public/audio/bgm/battle_galactic_grunt.mp3
Normal file
BIN
public/audio/bgm/battle_plasma_boss.mp3
Normal file
BIN
public/audio/bgm/battle_rocket_boss.mp3
Normal file
BIN
public/audio/bgm/battle_rocket_grunt.mp3
Normal file
BIN
public/audio/bgm/bw/victory_team_plasma.mp3
Normal file
@ -29,8 +29,8 @@
|
|||||||
"15-mega",
|
"15-mega",
|
||||||
"150-mega",
|
"150-mega",
|
||||||
"150-mega",
|
"150-mega",
|
||||||
"150-mega",
|
"150-mega-x",
|
||||||
"150-mega",
|
"150-mega-y",
|
||||||
"18-mega",
|
"18-mega",
|
||||||
"18-mega",
|
"18-mega",
|
||||||
"181-mega",
|
"181-mega",
|
||||||
@ -185,8 +185,8 @@
|
|||||||
"531-mega",
|
"531-mega",
|
||||||
"6-mega",
|
"6-mega",
|
||||||
"6-mega",
|
"6-mega",
|
||||||
"6-mega",
|
"6-mega-x",
|
||||||
"6-mega",
|
"6-mega-y",
|
||||||
"6058",
|
"6058",
|
||||||
"6058",
|
"6058",
|
||||||
"6059",
|
"6059",
|
||||||
@ -1161,8 +1161,8 @@
|
|||||||
"15b-mega",
|
"15b-mega",
|
||||||
"150b-mega",
|
"150b-mega",
|
||||||
"150b-mega",
|
"150b-mega",
|
||||||
"150b-mega",
|
"150b-mega-x",
|
||||||
"150b-mega",
|
"150b-mega-y",
|
||||||
"18b-mega",
|
"18b-mega",
|
||||||
"18b-mega",
|
"18b-mega",
|
||||||
"181b-mega",
|
"181b-mega",
|
||||||
@ -1317,8 +1317,8 @@
|
|||||||
"531b-mega",
|
"531b-mega",
|
||||||
"6b-mega",
|
"6b-mega",
|
||||||
"6b-mega",
|
"6b-mega",
|
||||||
"6b-mega",
|
"6b-mega-x",
|
||||||
"6b-mega",
|
"6b-mega-y",
|
||||||
"6058b",
|
"6058b",
|
||||||
"6058b",
|
"6058b",
|
||||||
"6059b",
|
"6059b",
|
||||||
@ -2295,8 +2295,8 @@
|
|||||||
"15sb-mega",
|
"15sb-mega",
|
||||||
"150sb-mega",
|
"150sb-mega",
|
||||||
"150sb-mega",
|
"150sb-mega",
|
||||||
"150sb-mega",
|
"150sb-mega-x",
|
||||||
"150sb-mega",
|
"150sb-mega-y",
|
||||||
"18sb-mega",
|
"18sb-mega",
|
||||||
"18sb-mega",
|
"18sb-mega",
|
||||||
"181sb-mega",
|
"181sb-mega",
|
||||||
@ -2451,8 +2451,8 @@
|
|||||||
"531sb-mega",
|
"531sb-mega",
|
||||||
"6sb-mega",
|
"6sb-mega",
|
||||||
"6sb-mega",
|
"6sb-mega",
|
||||||
"6sb-mega",
|
"6sb-mega-x",
|
||||||
"6sb-mega",
|
"6sb-mega-y",
|
||||||
"6058sb",
|
"6058sb",
|
||||||
"6058sb",
|
"6058sb",
|
||||||
"6059sb",
|
"6059sb",
|
||||||
@ -3432,8 +3432,8 @@
|
|||||||
"15s-mega",
|
"15s-mega",
|
||||||
"150s-mega",
|
"150s-mega",
|
||||||
"150s-mega",
|
"150s-mega",
|
||||||
"150s-mega",
|
"150s-mega-x",
|
||||||
"150s-mega",
|
"150s-mega-y",
|
||||||
"18s-mega",
|
"18s-mega",
|
||||||
"18s-mega",
|
"18s-mega",
|
||||||
"181s-mega",
|
"181s-mega",
|
||||||
@ -3588,8 +3588,8 @@
|
|||||||
"531s-mega",
|
"531s-mega",
|
||||||
"6s-mega",
|
"6s-mega",
|
||||||
"6s-mega",
|
"6s-mega",
|
||||||
"6s-mega",
|
"6s-mega-x",
|
||||||
"6s-mega",
|
"6s-mega-y",
|
||||||
"6058s",
|
"6058s",
|
||||||
"6058s",
|
"6058s",
|
||||||
"6059s",
|
"6059s",
|
||||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
BIN
public/images/items/eviolite.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 713 B |
Before Width: | Height: | Size: 565 B |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
@ -1,92 +1,36 @@
|
|||||||
{
|
{
|
||||||
"1": {
|
"1": {
|
||||||
"207cc1": "c67429",
|
|
||||||
"44b4f4": "eea747",
|
"44b4f4": "eea747",
|
||||||
"1d5486": "923d13",
|
|
||||||
"826c4d": "dd493b",
|
"826c4d": "dd493b",
|
||||||
"f8eaba": "fff3ec",
|
"f8eaba": "fff3ec",
|
||||||
"cdac7b": "bd9b8e",
|
"cdac7b": "bd9b8e",
|
||||||
"0d0d0d": "101010",
|
|
||||||
"090909": "101010",
|
|
||||||
"3b3f47": "c32625",
|
|
||||||
"3c3f47": "c32625",
|
|
||||||
"1f2025": "101010",
|
|
||||||
"202226": "101010",
|
|
||||||
"5e5f62": "dd493b",
|
"5e5f62": "dd493b",
|
||||||
"1c5486": "923d13",
|
|
||||||
"1f7cc1": "c67429",
|
"1f7cc1": "c67429",
|
||||||
"826b4d": "dd493b",
|
|
||||||
"992137": "8691d5",
|
|
||||||
"e6414a": "c9d4ff",
|
"e6414a": "c9d4ff",
|
||||||
"000000": "101010",
|
|
||||||
"f4f4f4": "f8f8f8",
|
"f4f4f4": "f8f8f8",
|
||||||
"992035": "8691d5",
|
|
||||||
"2b2d33": "682a23",
|
|
||||||
"2a2c31": "682a23",
|
|
||||||
"282a2e": "682a23",
|
|
||||||
"e0e0e0": "f37754",
|
"e0e0e0": "f37754",
|
||||||
"030303": "101010",
|
|
||||||
"393f47": "c32625",
|
|
||||||
"1c1d22": "101010",
|
|
||||||
"195486": "923d13",
|
|
||||||
"1c7cc1": "c67429",
|
|
||||||
"82694d": "dd493b",
|
|
||||||
"991d31": "8691d5",
|
"991d31": "8691d5",
|
||||||
"ffffff": "f8f8f8",
|
|
||||||
"26282c": "682a23",
|
|
||||||
"060606": "101010",
|
"060606": "101010",
|
||||||
"3a3f47": "c32625",
|
"3a3f47": "c32625",
|
||||||
"1d1f24": "101010",
|
|
||||||
"1a5486": "923d13",
|
"1a5486": "923d13",
|
||||||
"1d7cc1": "c67429",
|
"1d7cc1": "c67429",
|
||||||
"826a4d": "dd493b",
|
|
||||||
"991f33": "8691d5",
|
|
||||||
"292b2f": "682a23",
|
|
||||||
"27292d": "682a23"
|
"27292d": "682a23"
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"207cc1": "582c81",
|
|
||||||
"44b4f4": "7b43a1",
|
"44b4f4": "7b43a1",
|
||||||
"1d5486": "411f70",
|
|
||||||
"826c4d": "f2a366",
|
"826c4d": "f2a366",
|
||||||
"f8eaba": "ffedf4",
|
"f8eaba": "ffedf4",
|
||||||
"cdac7b": "d7aec0",
|
"cdac7b": "d7aec0",
|
||||||
"0d0d0d": "101010",
|
|
||||||
"090909": "101010",
|
|
||||||
"3b3f47": "bc6532",
|
|
||||||
"3c3f47": "bc6532",
|
|
||||||
"1f2025": "101010",
|
|
||||||
"202226": "101010",
|
|
||||||
"5e5f62": "f2a366",
|
"5e5f62": "f2a366",
|
||||||
"1c5486": "411f70",
|
|
||||||
"1f7cc1": "582c81",
|
"1f7cc1": "582c81",
|
||||||
"826b4d": "f2a366",
|
|
||||||
"992137": "a62869",
|
|
||||||
"e6414a": "e15693",
|
"e6414a": "e15693",
|
||||||
"000000": "101010",
|
|
||||||
"f4f4f4": "f8f8f8",
|
"f4f4f4": "f8f8f8",
|
||||||
"992035": "a62869",
|
|
||||||
"2b2d33": "202b47",
|
|
||||||
"2a2c31": "202b47",
|
|
||||||
"282a2e": "202b47",
|
|
||||||
"e0e0e0": "ffdb85",
|
"e0e0e0": "ffdb85",
|
||||||
"030303": "101010",
|
|
||||||
"393f47": "bc6532",
|
|
||||||
"1c1d22": "101010",
|
|
||||||
"195486": "411f70",
|
|
||||||
"1c7cc1": "582c81",
|
|
||||||
"82694d": "f2a366",
|
|
||||||
"991d31": "a62869",
|
"991d31": "a62869",
|
||||||
"ffffff": "f8f8f8",
|
|
||||||
"26282c": "202b47",
|
|
||||||
"060606": "101010",
|
"060606": "101010",
|
||||||
"3a3f47": "bc6532",
|
"3a3f47": "bc6532",
|
||||||
"1d1f24": "101010",
|
|
||||||
"1a5486": "411f70",
|
"1a5486": "411f70",
|
||||||
"1d7cc1": "582c81",
|
"1d7cc1": "582c81",
|
||||||
"826a4d": "f2a366",
|
|
||||||
"991f33": "a62869",
|
|
||||||
"292b2f": "202b47",
|
|
||||||
"27292d": "202b47"
|
"27292d": "202b47"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "678msb.png",
|
"image": "9-mega_2.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 55,
|
"w": 88,
|
||||||
"h": 55
|
"h": 88
|
||||||
},
|
},
|
||||||
"scale": 1,
|
"scale": 1,
|
||||||
"frames": [
|
"frames": [
|
||||||
@ -14,20 +14,20 @@
|
|||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"sourceSize": {
|
||||||
"w": 46,
|
"w": 88,
|
||||||
"h": 55
|
"h": 87
|
||||||
},
|
},
|
||||||
"spriteSourceSize": {
|
"spriteSourceSize": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 46,
|
"w": 88,
|
||||||
"h": 55
|
"h": 87
|
||||||
},
|
},
|
||||||
"frame": {
|
"frame": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 46,
|
"w": 88,
|
||||||
"h": 55
|
"h": 87
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -36,6 +36,6 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
"version": "3.0",
|
"version": "3.0",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:979291307687f1a4af47bc4d29542ccf:f61247ececc23f282bb95c5bfe49e179:bbcc2663448733722c64bc1ebafbf9c6$"
|
"smartupdate": "$TexturePacker:SmartUpdate:9b1bebbbe735399ba2678aa35a42b156:2dc7c20135acd855e9e97cb010985396:00f61506d33ec61875296e0fb5a82ee9$"
|
||||||
}
|
}
|
||||||
}
|
}
|
BIN
public/images/pokemon/variant/exp/9-mega_2.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
41
public/images/pokemon/variant/exp/9-mega_3.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "9-mega_3.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 88,
|
||||||
|
"h": 88
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 88,
|
||||||
|
"h": 87
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 88,
|
||||||
|
"h": 87
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 88,
|
||||||
|
"h": 87
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:9b1bebbbe735399ba2678aa35a42b156:2dc7c20135acd855e9e97cb010985396:00f61506d33ec61875296e0fb5a82ee9$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/pokemon/variant/exp/9-mega_3.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
41
public/images/pokemon/variant/exp/back/9-mega_2.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "9-mega_2.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:5d9f38fc4da0e99e00a40be3452a927c:2c58504a78e2752d4c536f8a79dab703:00f61506d33ec61875296e0fb5a82ee9$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/pokemon/variant/exp/back/9-mega_2.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
41
public/images/pokemon/variant/exp/back/9-mega_3.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "9-mega_3.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 77,
|
||||||
|
"h": 77
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:5d9f38fc4da0e99e00a40be3452a927c:2c58504a78e2752d4c536f8a79dab703:00f61506d33ec61875296e0fb5a82ee9$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/pokemon/variant/exp/back/9-mega_3.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 276 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 269 B |
Before Width: | Height: | Size: 293 B |
Before Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 261 B |
Before Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 880 B |
Before Width: | Height: | Size: 247 B |
Before Width: | Height: | Size: 256 B |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "types_pt_BR.png",
|
"image": "types_pt-BR.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,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "types_zh_CN.png",
|
"image": "types_zh-CN.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 32,
|
"w": 32,
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "types_zh_TW.png",
|
"image": "types_zh-TW.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 32,
|
"w": 32,
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 234 B |
78
public/images/ui/legacy/shiny_icons.json
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "shiny_icons.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "1",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 15,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 15,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "2",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 30,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 30,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
public/images/ui/legacy/shiny_icons.png
Normal file
After Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 800 B After Width: | Height: | Size: 800 B |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B |
78
public/images/ui/shiny_icons.json
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "shiny_icons.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "1",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 15,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 15,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "2",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 30,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 30,
|
||||||
|
"y": 0,
|
||||||
|
"w": 15,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
public/images/ui/shiny_icons.png
Normal file
After Width: | Height: | Size: 296 B |
9
src/@types/i18next.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { enConfig } from "#app/locales/en/config.js";
|
||||||
|
|
||||||
|
// Module declared to make referencing keys in the localization files type-safe.
|
||||||
|
declare module "i18next" {
|
||||||
|
interface CustomTypeOptions {
|
||||||
|
defaultNS: "menu", // needed here as well for typedoc
|
||||||
|
resources: typeof enConfig
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import UI from "./ui/ui";
|
|||||||
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
|
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
|
||||||
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
|
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
|
||||||
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
|
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
|
||||||
|
import { Constructor } from "#app/utils";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
|
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
|
||||||
import { PokeballType } from "./data/pokeball";
|
import { PokeballType } from "./data/pokeball";
|
||||||
@ -36,7 +37,7 @@ import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
|
|||||||
import { addUiThemeOverrides } from "./ui/ui-theme";
|
import { addUiThemeOverrides } from "./ui/ui-theme";
|
||||||
import PokemonData from "./system/pokemon-data";
|
import PokemonData from "./system/pokemon-data";
|
||||||
import { Nature } from "./data/nature";
|
import { Nature } from "./data/nature";
|
||||||
import { SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges } from "./data/pokemon-forms";
|
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges } from "./data/pokemon-forms";
|
||||||
import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase";
|
import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase";
|
||||||
import { getTypeRgb } from "./data/type";
|
import { getTypeRgb } from "./data/type";
|
||||||
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler";
|
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler";
|
||||||
@ -47,7 +48,7 @@ import { biomeDepths, getBiomeName } from "./data/biomes";
|
|||||||
import { SceneBase } from "./scene-base";
|
import { SceneBase } from "./scene-base";
|
||||||
import CandyBar from "./ui/candy-bar";
|
import CandyBar from "./ui/candy-bar";
|
||||||
import { Variant, variantData } from "./data/variant";
|
import { Variant, variantData } from "./data/variant";
|
||||||
import { Localizable } from "./plugins/i18n";
|
import { Localizable } from "#app/interfaces/locales";
|
||||||
import * as Overrides from "./overrides";
|
import * as Overrides from "./overrides";
|
||||||
import {InputsController} from "./inputs-controller";
|
import {InputsController} from "./inputs-controller";
|
||||||
import {UiInputs} from "./ui-inputs";
|
import {UiInputs} from "./ui-inputs";
|
||||||
@ -156,6 +157,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
public fusionPaletteSwaps: boolean = true;
|
public fusionPaletteSwaps: boolean = true;
|
||||||
public enableTouchControls: boolean = false;
|
public enableTouchControls: boolean = false;
|
||||||
public enableVibration: boolean = false;
|
public enableVibration: boolean = false;
|
||||||
|
public showBgmBar: boolean = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the selected battle style.
|
* Determines the selected battle style.
|
||||||
* - 0 = 'Switch'
|
* - 0 = 'Switch'
|
||||||
@ -218,6 +221,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
public arenaFlyout: ArenaFlyout;
|
public arenaFlyout: ArenaFlyout;
|
||||||
|
|
||||||
private fieldOverlay: Phaser.GameObjects.Rectangle;
|
private fieldOverlay: Phaser.GameObjects.Rectangle;
|
||||||
|
private shopOverlay: Phaser.GameObjects.Rectangle;
|
||||||
public modifiers: PersistentModifier[];
|
public modifiers: PersistentModifier[];
|
||||||
private enemyModifiers: PersistentModifier[];
|
private enemyModifiers: PersistentModifier[];
|
||||||
public uiContainer: Phaser.GameObjects.Container;
|
public uiContainer: Phaser.GameObjects.Container;
|
||||||
@ -331,7 +335,9 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
launchBattle() {
|
launchBattle() {
|
||||||
this.arenaBg = this.add.sprite(0, 0, "plains_bg");
|
this.arenaBg = this.add.sprite(0, 0, "plains_bg");
|
||||||
|
this.arenaBg.setName("sprite-arena-bg");
|
||||||
this.arenaBgTransition = this.add.sprite(0, 0, "plains_bg");
|
this.arenaBgTransition = this.add.sprite(0, 0, "plains_bg");
|
||||||
|
this.arenaBgTransition.setName("sprite-arena-bg-transition");
|
||||||
|
|
||||||
[ this.arenaBgTransition, this.arenaBg ].forEach(a => {
|
[ this.arenaBgTransition, this.arenaBg ].forEach(a => {
|
||||||
a.setPipeline(this.fieldSpritePipeline);
|
a.setPipeline(this.fieldSpritePipeline);
|
||||||
@ -341,13 +347,13 @@ export default class BattleScene extends SceneBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const field = this.add.container(0, 0);
|
const field = this.add.container(0, 0);
|
||||||
|
field.setName("field");
|
||||||
field.setScale(6);
|
field.setScale(6);
|
||||||
field.setName("container-field");
|
|
||||||
|
|
||||||
this.field = field;
|
this.field = field;
|
||||||
|
|
||||||
const fieldUI = this.add.container(0, this.game.canvas.height);
|
const fieldUI = this.add.container(0, this.game.canvas.height);
|
||||||
fieldUI.setName("container-field-ui");
|
fieldUI.setName("field-ui");
|
||||||
fieldUI.setDepth(1);
|
fieldUI.setDepth(1);
|
||||||
fieldUI.setScale(6);
|
fieldUI.setScale(6);
|
||||||
|
|
||||||
@ -371,7 +377,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.add.existing(transition);
|
this.add.existing(transition);
|
||||||
|
|
||||||
const uiContainer = this.add.container(0, 0);
|
const uiContainer = this.add.container(0, 0);
|
||||||
uiContainer.setName("container-ui");
|
uiContainer.setName("ui");
|
||||||
uiContainer.setDepth(2);
|
uiContainer.setDepth(2);
|
||||||
uiContainer.setScale(6);
|
uiContainer.setScale(6);
|
||||||
|
|
||||||
@ -385,16 +391,22 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.fieldOverlay.setAlpha(0);
|
this.fieldOverlay.setAlpha(0);
|
||||||
this.fieldUI.add(this.fieldOverlay);
|
this.fieldUI.add(this.fieldOverlay);
|
||||||
|
|
||||||
|
this.shopOverlay = this.add.rectangle(0, overlayHeight * -1 - 48, overlayWidth, overlayHeight, 0x070707);
|
||||||
|
this.shopOverlay.setName("rect-shop-overlay");
|
||||||
|
this.shopOverlay.setOrigin(0, 0);
|
||||||
|
this.shopOverlay.setAlpha(0);
|
||||||
|
this.fieldUI.add(this.shopOverlay);
|
||||||
|
|
||||||
this.modifiers = [];
|
this.modifiers = [];
|
||||||
this.enemyModifiers = [];
|
this.enemyModifiers = [];
|
||||||
|
|
||||||
this.modifierBar = new ModifierBar(this);
|
this.modifierBar = new ModifierBar(this);
|
||||||
this.modifierBar.setName("container-modifier-bar");
|
this.modifierBar.setName("modifier-bar");
|
||||||
this.add.existing(this.modifierBar);
|
this.add.existing(this.modifierBar);
|
||||||
uiContainer.add(this.modifierBar);
|
uiContainer.add(this.modifierBar);
|
||||||
|
|
||||||
this.enemyModifierBar = new ModifierBar(this, true);
|
this.enemyModifierBar = new ModifierBar(this, true);
|
||||||
this.enemyModifierBar.setName("container-enemy-modifier-bar");
|
this.enemyModifierBar.setName("enemy-modifier-bar");
|
||||||
this.add.existing(this.enemyModifierBar);
|
this.add.existing(this.enemyModifierBar);
|
||||||
uiContainer.add(this.enemyModifierBar);
|
uiContainer.add(this.enemyModifierBar);
|
||||||
|
|
||||||
@ -405,28 +417,28 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.fieldUI.add(this.charSprite);
|
this.fieldUI.add(this.charSprite);
|
||||||
|
|
||||||
this.pbTray = new PokeballTray(this, true);
|
this.pbTray = new PokeballTray(this, true);
|
||||||
this.pbTray.setName("container-pb-tray");
|
this.pbTray.setName("pb-tray");
|
||||||
this.pbTray.setup();
|
this.pbTray.setup();
|
||||||
|
|
||||||
this.pbTrayEnemy = new PokeballTray(this, false);
|
this.pbTrayEnemy = new PokeballTray(this, false);
|
||||||
this.pbTrayEnemy.setName("container-enemy-pb-tray");
|
this.pbTrayEnemy.setName("enemy-pb-tray");
|
||||||
this.pbTrayEnemy.setup();
|
this.pbTrayEnemy.setup();
|
||||||
|
|
||||||
this.fieldUI.add(this.pbTray);
|
this.fieldUI.add(this.pbTray);
|
||||||
this.fieldUI.add(this.pbTrayEnemy);
|
this.fieldUI.add(this.pbTrayEnemy);
|
||||||
|
|
||||||
this.abilityBar = new AbilityBar(this);
|
this.abilityBar = new AbilityBar(this);
|
||||||
this.abilityBar.setName("container-ability-bar");
|
this.abilityBar.setName("ability-bar");
|
||||||
this.abilityBar.setup();
|
this.abilityBar.setup();
|
||||||
this.fieldUI.add(this.abilityBar);
|
this.fieldUI.add(this.abilityBar);
|
||||||
|
|
||||||
this.partyExpBar = new PartyExpBar(this);
|
this.partyExpBar = new PartyExpBar(this);
|
||||||
this.partyExpBar.setName("container-party-exp-bar");
|
this.partyExpBar.setName("party-exp-bar");
|
||||||
this.partyExpBar.setup();
|
this.partyExpBar.setup();
|
||||||
this.fieldUI.add(this.partyExpBar);
|
this.fieldUI.add(this.partyExpBar);
|
||||||
|
|
||||||
this.candyBar = new CandyBar(this);
|
this.candyBar = new CandyBar(this);
|
||||||
this.candyBar.setName("container-candy-bar");
|
this.candyBar.setName("candy-bar");
|
||||||
this.candyBar.setup();
|
this.candyBar.setup();
|
||||||
this.fieldUI.add(this.candyBar);
|
this.fieldUI.add(this.candyBar);
|
||||||
|
|
||||||
@ -478,13 +490,13 @@ export default class BattleScene extends SceneBase {
|
|||||||
const loadPokemonAssets = [];
|
const loadPokemonAssets = [];
|
||||||
|
|
||||||
this.arenaPlayer = new ArenaBase(this, true);
|
this.arenaPlayer = new ArenaBase(this, true);
|
||||||
this.arenaPlayer.setName("container-arena-player");
|
this.arenaPlayer.setName("arena-player");
|
||||||
this.arenaPlayerTransition = new ArenaBase(this, true);
|
this.arenaPlayerTransition = new ArenaBase(this, true);
|
||||||
this.arenaPlayerTransition.setName("container-arena-player-transition");
|
this.arenaPlayerTransition.setName("arena-player-transition");
|
||||||
this.arenaEnemy = new ArenaBase(this, false);
|
this.arenaEnemy = new ArenaBase(this, false);
|
||||||
this.arenaEnemy.setName("container-arena-enemy");
|
this.arenaEnemy.setName("arena-enemy");
|
||||||
this.arenaNextEnemy = new ArenaBase(this, false);
|
this.arenaNextEnemy = new ArenaBase(this, false);
|
||||||
this.arenaNextEnemy.setName("container-arena-next-enemy");
|
this.arenaNextEnemy.setName("arena-next-enemy");
|
||||||
|
|
||||||
this.arenaBgTransition.setVisible(false);
|
this.arenaBgTransition.setVisible(false);
|
||||||
this.arenaPlayerTransition.setVisible(false);
|
this.arenaPlayerTransition.setVisible(false);
|
||||||
@ -736,6 +748,14 @@ export default class BattleScene extends SceneBase {
|
|||||||
: ret;
|
: ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ModifierBar of this scene, which is declared private and therefore not accessible elsewhere
|
||||||
|
* @returns {ModifierBar}
|
||||||
|
*/
|
||||||
|
getModifierBar(): ModifierBar {
|
||||||
|
return this.modifierBar;
|
||||||
|
}
|
||||||
|
|
||||||
// store info toggles to be accessible by the ui
|
// store info toggles to be accessible by the ui
|
||||||
addInfoToggle(infoToggle: InfoToggle): void {
|
addInfoToggle(infoToggle: InfoToggle): void {
|
||||||
this.infoToggles.push(infoToggle);
|
this.infoToggles.push(infoToggle);
|
||||||
@ -797,8 +817,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
addPokemonIcon(pokemon: Pokemon, x: number, y: number, originX: number = 0.5, originY: number = 0.5, ignoreOverride: boolean = false): Phaser.GameObjects.Container {
|
addPokemonIcon(pokemon: Pokemon, x: number, y: number, originX: number = 0.5, originY: number = 0.5, ignoreOverride: boolean = false): Phaser.GameObjects.Container {
|
||||||
const container = this.add.container(x, y);
|
const container = this.add.container(x, y);
|
||||||
|
container.setName(`${pokemon.name}-icon`);
|
||||||
|
|
||||||
const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(ignoreOverride));
|
const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(ignoreOverride));
|
||||||
|
icon.setName(`sprite-${pokemon.name}-icon`);
|
||||||
icon.setFrame(pokemon.getIconId(true));
|
icon.setFrame(pokemon.getIconId(true));
|
||||||
// Temporary fix to show pokemon's default icon if variant icon doesn't exist
|
// Temporary fix to show pokemon's default icon if variant icon doesn't exist
|
||||||
if (icon.frame.name !== pokemon.getIconId(true)) {
|
if (icon.frame.name !== pokemon.getIconId(true)) {
|
||||||
@ -815,6 +837,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
if (pokemon.isFusion()) {
|
if (pokemon.isFusion()) {
|
||||||
const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride));
|
const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride));
|
||||||
|
fusionIcon.setName("sprite-fusion-icon");
|
||||||
fusionIcon.setOrigin(0.5, 0);
|
fusionIcon.setOrigin(0.5, 0);
|
||||||
fusionIcon.setFrame(pokemon.getFusionIconId(true));
|
fusionIcon.setFrame(pokemon.getFusionIconId(true));
|
||||||
|
|
||||||
@ -1099,8 +1122,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
|
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
|
||||||
|
|
||||||
for (const pokemon of this.getParty()) {
|
for (const pokemon of this.getParty()) {
|
||||||
if (pokemon.hasAbility(Abilities.ICE_FACE)) {
|
// Only trigger form change when Eiscue is in Noice form
|
||||||
pokemon.formIndex = 0;
|
// Hardcoded Eiscue for now in case it is fused with another pokemon
|
||||||
|
if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
|
||||||
|
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
pokemon.resetBattleData();
|
pokemon.resetBattleData();
|
||||||
@ -1396,6 +1421,30 @@ export default class BattleScene extends SceneBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showShopOverlay(duration: integer): Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.shopOverlay,
|
||||||
|
alpha: 0.8,
|
||||||
|
ease: "Sine.easeOut",
|
||||||
|
duration: duration,
|
||||||
|
onComplete: () => resolve()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hideShopOverlay(duration: integer): Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.shopOverlay,
|
||||||
|
alpha: 0,
|
||||||
|
duration: duration,
|
||||||
|
ease: "Cubic.easeIn",
|
||||||
|
onComplete: () => resolve()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
showEnemyModifierBar(): void {
|
showEnemyModifierBar(): void {
|
||||||
this.enemyModifierBar.setVisible(true);
|
this.enemyModifierBar.setVisible(true);
|
||||||
}
|
}
|
||||||
@ -1407,6 +1456,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
updateBiomeWaveText(): void {
|
updateBiomeWaveText(): void {
|
||||||
const isBoss = !(this.currentBattle.waveIndex % 10);
|
const isBoss = !(this.currentBattle.waveIndex % 10);
|
||||||
const biomeString: string = getBiomeName(this.arena.biomeType);
|
const biomeString: string = getBiomeName(this.arena.biomeType);
|
||||||
|
this.fieldUI.moveAbove(this.biomeWaveText, this.luckText);
|
||||||
this.biomeWaveText.setText( biomeString + " - " + this.currentBattle.waveIndex.toString());
|
this.biomeWaveText.setText( biomeString + " - " + this.currentBattle.waveIndex.toString());
|
||||||
this.biomeWaveText.setColor(!isBoss ? "#ffffff" : "#f89890");
|
this.biomeWaveText.setColor(!isBoss ? "#ffffff" : "#f89890");
|
||||||
this.biomeWaveText.setShadowColor(!isBoss ? "#636363" : "#984038");
|
this.biomeWaveText.setShadowColor(!isBoss ? "#636363" : "#984038");
|
||||||
@ -1591,6 +1641,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
: this.getBgmLoopPoint(bgmName);
|
: this.getBgmLoopPoint(bgmName);
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
const playNewBgm = () => {
|
const playNewBgm = () => {
|
||||||
|
this.ui.bgmBar.setBgmToBgmBar(bgmName);
|
||||||
if (bgmName === null && this.bgm && !this.bgm.pendingRemove) {
|
if (bgmName === null && this.bgm && !this.bgm.pendingRemove) {
|
||||||
this.bgm.play({
|
this.bgm.play({
|
||||||
volume: this.masterVolume * this.bgmVolume
|
volume: this.masterVolume * this.bgmVolume
|
||||||
@ -1846,8 +1897,26 @@ export default class BattleScene extends SceneBase {
|
|||||||
return 13.940;
|
return 13.940;
|
||||||
case "end_summit": //PMD RTDX Sky Tower Summit
|
case "end_summit": //PMD RTDX Sky Tower Summit
|
||||||
return 30.025;
|
return 30.025;
|
||||||
|
case "battle_rocket_grunt": //HGSS Team Rocket Battle
|
||||||
|
return 12.707;
|
||||||
|
case "battle_aqua_magma_grunt": //ORAS Team Aqua & Magma Battle
|
||||||
|
return 12.062;
|
||||||
|
case "battle_galactic_grunt": //BDSP Team Galactic Battle
|
||||||
|
return 13.043;
|
||||||
case "battle_plasma_grunt": //BW Team Plasma Battle
|
case "battle_plasma_grunt": //BW Team Plasma Battle
|
||||||
return 12.974;
|
return 12.974;
|
||||||
|
case "battle_flare_grunt": //XY Team Flare Battle
|
||||||
|
return 4.228;
|
||||||
|
case "battle_rocket_boss": //USUM Giovanni Battle
|
||||||
|
return 9.115;
|
||||||
|
case "battle_aqua_magma_boss": //ORAS Archie & Maxie Battle
|
||||||
|
return 14.847;
|
||||||
|
case "battle_galactic_boss": //BDSP Cyrus Battle
|
||||||
|
return 106.962;
|
||||||
|
case "battle_plasma_boss": //B2W2 Ghetsis Battle
|
||||||
|
return 25.624;
|
||||||
|
case "battle_flare_boss": //XY Lysandre Battle
|
||||||
|
return 8.085;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2340,8 +2409,14 @@ export default class BattleScene extends SceneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getModifiers(modifierType: { new(...args: any[]): Modifier }, player: boolean = true): PersistentModifier[] {
|
/**
|
||||||
return (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType);
|
* Get all of the modifiers that match `modifierType`
|
||||||
|
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
|
||||||
|
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
|
||||||
|
* @returns the list of all modifiers that matched `modifierType`.
|
||||||
|
*/
|
||||||
|
getModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true): T[] {
|
||||||
|
return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType);
|
||||||
}
|
}
|
||||||
|
|
||||||
findModifiers(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier[] {
|
findModifiers(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier[] {
|
||||||
@ -2352,7 +2427,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m));
|
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyShuffledModifiers(scene: BattleScene, modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier[] {
|
applyShuffledModifiers(scene: BattleScene, modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier[] {
|
||||||
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
||||||
scene.executeWithSeedOffset(() => {
|
scene.executeWithSeedOffset(() => {
|
||||||
const shuffleModifiers = mods => {
|
const shuffleModifiers = mods => {
|
||||||
@ -2367,7 +2442,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return this.applyModifiersInternal(modifiers, player, args);
|
return this.applyModifiersInternal(modifiers, player, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyModifiers(modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier[] {
|
applyModifiers(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier[] {
|
||||||
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
||||||
return this.applyModifiersInternal(modifiers, player, args);
|
return this.applyModifiersInternal(modifiers, player, args);
|
||||||
}
|
}
|
||||||
@ -2384,7 +2459,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return appliedModifiers;
|
return appliedModifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyModifier(modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier {
|
applyModifier(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier {
|
||||||
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
||||||
for (const modifier of modifiers) {
|
for (const modifier of modifiers) {
|
||||||
if (modifier.apply(args)) {
|
if (modifier.apply(args)) {
|
||||||
@ -2396,7 +2471,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: { new(...args: any[]): SpeciesFormChangeTrigger }, delayed: boolean = false, modal: boolean = false): boolean {
|
triggerPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: Constructor<SpeciesFormChangeTrigger>, delayed: boolean = false, modal: boolean = false): boolean {
|
||||||
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)) {
|
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)) {
|
||||||
const matchingFormChange = pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
|
const matchingFormChange = pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
|
||||||
if (matchingFormChange) {
|
if (matchingFormChange) {
|
||||||
@ -2420,7 +2495,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void {
|
validateAchvs(achvType: Constructor<Achv>, ...args: unknown[]): void {
|
||||||
const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType);
|
const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType);
|
||||||
for (const achv of filteredAchvs) {
|
for (const achv of filteredAchvs) {
|
||||||
this.validateAchv(achv, args);
|
this.validateAchv(achv, args);
|
||||||
|
@ -7,6 +7,7 @@ import { GameMode } from "./game-mode";
|
|||||||
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
||||||
import { PokeballType } from "./data/pokeball";
|
import { PokeballType } from "./data/pokeball";
|
||||||
import {trainerConfigs} from "#app/data/trainer-config";
|
import {trainerConfigs} from "#app/data/trainer-config";
|
||||||
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { BattleSpec } from "#enums/battle-spec";
|
import { BattleSpec } from "#enums/battle-spec";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
@ -166,6 +167,10 @@ export default class Battle {
|
|||||||
const moneyAmount = new Utils.IntegerHolder(scene.currentBattle.moneyScattered);
|
const moneyAmount = new Utils.IntegerHolder(scene.currentBattle.moneyScattered);
|
||||||
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
||||||
|
|
||||||
|
if (scene.arena.getTag(ArenaTagType.HAPPY_HOUR)) {
|
||||||
|
moneyAmount.value *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
scene.addMoney(moneyAmount.value);
|
scene.addMoney(moneyAmount.value);
|
||||||
|
|
||||||
scene.queueMessage(`You picked up ₽${moneyAmount.value.toLocaleString("en-US")}!`, null, true);
|
scene.queueMessage(`You picked up ₽${moneyAmount.value.toLocaleString("en-US")}!`, null, true);
|
||||||
@ -426,8 +431,8 @@ export interface FixedBattleConfigs {
|
|||||||
/**
|
/**
|
||||||
* Youngster/Lass on 5
|
* Youngster/Lass on 5
|
||||||
* Rival on 8, 55, 95, 145, 195
|
* Rival on 8, 55, 95, 145, 195
|
||||||
* Evil team grunts on 35, 62, 64, 65, 112, 114 (Not currently spawning)
|
* Evil team grunts on 35, 62, 64, 66, 112, 114
|
||||||
* Evil leader on 115, 165 (Not currently spawning)
|
* Evil leader on 115, 165
|
||||||
* E4 on 182, 184, 186, 188
|
* E4 on 182, 184, 186, 188
|
||||||
* Champion on 190
|
* Champion on 190
|
||||||
*/
|
*/
|
||||||
@ -438,28 +443,28 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
// [35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
// [62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
// [64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
// [65]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
// [112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
// [114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])),
|
||||||
// [115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])),
|
||||||
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
// [165]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[165]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
// .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2 ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2 ])),
|
||||||
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])),
|
||||||
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
||||||
|
435
src/data/ability.ts
Executable file → Normal file
@ -1,11 +1,12 @@
|
|||||||
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
|
import { Constructor } from "#app/utils";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||||
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||||
import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
|
import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
|
||||||
import { Weather, WeatherType } from "./weather";
|
import { Weather, WeatherType } from "./weather";
|
||||||
import { BattlerTag } from "./battler-tags";
|
import { BattlerTag, GroundedTag } from "./battler-tags";
|
||||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||||
import { Gender } from "./gender";
|
import { Gender } from "./gender";
|
||||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr } from "./move";
|
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr } from "./move";
|
||||||
@ -14,7 +15,8 @@ import { Stat, getStatName } from "./pokemon-stat";
|
|||||||
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
|
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
|
||||||
import { TerrainType } from "./terrain";
|
import { TerrainType } from "./terrain";
|
||||||
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
|
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
|
||||||
import i18next, { Localizable } from "#app/plugins/i18n.js";
|
import i18next from "i18next";
|
||||||
|
import { Localizable } from "#app/interfaces/locales.js";
|
||||||
import { Command } from "../ui/command-ui-handler";
|
import { Command } from "../ui/command-ui-handler";
|
||||||
import { BerryModifierType } from "#app/modifier/modifier-type";
|
import { BerryModifierType } from "#app/modifier/modifier-type";
|
||||||
import { getPokeballName } from "./pokeball";
|
import { getPokeballName } from "./pokeball";
|
||||||
@ -60,7 +62,7 @@ export class Ability implements Localizable {
|
|||||||
* @param attrType any attribute that extends {@linkcode AbAttr}
|
* @param attrType any attribute that extends {@linkcode AbAttr}
|
||||||
* @returns Array of attributes that match `attrType`, Empty Array if none match.
|
* @returns Array of attributes that match `attrType`, Empty Array if none match.
|
||||||
*/
|
*/
|
||||||
getAttrs<T extends AbAttr>(attrType: new(...args: any[]) => T ): T[] {
|
getAttrs<T extends AbAttr>(attrType: Constructor<T> ): T[] {
|
||||||
return this.attrs.filter((a): a is T => a instanceof attrType);
|
return this.attrs.filter((a): a is T => a instanceof attrType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,18 +71,18 @@ export class Ability implements Localizable {
|
|||||||
* @param attrType any attribute that extends {@linkcode AbAttr}
|
* @param attrType any attribute that extends {@linkcode AbAttr}
|
||||||
* @returns true if the ability has attribute `attrType`
|
* @returns true if the ability has attribute `attrType`
|
||||||
*/
|
*/
|
||||||
hasAttr<T extends AbAttr>(attrType: new(...args: any[]) => T): boolean {
|
hasAttr<T extends AbAttr>(attrType: Constructor<T>): boolean {
|
||||||
return this.attrs.some((attr) => attr instanceof attrType);
|
return this.attrs.some((attr) => attr instanceof attrType);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr<T extends new (...args: any[]) => AbAttr>(AttrType: T, ...args: ConstructorParameters<T>): Ability {
|
attr<T extends Constructor<AbAttr>>(AttrType: T, ...args: ConstructorParameters<T>): Ability {
|
||||||
const attr = new AttrType(...args);
|
const attr = new AttrType(...args);
|
||||||
this.attrs.push(attr);
|
this.attrs.push(attr);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionalAttr<T extends new (...args: any[]) => AbAttr>(condition: AbAttrCondition, AttrType: T, ...args: ConstructorParameters<T>): Ability {
|
conditionalAttr<T extends Constructor<AbAttr>>(condition: AbAttrCondition, AttrType: T, ...args: ConstructorParameters<T>): Ability {
|
||||||
const attr = new AttrType(...args);
|
const attr = new AttrType(...args);
|
||||||
attr.addCondition(condition);
|
attr.addCondition(condition);
|
||||||
this.attrs.push(attr);
|
this.attrs.push(attr);
|
||||||
@ -299,18 +301,19 @@ export class StabBoostAbAttr extends AbAttr {
|
|||||||
|
|
||||||
export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr {
|
export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr {
|
||||||
protected condition: PokemonDefendCondition;
|
protected condition: PokemonDefendCondition;
|
||||||
private powerMultiplier: number;
|
private damageMultiplier: number;
|
||||||
|
|
||||||
constructor(condition: PokemonDefendCondition, powerMultiplier: number) {
|
constructor(condition: PokemonDefendCondition, damageMultiplier: number) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.powerMultiplier = powerMultiplier;
|
this.damageMultiplier = damageMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
if (this.condition(pokemon, attacker, move)) {
|
if (this.condition(pokemon, attacker, move)) {
|
||||||
(args[0] as Utils.NumberHolder).value *= this.powerMultiplier;
|
(args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * this.damageMultiplier);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,19 +322,19 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
||||||
constructor(moveType: Type, powerMultiplier: number) {
|
constructor(moveType: Type, damageMultiplier: number) {
|
||||||
super((user, target, move) => move.type === moveType, powerMultiplier);
|
super((user, target, move) => move.type === moveType, damageMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PreDefendMovePowerToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
||||||
constructor(condition: PokemonDefendCondition) {
|
constructor(condition: PokemonDefendCondition) {
|
||||||
super(condition, 1);
|
super(condition, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
if (this.condition(pokemon, attacker, move)) {
|
if (this.condition(pokemon, attacker, move)) {
|
||||||
(args[0] as Utils.NumberHolder).value = 1;
|
(args[0] as Utils.NumberHolder).value = Math.floor(pokemon.getMaxHp() / 8);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,6 +1047,56 @@ export class PreAttackAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies moves additional effects with multipliers, ie. Sheer Force, Serene Grace.
|
||||||
|
* @extends AbAttr
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
|
||||||
|
private chanceMultiplier: number;
|
||||||
|
|
||||||
|
constructor(chanceMultiplier?: number) {
|
||||||
|
super(true);
|
||||||
|
this.chanceMultiplier = chanceMultiplier;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. Has to be higher than or equal to 0.
|
||||||
|
* [1]: {@linkcode Moves } Move used by the ability user.
|
||||||
|
*/
|
||||||
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
|
||||||
|
if ((args[0] as Utils.NumberHolder).value <= 0 || (args[1] as Move).id === Moves.ORDER_UP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(args[0] as Utils.NumberHolder).value *= this.chanceMultiplier;
|
||||||
|
(args[0] as Utils.NumberHolder).value = Math.min((args[0] as Utils.NumberHolder).value, 100);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets incoming moves additional effect chance to zero, ignoring all effects from moves. ie. Shield Dust.
|
||||||
|
* @extends PreDefendAbAttr
|
||||||
|
* @see {@linkcode applyPreDefend}
|
||||||
|
*/
|
||||||
|
export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr {
|
||||||
|
/**
|
||||||
|
* @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance.
|
||||||
|
*/
|
||||||
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
|
||||||
|
if ((args[0] as Utils.NumberHolder).value <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(args[0] as Utils.NumberHolder).value = 0;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class VariableMovePowerAbAttr extends PreAttackAbAttr {
|
export class VariableMovePowerAbAttr extends PreAttackAbAttr {
|
||||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
||||||
//const power = args[0] as Utils.NumberHolder;
|
//const power = args[0] as Utils.NumberHolder;
|
||||||
@ -1282,17 +1335,18 @@ export class VariableMovePowerBoostAbAttr extends VariableMovePowerAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FieldVariableMovePowerAbAttr extends AbAttr {
|
/**
|
||||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
* Boosts the power of a Pokémon's move under certain conditions.
|
||||||
//const power = args[0] as Utils.NumberHolder;
|
* @extends AbAttr
|
||||||
return false;
|
*/
|
||||||
}
|
export class FieldMovePowerBoostAbAttr extends AbAttr {
|
||||||
}
|
|
||||||
|
|
||||||
export class FieldMovePowerBoostAbAttr extends FieldVariableMovePowerAbAttr {
|
|
||||||
private condition: PokemonAttackCondition;
|
private condition: PokemonAttackCondition;
|
||||||
private powerMultiplier: number;
|
private powerMultiplier: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param condition - A function that determines whether the power boost condition is met.
|
||||||
|
* @param powerMultiplier - The multiplier to apply to the move's power when the condition is met.
|
||||||
|
*/
|
||||||
constructor(condition: PokemonAttackCondition, powerMultiplier: number) {
|
constructor(condition: PokemonAttackCondition, powerMultiplier: number) {
|
||||||
super(false);
|
super(false);
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
@ -1310,12 +1364,34 @@ export class FieldMovePowerBoostAbAttr extends FieldVariableMovePowerAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boosts the power of a specific type of move.
|
||||||
|
* @extends FieldMovePowerBoostAbAttr
|
||||||
|
*/
|
||||||
export class FieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
|
export class FieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
|
||||||
|
/**
|
||||||
|
* @param boostedType - The type of move that will receive the power boost.
|
||||||
|
* @param powerMultiplier - The multiplier to apply to the move's power, defaults to 1.5 if not provided.
|
||||||
|
*/
|
||||||
constructor(boostedType: Type, powerMultiplier?: number) {
|
constructor(boostedType: Type, powerMultiplier?: number) {
|
||||||
super((pokemon, defender, move) => move.type === boostedType, powerMultiplier || 1.5);
|
super((pokemon, defender, move) => move.type === boostedType, powerMultiplier || 1.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boosts the power of moves in specified categories.
|
||||||
|
* @extends FieldMovePowerBoostAbAttr
|
||||||
|
*/
|
||||||
|
export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
|
||||||
|
/**
|
||||||
|
* @param boostedCategories - The categories of moves that will receive the power boost.
|
||||||
|
* @param powerMultiplier - The multiplier to apply to the move's power.
|
||||||
|
*/
|
||||||
|
constructor(boostedCategories: MoveCategory[], powerMultiplier: number) {
|
||||||
|
super((pokemon, defender, move) => boostedCategories.includes(move.category), powerMultiplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class BattleStatMultiplierAbAttr extends AbAttr {
|
export class BattleStatMultiplierAbAttr extends AbAttr {
|
||||||
private battleStat: BattleStat;
|
private battleStat: BattleStat;
|
||||||
private multiplier: number;
|
private multiplier: number;
|
||||||
@ -1394,7 +1470,8 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
/**Status inflicted by abilities post attacking are also considered additional effects.*/
|
||||||
|
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
||||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
||||||
return attacker.trySetStatus(effect, true, pokemon);
|
return attacker.trySetStatus(effect, true, pokemon);
|
||||||
}
|
}
|
||||||
@ -1424,10 +1501,9 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) {
|
/**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
|
||||||
|
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) {
|
||||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
||||||
|
|
||||||
|
|
||||||
return attacker.addTag(effect);
|
return attacker.addTag(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1627,11 +1703,44 @@ export class PostIntimidateStatChangeAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for defining all {@linkcode Ability} Attributes post summon
|
||||||
|
* @see {@linkcode applyPostSummon()}
|
||||||
|
*/
|
||||||
export class PostSummonAbAttr extends AbAttr {
|
export class PostSummonAbAttr extends AbAttr {
|
||||||
|
/**
|
||||||
|
* Applies ability post summon (after switching in)
|
||||||
|
* @param pokemon {@linkcode Pokemon} with this ability
|
||||||
|
* @param passive Whether this ability is a passive
|
||||||
|
* @param args Set of unique arguments needed by this attribute
|
||||||
|
* @returns true if application of the ability succeeds
|
||||||
|
*/
|
||||||
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Removes specified arena tags when a Pokemon is summoned.
|
||||||
|
*/
|
||||||
|
export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr {
|
||||||
|
private arenaTags: ArenaTagType[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arenaTags {@linkcode ArenaTagType[]} - the arena tags to be removed
|
||||||
|
*/
|
||||||
|
constructor(arenaTags: ArenaTagType[]) {
|
||||||
|
super(true);
|
||||||
|
|
||||||
|
this.arenaTags = arenaTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
|
for (const arenaTag of this.arenaTags) {
|
||||||
|
pokemon.scene.arena.removeTag(arenaTag);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostSummonMessageAbAttr extends PostSummonAbAttr {
|
export class PostSummonMessageAbAttr extends PostSummonAbAttr {
|
||||||
private messageFunc: (pokemon: Pokemon) => string;
|
private messageFunc: (pokemon: Pokemon) => string;
|
||||||
@ -1877,7 +1986,11 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TraceAbAttr extends PostSummonAbAttr {
|
/** Attempts to copy a pokemon's ability */
|
||||||
|
export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
|
||||||
|
private target: Pokemon;
|
||||||
|
private targetAbilityName: string;
|
||||||
|
|
||||||
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
const targets = pokemon.getOpponents();
|
const targets = pokemon.getOpponents();
|
||||||
if (!targets.length) {
|
if (!targets.length) {
|
||||||
@ -1891,18 +2004,57 @@ export class TraceAbAttr extends PostSummonAbAttr {
|
|||||||
target = targets[0];
|
target = targets[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wonder Guard is normally uncopiable so has the attribute, but trace specifically can copy it
|
if (
|
||||||
if (target.getAbility().hasAttr(UncopiableAbilityAbAttr) && target.getAbility().id !== Abilities.WONDER_GUARD) {
|
target.getAbility().hasAttr(UncopiableAbilityAbAttr) &&
|
||||||
|
// Wonder Guard is normally uncopiable so has the attribute, but Trace specifically can copy it
|
||||||
|
!(pokemon.hasAbility(Abilities.TRACE) && target.getAbility().id === Abilities.WONDER_GUARD)
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.target = target;
|
||||||
|
this.targetAbilityName = allAbilities[target.getAbility().id].name;
|
||||||
pokemon.summonData.ability = target.getAbility().id;
|
pokemon.summonData.ability = target.getAbility().id;
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` traced ${target.name}'s\n${allAbilities[target.getAbility().id].name}!`));
|
|
||||||
setAbilityRevealed(target);
|
setAbilityRevealed(target);
|
||||||
|
pokemon.updateInfo();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return i18next.t("abilityTriggers:trace", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
targetName: getPokemonNameWithAffix(this.target),
|
||||||
|
abilityName: this.targetAbilityName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Attempt to copy the stat changes on an ally pokemon */
|
||||||
|
export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr {
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
|
if (!pokemon.scene.currentBattle.double) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ally = pokemon.getAlly();
|
||||||
|
if (!ally || ally.summonData.battleStats.every((change) => change === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pokemon.summonData.battleStats = ally.summonData.battleStats;
|
||||||
|
pokemon.updateInfo();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return i18next.t("abilityTriggers:costar", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
allyName: getPokemonNameWithAffix(pokemon.getAlly()),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
||||||
@ -2253,7 +2405,7 @@ export class BlockNonDirectDamageAbAttr extends AbAttr {
|
|||||||
/**
|
/**
|
||||||
* This attribute will block any status damage that you put in the parameter.
|
* This attribute will block any status damage that you put in the parameter.
|
||||||
*/
|
*/
|
||||||
export class BlockStatusDamageAbAttr extends BlockNonDirectDamageAbAttr {
|
export class BlockStatusDamageAbAttr extends AbAttr {
|
||||||
private effects: StatusEffect[];
|
private effects: StatusEffect[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2273,7 +2425,7 @@ export class BlockStatusDamageAbAttr extends BlockNonDirectDamageAbAttr {
|
|||||||
* @returns Returns true if status damage is blocked
|
* @returns Returns true if status damage is blocked
|
||||||
*/
|
*/
|
||||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
if (this.effects.includes(pokemon.status.effect)) {
|
if (this.effects.includes(pokemon.status?.effect)) {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2356,8 +2508,40 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Condition function to applied to abilities related to Sheer Force.
|
||||||
|
* Checks if last move used against target was affected by a Sheer Force user and:
|
||||||
|
* Disables: Color Change, Pickpocket, Wimp Out, Emergency Exit, Berserk, Anger Shell
|
||||||
|
* @returns {AbAttrCondition} If false disables the ability which the condition is applied to.
|
||||||
|
*/
|
||||||
|
function getSheerForceHitDisableAbCondition(): AbAttrCondition {
|
||||||
|
return (pokemon: Pokemon) => {
|
||||||
|
if (!pokemon.turnData) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastReceivedAttack = pokemon.turnData.attacksReceived[0];
|
||||||
|
if (!lastReceivedAttack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastAttacker = pokemon.getOpponents().find(p => p.id === lastReceivedAttack.sourceId);
|
||||||
|
if (!lastAttacker) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**if the last move chance is greater than or equal to cero, and the last attacker's ability is sheer force*/
|
||||||
|
const SheerForceAffected = allMoves[lastReceivedAttack.move].chance >= 0 && lastAttacker.hasAbility(Abilities.SHEER_FORCE);
|
||||||
|
|
||||||
|
return !SheerForceAffected;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
|
function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
|
||||||
return (pokemon: Pokemon) => {
|
return (pokemon: Pokemon) => {
|
||||||
|
if (!pokemon.scene?.arena) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) {
|
if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2543,16 +2727,12 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean {
|
applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean {
|
||||||
if (pokemon.getHpRatio() < 1) {
|
|
||||||
const scene = pokemon.scene;
|
const scene = pokemon.scene;
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby its ${abilityName}!`));
|
scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby its ${abilityName}!`));
|
||||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER);
|
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostTerrainChangeAbAttr extends AbAttr {
|
export class PostTerrainChangeAbAttr extends AbAttr {
|
||||||
@ -3557,13 +3737,21 @@ export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAtt
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies immunity to physical moves.
|
* Takes no damage from the first hit of a physical move.
|
||||||
* This is used in Ice Face ability.
|
* This is used in Ice Face ability.
|
||||||
*/
|
*/
|
||||||
export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
|
export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
||||||
|
private multiplier: number;
|
||||||
|
|
||||||
|
constructor(condition: PokemonDefendCondition, multiplier: number) {
|
||||||
|
super(condition, multiplier);
|
||||||
|
|
||||||
|
this.multiplier = multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the Ice Face pre-defense ability to the Pokémon.
|
* Applies the Ice Face pre-defense ability to the Pokémon.
|
||||||
* Removes BattlerTagType.ICE_FACE hit by physical attack and is in Ice Face form.
|
* Removes BattlerTagType.ICE_FACE when hit by physical attack and is in Ice Face form.
|
||||||
*
|
*
|
||||||
* @param {Pokemon} pokemon - The Pokémon with the Ice Face ability.
|
* @param {Pokemon} pokemon - The Pokémon with the Ice Face ability.
|
||||||
* @param {boolean} passive - Whether the ability is passive.
|
* @param {boolean} passive - Whether the ability is passive.
|
||||||
@ -3574,16 +3762,13 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
|
|||||||
* @returns {boolean} - Whether the immunity was applied.
|
* @returns {boolean} - Whether the immunity was applied.
|
||||||
*/
|
*/
|
||||||
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
const isImmune = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args);
|
if (this.condition(pokemon, attacker, move)) {
|
||||||
|
(args[0] as Utils.NumberHolder).value = this.multiplier;
|
||||||
if (isImmune) {
|
|
||||||
const simulated = args.length > 1 && args[1];
|
|
||||||
if (!simulated) {
|
|
||||||
pokemon.removeTag(BattlerTagType.ICE_FACE);
|
pokemon.removeTag(BattlerTagType.ICE_FACE);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isImmune;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3598,7 +3783,55 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
/**
|
||||||
|
* If a Pokémon with this Ability selects a damaging move, it has a 30% chance of going first in its priority bracket. If the Ability activates, this is announced at the start of the turn (after move selection).
|
||||||
|
*
|
||||||
|
* @extends AbAttr
|
||||||
|
*/
|
||||||
|
export class BypassSpeedChanceAbAttr extends AbAttr {
|
||||||
|
public chance: integer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {integer} chance probability of ability being active.
|
||||||
|
*/
|
||||||
|
constructor(chance: integer) {
|
||||||
|
super(true);
|
||||||
|
this.chance = chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bypass move order in their priority bracket when pokemon choose damaging move
|
||||||
|
* @param {Pokemon} pokemon {@linkcode Pokemon} the Pokemon applying this ability
|
||||||
|
* @param {boolean} passive N/A
|
||||||
|
* @param {Utils.BooleanHolder} cancelled N/A
|
||||||
|
* @param {any[]} args [0] {@linkcode Utils.BooleanHolder} set to true when the ability activated
|
||||||
|
* @returns {boolean} - whether the ability was activated.
|
||||||
|
*/
|
||||||
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
const bypassSpeed = args[0] as Utils.BooleanHolder;
|
||||||
|
|
||||||
|
if (!bypassSpeed.value && pokemon.randSeedInt(100) < this.chance) {
|
||||||
|
const turnCommand =
|
||||||
|
pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
||||||
|
const isCommandFight = turnCommand?.command === Command.FIGHT;
|
||||||
|
const move = allMoves[turnCommand.move?.move];
|
||||||
|
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
|
||||||
|
|
||||||
|
if (isCommandFight && isDamageMove) {
|
||||||
|
bypassSpeed.value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return i18next.t("abilityTriggers:quickDraw", {pokemonName: getPokemonNameWithAffix(pokemon)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: Constructor<TAttr>,
|
||||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
|
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (!pokemon.canApplyAbility(passive)) {
|
if (!pokemon.canApplyAbility(passive)) {
|
||||||
@ -3613,7 +3846,7 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
|
|||||||
const attrs = ability.getAttrs(attrType);
|
const attrs = ability.getAttrs(attrType);
|
||||||
|
|
||||||
const clearSpliceQueueAndResolve = () => {
|
const clearSpliceQueueAndResolve = () => {
|
||||||
pokemon.scene.clearPhaseQueueSplice();
|
pokemon.scene?.clearPhaseQueueSplice();
|
||||||
if (!passive) {
|
if (!passive) {
|
||||||
return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
|
return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
|
||||||
} else {
|
} else {
|
||||||
@ -3676,32 +3909,32 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
export function applyAbAttrs(attrType: Constructor<AbAttr>, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<AbAttr>(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args);
|
return applyAbAttrsInternal<AbAttr>(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostBattleInitAbAttrs(attrType: { new(...args: any[]): PostBattleInitAbAttr },
|
export function applyPostBattleInitAbAttrs(attrType: Constructor<PostBattleInitAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostBattleInitAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostBattleInitAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr },
|
export function applyPreDefendAbAttrs(attrType: Constructor<PreDefendAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
const simulated = args.length > 1 && args[1];
|
const simulated = args.length > 1 && args[1];
|
||||||
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, false, simulated);
|
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, false, simulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostDefendAbAttrs(attrType: { new(...args: any[]): PostDefendAbAttr },
|
export function applyPostDefendAbAttrs(attrType: Constructor<PostDefendAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostMoveUsedAbAttrs(attrType: { new(...args: any[]): PostMoveUsedAbAttr },
|
export function applyPostMoveUsedAbAttrs(attrType: Constructor<PostMoveUsedAbAttr>,
|
||||||
pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], ...args: any[]): Promise<void> {
|
pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostMoveUsedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, args), args);
|
return applyAbAttrsInternal<PostMoveUsedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): BattleStatMultiplierAbAttr },
|
export function applyBattleStatMultiplierAbAttrs(attrType: Constructor<BattleStatMultiplierAbAttr>,
|
||||||
pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<BattleStatMultiplierAbAttr>(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args);
|
return applyAbAttrsInternal<BattleStatMultiplierAbAttr>(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args);
|
||||||
}
|
}
|
||||||
@ -3716,98 +3949,98 @@ export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[])
|
|||||||
* @param hasApplied {@linkcode Utils.BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat
|
* @param hasApplied {@linkcode Utils.BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat
|
||||||
* @param args unused
|
* @param args unused
|
||||||
*/
|
*/
|
||||||
export function applyFieldBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): FieldMultiplyBattleStatAbAttr },
|
export function applyFieldBattleStatMultiplierAbAttrs(attrType: Constructor<FieldMultiplyBattleStatAbAttr>,
|
||||||
pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<FieldMultiplyBattleStatAbAttr>(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, stat, statValue, checkedPokemon, hasApplied, args), args);
|
return applyAbAttrsInternal<FieldMultiplyBattleStatAbAttr>(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, stat, statValue, checkedPokemon, hasApplied, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreAttackAbAttrs(attrType: { new(...args: any[]): PreAttackAbAttr },
|
export function applyPreAttackAbAttrs(attrType: Constructor<PreAttackAbAttr>,
|
||||||
pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
|
return applyAbAttrsInternal<PreAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostAttackAbAttrs(attrType: { new(...args: any[]): PostAttackAbAttr },
|
export function applyPostAttackAbAttrs(attrType: Constructor<PostAttackAbAttr>,
|
||||||
pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr },
|
export function applyPostKnockOutAbAttrs(attrType: Constructor<PostKnockOutAbAttr>,
|
||||||
pokemon: Pokemon, knockedOut: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, knockedOut: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostKnockOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, knockedOut, args), args);
|
return applyAbAttrsInternal<PostKnockOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, knockedOut, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
|
export function applyPostVictoryAbAttrs(attrType: Constructor<PostVictoryAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostVictoryAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostVictoryAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostSummonAbAttrs(attrType: { new(...args: any[]): PostSummonAbAttr },
|
export function applyPostSummonAbAttrs(attrType: Constructor<PostSummonAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostSummonAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostSummonAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreSwitchOutAbAttrs(attrType: { new(...args: any[]): PreSwitchOutAbAttr },
|
export function applyPreSwitchOutAbAttrs(attrType: Constructor<PreSwitchOutAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreSwitchOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, false, true);
|
return applyAbAttrsInternal<PreSwitchOutAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreStatChangeAbAttr },
|
export function applyPreStatChangeAbAttrs(attrType: Constructor<PreStatChangeAbAttr>,
|
||||||
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostStatChangeAbAttrs(attrType: { new(...args: any[]): PostStatChangeAbAttr },
|
export function applyPostStatChangeAbAttrs(attrType: Constructor<PostStatChangeAbAttr>,
|
||||||
pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, stats, levels, selfTarget, args), args);
|
return applyAbAttrsInternal<PostStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, stats, levels, selfTarget, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
|
export function applyPreSetStatusAbAttrs(attrType: Constructor<PreSetStatusAbAttr>,
|
||||||
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
const simulated = args.length > 1 && args[1];
|
const simulated = args.length > 1 && args[1];
|
||||||
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, false, !simulated);
|
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, false, !simulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreApplyBattlerTagAbAttrs(attrType: { new(...args: any[]): PreApplyBattlerTagAbAttr },
|
export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor<PreApplyBattlerTagAbAttr>,
|
||||||
pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreApplyBattlerTagAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, tag, cancelled, args), args);
|
return applyAbAttrsInternal<PreApplyBattlerTagAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, tag, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreWeatherEffectAbAttrs(attrType: { new(...args: any[]): PreWeatherEffectAbAttr },
|
export function applyPreWeatherEffectAbAttrs(attrType: Constructor<PreWeatherEffectAbAttr>,
|
||||||
pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreWeatherDamageAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, false, true);
|
return applyAbAttrsInternal<PreWeatherDamageAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostTurnAbAttrs(attrType: { new(...args: any[]): PostTurnAbAttr },
|
export function applyPostTurnAbAttrs(attrType: Constructor<PostTurnAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostTurnAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostTurnAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostWeatherChangeAbAttrs(attrType: { new(...args: any[]): PostWeatherChangeAbAttr },
|
export function applyPostWeatherChangeAbAttrs(attrType: Constructor<PostWeatherChangeAbAttr>,
|
||||||
pokemon: Pokemon, weather: WeatherType, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, weather: WeatherType, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostWeatherChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, weather, args), args);
|
return applyAbAttrsInternal<PostWeatherChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, weather, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostWeatherLapseAbAttrs(attrType: { new(...args: any[]): PostWeatherLapseAbAttr },
|
export function applyPostWeatherLapseAbAttrs(attrType: Constructor<PostWeatherLapseAbAttr>,
|
||||||
pokemon: Pokemon, weather: Weather, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, weather: Weather, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostWeatherLapseAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args);
|
return applyAbAttrsInternal<PostWeatherLapseAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostTerrainChangeAbAttrs(attrType: { new(...args: any[]): PostTerrainChangeAbAttr },
|
export function applyPostTerrainChangeAbAttrs(attrType: Constructor<PostTerrainChangeAbAttr>,
|
||||||
pokemon: Pokemon, terrain: TerrainType, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, terrain: TerrainType, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostTerrainChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, terrain, args), args);
|
return applyAbAttrsInternal<PostTerrainChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, terrain, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyCheckTrappedAbAttrs(attrType: { new(...args: any[]): CheckTrappedAbAttr },
|
export function applyCheckTrappedAbAttrs(attrType: Constructor<CheckTrappedAbAttr>,
|
||||||
pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, true);
|
return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostBattleAbAttrs(attrType: { new(...args: any[]): PostBattleAbAttr },
|
export function applyPostBattleAbAttrs(attrType: Constructor<PostBattleAbAttr>,
|
||||||
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostBattleAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, args), args);
|
return applyAbAttrsInternal<PostBattleAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostFaintAbAttrs(attrType: { new(...args: any[]): PostFaintAbAttr },
|
export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
@ -3886,7 +4119,8 @@ export function initAbilities() {
|
|||||||
.attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
|
.attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.COLOR_CHANGE, 3)
|
new Ability(Abilities.COLOR_CHANGE, 3)
|
||||||
.attr(PostDefendTypeChangeAbAttr),
|
.attr(PostDefendTypeChangeAbAttr)
|
||||||
|
.condition(getSheerForceHitDisableAbCondition()),
|
||||||
new Ability(Abilities.IMMUNITY, 3)
|
new Ability(Abilities.IMMUNITY, 3)
|
||||||
.attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
.attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -3894,8 +4128,8 @@ export function initAbilities() {
|
|||||||
.attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1, (pokemon: Pokemon) => !pokemon.status || pokemon.status.effect !== StatusEffect.FREEZE)
|
.attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1, (pokemon: Pokemon) => !pokemon.status || pokemon.status.effect !== StatusEffect.FREEZE)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SHIELD_DUST, 3)
|
new Ability(Abilities.SHIELD_DUST, 3)
|
||||||
.ignorable()
|
.attr(IgnoreMoveEffectsAbAttr)
|
||||||
.unimplemented(),
|
.partial(),
|
||||||
new Ability(Abilities.OWN_TEMPO, 3)
|
new Ability(Abilities.OWN_TEMPO, 3)
|
||||||
.attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED)
|
.attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED)
|
||||||
.attr(IntimidateImmunityAbAttr)
|
.attr(IntimidateImmunityAbAttr)
|
||||||
@ -3921,7 +4155,7 @@ export function initAbilities() {
|
|||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.LEVITATE, 3)
|
new Ability(Abilities.LEVITATE, 3)
|
||||||
.attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(BattlerTagType.IGNORE_FLYING) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY) && !pokemon.getTag(BattlerTagType.GROUNDED))
|
.attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(GroundedTag) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.EFFECT_SPORE, 3)
|
new Ability(Abilities.EFFECT_SPORE, 3)
|
||||||
.attr(EffectSporeAbAttr),
|
.attr(EffectSporeAbAttr),
|
||||||
@ -3938,7 +4172,8 @@ export function initAbilities() {
|
|||||||
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1)
|
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SERENE_GRACE, 3)
|
new Ability(Abilities.SERENE_GRACE, 3)
|
||||||
.unimplemented(),
|
.attr(MoveEffectChanceMultiplierAbAttr, 2)
|
||||||
|
.partial(),
|
||||||
new Ability(Abilities.SWIFT_SWIM, 3)
|
new Ability(Abilities.SWIFT_SWIM, 3)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
||||||
.condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)),
|
.condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)),
|
||||||
@ -3950,7 +4185,7 @@ export function initAbilities() {
|
|||||||
.attr(DoubleBattleChanceAbAttr)
|
.attr(DoubleBattleChanceAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.TRACE, 3)
|
new Ability(Abilities.TRACE, 3)
|
||||||
.attr(TraceAbAttr)
|
.attr(PostSummonCopyAbilityAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr),
|
.attr(UncopiableAbilityAbAttr),
|
||||||
new Ability(Abilities.HUGE_POWER, 3)
|
new Ability(Abilities.HUGE_POWER, 3)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 2),
|
.attr(BattleStatMultiplierAbAttr, BattleStat.ATK, 2),
|
||||||
@ -4214,9 +4449,12 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.BAD_DREAMS, 4)
|
new Ability(Abilities.BAD_DREAMS, 4)
|
||||||
.attr(PostTurnHurtIfSleepingAbAttr),
|
.attr(PostTurnHurtIfSleepingAbAttr),
|
||||||
new Ability(Abilities.PICKPOCKET, 5)
|
new Ability(Abilities.PICKPOCKET, 5)
|
||||||
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)),
|
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT))
|
||||||
|
.condition(getSheerForceHitDisableAbCondition()),
|
||||||
new Ability(Abilities.SHEER_FORCE, 5)
|
new Ability(Abilities.SHEER_FORCE, 5)
|
||||||
.unimplemented(),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461/4096)
|
||||||
|
.attr(MoveEffectChanceMultiplierAbAttr, 0)
|
||||||
|
.partial(),
|
||||||
new Ability(Abilities.CONTRARY, 5)
|
new Ability(Abilities.CONTRARY, 5)
|
||||||
.attr(StatChangeMultiplierAbAttr, -1)
|
.attr(StatChangeMultiplierAbAttr, -1)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -4350,8 +4588,8 @@ export function initAbilities() {
|
|||||||
.attr(HealFromBerryUseAbAttr, 1/3)
|
.attr(HealFromBerryUseAbAttr, 1/3)
|
||||||
.partial(), // Healing not blocked by Heal Block
|
.partial(), // Healing not blocked by Heal Block
|
||||||
new Ability(Abilities.PROTEAN, 6)
|
new Ability(Abilities.PROTEAN, 6)
|
||||||
.attr(PokemonTypeChangeAbAttr)
|
.attr(PokemonTypeChangeAbAttr),
|
||||||
.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)),
|
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation
|
||||||
new Ability(Abilities.FUR_COAT, 6)
|
new Ability(Abilities.FUR_COAT, 6)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, 0.5)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, 0.5)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -4403,7 +4641,8 @@ export function initAbilities() {
|
|||||||
.attr(FieldMoveTypePowerBoostAbAttr, Type.FAIRY, 4 / 3),
|
.attr(FieldMoveTypePowerBoostAbAttr, Type.FAIRY, 4 / 3),
|
||||||
new Ability(Abilities.AURA_BREAK, 6)
|
new Ability(Abilities.AURA_BREAK, 6)
|
||||||
.ignorable()
|
.ignorable()
|
||||||
.unimplemented(),
|
.conditionalAttr(target => target.hasAbility(Abilities.DARK_AURA), FieldMoveTypePowerBoostAbAttr, Type.DARK, 9 / 16)
|
||||||
|
.conditionalAttr(target => target.hasAbility(Abilities.FAIRY_AURA), FieldMoveTypePowerBoostAbAttr, Type.FAIRY, 9 / 16),
|
||||||
new Ability(Abilities.PRIMORDIAL_SEA, 6)
|
new Ability(Abilities.PRIMORDIAL_SEA, 6)
|
||||||
.attr(PostSummonWeatherChangeAbAttr, WeatherType.HEAVY_RAIN)
|
.attr(PostSummonWeatherChangeAbAttr, WeatherType.HEAVY_RAIN)
|
||||||
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.HEAVY_RAIN)
|
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.HEAVY_RAIN)
|
||||||
@ -4425,8 +4664,10 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.STAMINA, 7)
|
new Ability(Abilities.STAMINA, 7)
|
||||||
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattleStat.DEF, 1),
|
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattleStat.DEF, 1),
|
||||||
new Ability(Abilities.WIMP_OUT, 7)
|
new Ability(Abilities.WIMP_OUT, 7)
|
||||||
|
.condition(getSheerForceHitDisableAbCondition())
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.EMERGENCY_EXIT, 7)
|
new Ability(Abilities.EMERGENCY_EXIT, 7)
|
||||||
|
.condition(getSheerForceHitDisableAbCondition())
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.WATER_COMPACTION, 7)
|
new Ability(Abilities.WATER_COMPACTION, 7)
|
||||||
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
|
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
|
||||||
@ -4452,7 +4693,8 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.STEELWORKER, 7)
|
new Ability(Abilities.STEELWORKER, 7)
|
||||||
.attr(MoveTypePowerBoostAbAttr, Type.STEEL),
|
.attr(MoveTypePowerBoostAbAttr, Type.STEEL),
|
||||||
new Ability(Abilities.BERSERK, 7)
|
new Ability(Abilities.BERSERK, 7)
|
||||||
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [BattleStat.SPATK], 1),
|
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [BattleStat.SPATK], 1)
|
||||||
|
.condition(getSheerForceHitDisableAbCondition()),
|
||||||
new Ability(Abilities.SLUSH_RUSH, 7)
|
new Ability(Abilities.SLUSH_RUSH, 7)
|
||||||
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
||||||
.condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)),
|
.condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)),
|
||||||
@ -4476,7 +4718,7 @@ export function initAbilities() {
|
|||||||
.attr(NoFusionAbilityAbAttr)
|
.attr(NoFusionAbilityAbAttr)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
new Ability(Abilities.DISGUISE, 7)
|
new Ability(Abilities.DISGUISE, 7)
|
||||||
.attr(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex === 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
|
.attr(PreDefendMoveDamageToOneAbAttr, (target, user, move) => target.formIndex === 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
|
||||||
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
|
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
|
||||||
.attr(PostBattleInitFormChangeAbAttr, () => 0)
|
.attr(PostBattleInitFormChangeAbAttr, () => 0)
|
||||||
.attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
|
.attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
|
||||||
@ -4526,7 +4768,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.DANCER, 7)
|
new Ability(Abilities.DANCER, 7)
|
||||||
.attr(PostDancingMoveAbAttr),
|
.attr(PostDancingMoveAbAttr),
|
||||||
new Ability(Abilities.BATTERY, 7)
|
new Ability(Abilities.BATTERY, 7)
|
||||||
.unimplemented(),
|
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL], 1.3),
|
||||||
new Ability(Abilities.FLUFFY, 7)
|
new Ability(Abilities.FLUFFY, 7)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.type === Type.FIRE, 2)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.type === Type.FIRE, 2)
|
||||||
@ -4590,8 +4832,8 @@ export function initAbilities() {
|
|||||||
.attr(PostSummonStatChangeAbAttr, BattleStat.DEF, 1, true)
|
.attr(PostSummonStatChangeAbAttr, BattleStat.DEF, 1, true)
|
||||||
.condition(getOncePerBattleCondition(Abilities.DAUNTLESS_SHIELD)),
|
.condition(getOncePerBattleCondition(Abilities.DAUNTLESS_SHIELD)),
|
||||||
new Ability(Abilities.LIBERO, 8)
|
new Ability(Abilities.LIBERO, 8)
|
||||||
.attr(PokemonTypeChangeAbAttr)
|
.attr(PokemonTypeChangeAbAttr),
|
||||||
.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.LIBERO)),
|
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.LIBERO)), //Gen 9 Implementation
|
||||||
new Ability(Abilities.BALL_FETCH, 8)
|
new Ability(Abilities.BALL_FETCH, 8)
|
||||||
.attr(FetchBallAbAttr)
|
.attr(FetchBallAbAttr)
|
||||||
.condition(getOncePerBattleCondition(Abilities.BALL_FETCH)),
|
.condition(getOncePerBattleCondition(Abilities.BALL_FETCH)),
|
||||||
@ -4635,14 +4877,14 @@ export function initAbilities() {
|
|||||||
.conditionalAttr(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW), PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0)
|
.conditionalAttr(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW), PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0)
|
||||||
// When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE
|
// When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE
|
||||||
.attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW)
|
.attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW)
|
||||||
.attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE))
|
.attr(IceFaceBlockPhysicalAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.POWER_SPOT, 8)
|
new Ability(Abilities.POWER_SPOT, 8)
|
||||||
.unimplemented(),
|
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3),
|
||||||
new Ability(Abilities.MIMICRY, 8)
|
new Ability(Abilities.MIMICRY, 8)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.SCREEN_CLEANER, 8)
|
new Ability(Abilities.SCREEN_CLEANER, 8)
|
||||||
.unimplemented(),
|
.attr(PostSummonRemoveArenaTagAbAttr, [ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT]),
|
||||||
new Ability(Abilities.STEELY_SPIRIT, 8)
|
new Ability(Abilities.STEELY_SPIRIT, 8)
|
||||||
.attr(MoveTypePowerBoostAbAttr, Type.STEEL)
|
.attr(MoveTypePowerBoostAbAttr, Type.STEEL)
|
||||||
.partial(),
|
.partial(),
|
||||||
@ -4673,7 +4915,7 @@ export function initAbilities() {
|
|||||||
.attr(NoFusionAbilityAbAttr)
|
.attr(NoFusionAbilityAbAttr)
|
||||||
.condition((pokemon) => !pokemon.isTerastallized()),
|
.condition((pokemon) => !pokemon.isTerastallized()),
|
||||||
new Ability(Abilities.QUICK_DRAW, 8)
|
new Ability(Abilities.QUICK_DRAW, 8)
|
||||||
.unimplemented(),
|
.attr(BypassSpeedChanceAbAttr, 30),
|
||||||
new Ability(Abilities.UNSEEN_FIST, 8)
|
new Ability(Abilities.UNSEEN_FIST, 8)
|
||||||
.attr(IgnoreProtectOnContactAbAttr),
|
.attr(IgnoreProtectOnContactAbAttr),
|
||||||
new Ability(Abilities.CURIOUS_MEDICINE, 8)
|
new Ability(Abilities.CURIOUS_MEDICINE, 8)
|
||||||
@ -4711,7 +4953,8 @@ export function initAbilities() {
|
|||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.ANGER_SHELL, 9)
|
new Ability(Abilities.ANGER_SHELL, 9)
|
||||||
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 1)
|
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 1)
|
||||||
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.DEF, BattleStat.SPDEF ], -1),
|
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.DEF, BattleStat.SPDEF ], -1)
|
||||||
|
.condition(getSheerForceHitDisableAbCondition()),
|
||||||
new Ability(Abilities.PURIFYING_SALT, 9)
|
new Ability(Abilities.PURIFYING_SALT, 9)
|
||||||
.attr(StatusEffectImmunityAbAttr)
|
.attr(StatusEffectImmunityAbAttr)
|
||||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.GHOST, 0.5)
|
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.GHOST, 0.5)
|
||||||
@ -4798,7 +5041,7 @@ export function initAbilities() {
|
|||||||
.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(),
|
.partial(),
|
||||||
new Ability(Abilities.COSTAR, 9)
|
new Ability(Abilities.COSTAR, 9)
|
||||||
.unimplemented(),
|
.attr(PostSummonCopyAllyStatsAbAttr),
|
||||||
new Ability(Abilities.TOXIC_DEBRIS, 9)
|
new Ability(Abilities.TOXIC_DEBRIS, 9)
|
||||||
.attr(PostDefendApplyArenaTrapTagAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, ArenaTagType.TOXIC_SPIKES)
|
.attr(PostDefendApplyArenaTrapTagAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, ArenaTagType.TOXIC_SPIKES)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
|
@ -4,7 +4,7 @@ import * as Utils from "../utils";
|
|||||||
import { MoveCategory, allMoves, MoveTarget } from "./move";
|
import { MoveCategory, allMoves, MoveTarget } from "./move";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage } from "../messages";
|
||||||
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||||
import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase} from "../phases";
|
import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||||
import { StatusEffect } from "./status-effect";
|
import { StatusEffect } from "./status-effect";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
|
import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
|
||||||
@ -63,6 +63,10 @@ export abstract class ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Mist_(move) Mist}.
|
||||||
|
* Prevents Pokémon on the opposing side from lowering the stats of the Pokémon in the Mist.
|
||||||
|
*/
|
||||||
export class MistTag extends ArenaTag {
|
export class MistTag extends ArenaTag {
|
||||||
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.MIST, turnCount, Moves.MIST, sourceId, side);
|
super(ArenaTagType.MIST, turnCount, Moves.MIST, sourceId, side);
|
||||||
@ -86,37 +90,57 @@ export class MistTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the damage of specific move categories in the arena.
|
||||||
|
* @extends ArenaTag
|
||||||
|
*/
|
||||||
export class WeakenMoveScreenTag extends ArenaTag {
|
export class WeakenMoveScreenTag extends ArenaTag {
|
||||||
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide) {
|
protected weakenedCategories: MoveCategory[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the WeakenMoveScreenTag class.
|
||||||
|
*
|
||||||
|
* @param tagType - The type of the arena tag.
|
||||||
|
* @param turnCount - The number of turns the tag is active.
|
||||||
|
* @param sourceMove - The move that created the tag.
|
||||||
|
* @param sourceId - The ID of the source of the tag.
|
||||||
|
* @param side - The side (player or enemy) the tag affects.
|
||||||
|
* @param weakenedCategories - The categories of moves that are weakened by this tag.
|
||||||
|
*/
|
||||||
|
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, weakenedCategories: MoveCategory[]) {
|
||||||
super(tagType, turnCount, sourceMove, sourceId, side);
|
super(tagType, turnCount, sourceMove, sourceId, side);
|
||||||
|
|
||||||
|
this.weakenedCategories = weakenedCategories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the weakening effect to the move.
|
||||||
|
*
|
||||||
|
* @param arena - The arena where the move is applied.
|
||||||
|
* @param args - The arguments for the move application.
|
||||||
|
* @param args[0] - The category of the move.
|
||||||
|
* @param args[1] - A boolean indicating whether it is a double battle.
|
||||||
|
* @param args[2] - An object of type `Utils.NumberHolder` that holds the damage multiplier
|
||||||
|
*
|
||||||
|
* @returns True if the move was weakened, otherwise false.
|
||||||
|
*/
|
||||||
apply(arena: Arena, args: any[]): boolean {
|
apply(arena: Arena, args: any[]): boolean {
|
||||||
if ((args[1] as boolean)) {
|
if (this.weakenedCategories.includes((args[0] as MoveCategory))) {
|
||||||
(args[2] as Utils.NumberHolder).value = 2732/4096;
|
(args[2] as Utils.NumberHolder).value = (args[1] as boolean) ? 2732/4096 : 0.5;
|
||||||
} else {
|
|
||||||
(args[2] as Utils.NumberHolder).value = 0.5;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReflectTag extends WeakenMoveScreenTag {
|
|
||||||
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
|
||||||
super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(arena: Arena, args: any[]): boolean {
|
|
||||||
if ((args[0] as MoveCategory) === MoveCategory.PHYSICAL) {
|
|
||||||
if ((args[1] as boolean)) {
|
|
||||||
(args[2] as Utils.NumberHolder).value = 2732/4096;
|
|
||||||
} else {
|
|
||||||
(args[2] as Utils.NumberHolder).value = 0.5;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the damage of physical moves.
|
||||||
|
* Used by {@linkcode Moves.REFLECT}
|
||||||
|
*/
|
||||||
|
class ReflectTag extends WeakenMoveScreenTag {
|
||||||
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
|
super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [MoveCategory.PHYSICAL]);
|
||||||
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
@ -125,21 +149,13 @@ class ReflectTag extends WeakenMoveScreenTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the damage of special moves.
|
||||||
|
* Used by {@linkcode Moves.LIGHT_SCREEN}
|
||||||
|
*/
|
||||||
class LightScreenTag extends WeakenMoveScreenTag {
|
class LightScreenTag extends WeakenMoveScreenTag {
|
||||||
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side);
|
super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [MoveCategory.SPECIAL]);
|
||||||
}
|
|
||||||
|
|
||||||
apply(arena: Arena, args: any[]): boolean {
|
|
||||||
if ((args[0] as MoveCategory) === MoveCategory.SPECIAL) {
|
|
||||||
if ((args[1] as boolean)) {
|
|
||||||
(args[2] as Utils.NumberHolder).value = 2732/4096;
|
|
||||||
} else {
|
|
||||||
(args[2] as Utils.NumberHolder).value = 0.5;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
@ -149,9 +165,13 @@ class LightScreenTag extends WeakenMoveScreenTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the damage of physical and special moves.
|
||||||
|
* Used by {@linkcode Moves.AURORA_VEIL}
|
||||||
|
*/
|
||||||
class AuroraVeilTag extends WeakenMoveScreenTag {
|
class AuroraVeilTag extends WeakenMoveScreenTag {
|
||||||
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side);
|
super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
@ -283,6 +303,10 @@ class CraftyShieldTag extends ConditionalProtectTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Wish_(move) Wish}.
|
||||||
|
* Heals the Pokémon in the user's position the turn after Wish is used.
|
||||||
|
*/
|
||||||
class WishTag extends ArenaTag {
|
class WishTag extends ArenaTag {
|
||||||
private battlerIndex: BattlerIndex;
|
private battlerIndex: BattlerIndex;
|
||||||
private triggerMessage: string;
|
private triggerMessage: string;
|
||||||
@ -308,9 +332,21 @@ class WishTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class to implement weakened moves of a specific type.
|
||||||
|
*/
|
||||||
export class WeakenMoveTypeTag extends ArenaTag {
|
export class WeakenMoveTypeTag extends ArenaTag {
|
||||||
private weakenedType: Type;
|
private weakenedType: Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the WeakenMoveTypeTag class.
|
||||||
|
*
|
||||||
|
* @param tagType - The type of the arena tag.
|
||||||
|
* @param turnCount - The number of turns the tag is active.
|
||||||
|
* @param type - The type being weakened from this tag.
|
||||||
|
* @param sourceMove - The move that created the tag.
|
||||||
|
* @param sourceId - The ID of the source of the tag.
|
||||||
|
*/
|
||||||
constructor(tagType: ArenaTagType, turnCount: integer, type: Type, sourceMove: Moves, sourceId: integer) {
|
constructor(tagType: ArenaTagType, turnCount: integer, type: Type, sourceMove: Moves, sourceId: integer) {
|
||||||
super(tagType, turnCount, sourceMove, sourceId);
|
super(tagType, turnCount, sourceMove, sourceId);
|
||||||
|
|
||||||
@ -327,6 +363,10 @@ export class WeakenMoveTypeTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Mud_Sport_(move) Mud Sport}.
|
||||||
|
* Weakens Electric type moves for a set amount of turns, usually 5.
|
||||||
|
*/
|
||||||
class MudSportTag extends WeakenMoveTypeTag {
|
class MudSportTag extends WeakenMoveTypeTag {
|
||||||
constructor(turnCount: integer, sourceId: integer) {
|
constructor(turnCount: integer, sourceId: integer) {
|
||||||
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC, Moves.MUD_SPORT, sourceId);
|
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC, Moves.MUD_SPORT, sourceId);
|
||||||
@ -341,6 +381,10 @@ class MudSportTag extends WeakenMoveTypeTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Water_Sport_(move) Water Sport}.
|
||||||
|
* Weakens Fire type moves for a set amount of turns, usually 5.
|
||||||
|
*/
|
||||||
class WaterSportTag extends WeakenMoveTypeTag {
|
class WaterSportTag extends WeakenMoveTypeTag {
|
||||||
constructor(turnCount: integer, sourceId: integer) {
|
constructor(turnCount: integer, sourceId: integer) {
|
||||||
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE, Moves.WATER_SPORT, sourceId);
|
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE, Moves.WATER_SPORT, sourceId);
|
||||||
@ -355,10 +399,22 @@ class WaterSportTag extends WeakenMoveTypeTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class to implement arena traps.
|
||||||
|
*/
|
||||||
export class ArenaTrapTag extends ArenaTag {
|
export class ArenaTrapTag extends ArenaTag {
|
||||||
public layers: integer;
|
public layers: integer;
|
||||||
public maxLayers: integer;
|
public maxLayers: integer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the ArenaTrapTag class.
|
||||||
|
*
|
||||||
|
* @param tagType - The type of the arena tag.
|
||||||
|
* @param sourceMove - The move that created the tag.
|
||||||
|
* @param sourceId - The ID of the source of the tag.
|
||||||
|
* @param side - The side (player or enemy) the tag affects.
|
||||||
|
* @param maxLayers - The maximum amount of layers this tag can have.
|
||||||
|
*/
|
||||||
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, maxLayers: integer) {
|
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, side: ArenaTagSide, maxLayers: integer) {
|
||||||
super(tagType, 0, sourceMove, sourceId, side);
|
super(tagType, 0, sourceMove, sourceId, side);
|
||||||
|
|
||||||
@ -392,6 +448,11 @@ export class ArenaTrapTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Spikes_(move) Spikes}.
|
||||||
|
* Applies up to 3 layers of Spikes, dealing 1/8th, 1/6th, or 1/4th of the the Pokémon's HP
|
||||||
|
* in damage for 1, 2, or 3 layers of Spikes respectively if they are summoned into this trap.
|
||||||
|
*/
|
||||||
class SpikesTag extends ArenaTrapTag {
|
class SpikesTag extends ArenaTrapTag {
|
||||||
constructor(sourceId: integer, side: ArenaTagSide) {
|
constructor(sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.SPIKES, Moves.SPIKES, sourceId, side, 3);
|
super(ArenaTagType.SPIKES, Moves.SPIKES, sourceId, side, 3);
|
||||||
@ -428,6 +489,12 @@ class SpikesTag extends ArenaTrapTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Toxic_Spikes_(move) Toxic Spikes}.
|
||||||
|
* Applies up to 2 layers of Toxic Spikes, poisoning or badly poisoning any Pokémon who is
|
||||||
|
* summoned into this trap if 1 or 2 layers of Toxic Spikes respectively are up. Poison-type
|
||||||
|
* Pokémon summoned into this trap remove it entirely.
|
||||||
|
*/
|
||||||
class ToxicSpikesTag extends ArenaTrapTag {
|
class ToxicSpikesTag extends ArenaTrapTag {
|
||||||
private neutralized: boolean;
|
private neutralized: boolean;
|
||||||
|
|
||||||
@ -481,6 +548,11 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for delayed attacks, such as {@linkcode Moves.FUTURE_SIGHT} or {@linkcode Moves.DOOM_DESIRE}.
|
||||||
|
* Delays the attack's effect by a set amount of turns, usually 3 (including the turn the move is used),
|
||||||
|
* and deals damage after the turn count is reached.
|
||||||
|
*/
|
||||||
class DelayedAttackTag extends ArenaTag {
|
class DelayedAttackTag extends ArenaTag {
|
||||||
public targetIndex: BattlerIndex;
|
public targetIndex: BattlerIndex;
|
||||||
|
|
||||||
@ -503,6 +575,11 @@ class DelayedAttackTag extends ArenaTag {
|
|||||||
onRemove(arena: Arena): void { }
|
onRemove(arena: Arena): void { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Stealth_Rock_(move) Stealth Rock}.
|
||||||
|
* Applies up to 1 layer of Stealth Rocks, dealing percentage-based damage to any Pokémon
|
||||||
|
* who is summoned into the trap, based on the Rock type's type effectiveness.
|
||||||
|
*/
|
||||||
class StealthRockTag extends ArenaTrapTag {
|
class StealthRockTag extends ArenaTrapTag {
|
||||||
constructor(sourceId: integer, side: ArenaTagSide) {
|
constructor(sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.STEALTH_ROCK, Moves.STEALTH_ROCK, sourceId, side, 1);
|
super(ArenaTagType.STEALTH_ROCK, Moves.STEALTH_ROCK, sourceId, side, 1);
|
||||||
@ -574,6 +651,11 @@ class StealthRockTag extends ArenaTrapTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Sticky_Web_(move) Sticky Web}.
|
||||||
|
* Applies up to 1 layer of Sticky Web, which lowers the Speed by one stage
|
||||||
|
* to any Pokémon who is summoned into this trap.
|
||||||
|
*/
|
||||||
class StickyWebTag extends ArenaTrapTag {
|
class StickyWebTag extends ArenaTrapTag {
|
||||||
constructor(sourceId: integer, side: ArenaTagSide) {
|
constructor(sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.STICKY_WEB, Moves.STICKY_WEB, sourceId, side, 1);
|
super(ArenaTagType.STICKY_WEB, Moves.STICKY_WEB, sourceId, side, 1);
|
||||||
@ -606,6 +688,11 @@ class StickyWebTag extends ArenaTrapTag {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Trick_Room_(move) Trick Room}.
|
||||||
|
* Reverses the Speed stats for all Pokémon on the field as long as this arena tag is up,
|
||||||
|
* also reversing the turn order for all Pokémon on the field as well.
|
||||||
|
*/
|
||||||
export class TrickRoomTag extends ArenaTag {
|
export class TrickRoomTag extends ArenaTag {
|
||||||
constructor(turnCount: integer, sourceId: integer) {
|
constructor(turnCount: integer, sourceId: integer) {
|
||||||
super(ArenaTagType.TRICK_ROOM, turnCount, Moves.TRICK_ROOM, sourceId);
|
super(ArenaTagType.TRICK_ROOM, turnCount, Moves.TRICK_ROOM, sourceId);
|
||||||
@ -626,6 +713,11 @@ export class TrickRoomTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Gravity_(move) Gravity}.
|
||||||
|
* Grounds all Pokémon on the field, including Flying-types and those with
|
||||||
|
* {@linkcode Abilities.LEVITATE} for the duration of the arena tag, usually 5 turns.
|
||||||
|
*/
|
||||||
export class GravityTag extends ArenaTag {
|
export class GravityTag extends ArenaTag {
|
||||||
constructor(turnCount: integer) {
|
constructor(turnCount: integer) {
|
||||||
super(ArenaTagType.GRAVITY, turnCount, Moves.GRAVITY);
|
super(ArenaTagType.GRAVITY, turnCount, Moves.GRAVITY);
|
||||||
@ -633,6 +725,11 @@ export class GravityTag extends ArenaTag {
|
|||||||
|
|
||||||
onAdd(arena: Arena): void {
|
onAdd(arena: Arena): void {
|
||||||
arena.scene.queueMessage("Gravity intensified!");
|
arena.scene.queueMessage("Gravity intensified!");
|
||||||
|
arena.scene.getField(true).forEach((pokemon) => {
|
||||||
|
if (pokemon !== null) {
|
||||||
|
pokemon.removeTag(BattlerTagType.MAGNET_RISEN);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(arena: Arena): void {
|
onRemove(arena: Arena): void {
|
||||||
@ -640,6 +737,11 @@ export class GravityTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Tailwind_(move) Tailwind}.
|
||||||
|
* Doubles the Speed of the Pokémon who created this arena tag, as well as all allied Pokémon.
|
||||||
|
* Applies this arena tag for 4 turns (including the turn the move was used).
|
||||||
|
*/
|
||||||
class TailwindTag extends ArenaTag {
|
class TailwindTag extends ArenaTag {
|
||||||
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
super(ArenaTagType.TAILWIND, turnCount, Moves.TAILWIND, sourceId, side);
|
super(ArenaTagType.TAILWIND, turnCount, Moves.TAILWIND, sourceId, side);
|
||||||
@ -674,6 +776,24 @@ class TailwindTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Happy_Hour_(move) Happy Hour}.
|
||||||
|
* Doubles the prize money from trainers and money moves like {@linkcode Moves.PAY_DAY} and {@linkcode Moves.MAKE_IT_RAIN}.
|
||||||
|
*/
|
||||||
|
class HappyHourTag extends ArenaTag {
|
||||||
|
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
|
||||||
|
super(ArenaTagType.HAPPY_HOUR, turnCount, Moves.HAPPY_HOUR, sourceId, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(arena: Arena): void {
|
||||||
|
arena.scene.queueMessage("Everyone is caught up in the happy atmosphere!");
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(arena: Arena): void {
|
||||||
|
arena.scene.queueMessage("The atmosphere returned to normal.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag {
|
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case ArenaTagType.MIST:
|
case ArenaTagType.MIST:
|
||||||
@ -715,5 +835,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new AuroraVeilTag(turnCount, sourceId, side);
|
return new AuroraVeilTag(turnCount, sourceId, side);
|
||||||
case ArenaTagType.TAILWIND:
|
case ArenaTagType.TAILWIND:
|
||||||
return new TailwindTag(turnCount, sourceId, side);
|
return new TailwindTag(turnCount, sourceId, side);
|
||||||
|
case ArenaTagType.HAPPY_HOUR:
|
||||||
|
return new HappyHourTag(turnCount, sourceId, side);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,34 +32,38 @@ export function getBattleStatName(stat: BattleStat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBattleStatLevelChangeDescription(levels: integer, up: boolean) {
|
export function getBattleStatLevelChangeDescription(pokemonNameWithAffix: string, stats: string, levels: integer, up: boolean) {
|
||||||
|
const stringKey = (() => {
|
||||||
if (up) {
|
if (up) {
|
||||||
switch (levels) {
|
switch (levels) {
|
||||||
case 1:
|
case 1:
|
||||||
return i18next.t("battle:statRose");
|
return "battle:statRose";
|
||||||
case 2:
|
case 2:
|
||||||
return i18next.t("battle:statSharplyRose");
|
return "battle:statSharplyRose";
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
case 6:
|
||||||
return i18next.t("battle:statRoseDrastically");
|
return "battle:statRoseDrastically";
|
||||||
default:
|
default:
|
||||||
return i18next.t("battle:statWontGoAnyHigher");
|
return "battle:statWontGoAnyHigher";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (levels) {
|
switch (levels) {
|
||||||
case 1:
|
case 1:
|
||||||
return i18next.t("battle:statFell");
|
return "battle:statFell";
|
||||||
case 2:
|
case 2:
|
||||||
return i18next.t("battle:statHarshlyFell");
|
return "battle:statHarshlyFell";
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
case 6:
|
||||||
return i18next.t("battle:statSeverelyFell");
|
return "battle:statSeverelyFell";
|
||||||
default:
|
default:
|
||||||
return i18next.t("battle:statWontGoAnyLower");
|
return "battle:statWontGoAnyLower";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return i18next.t(stringKey, { pokemonNameWithAffix, stats });
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { Abilities } from "#enums/abilities";
|
|||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import i18next from "#app/plugins/i18n.js";
|
||||||
|
|
||||||
export enum BattlerTagLapseType {
|
export enum BattlerTagLapseType {
|
||||||
FAINT,
|
FAINT,
|
||||||
@ -105,7 +106,7 @@ export class RechargingTag extends BattlerTag {
|
|||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
super.lapse(pokemon, lapseType);
|
super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " must\nrecharge!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsRechargingLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
pokemon.getMoveQueue().shift();
|
pokemon.getMoveQueue().shift();
|
||||||
|
|
||||||
@ -134,7 +135,10 @@ export class TrappedTag extends BattlerTag {
|
|||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` was freed\nfrom ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsTrappedOnRemove", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescriptor(): string {
|
getDescriptor(): string {
|
||||||
@ -146,7 +150,7 @@ export class TrappedTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, " can no\nlonger escape!");
|
return i18next.t("battle:battlerTagsTrappedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +173,7 @@ export class FlinchedTag extends BattlerTag {
|
|||||||
super.lapse(pokemon, lapseType);
|
super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " flinched!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsFlinchedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -218,26 +222,26 @@ export class ConfusedTag extends BattlerTag {
|
|||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " became\nconfused!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " snapped\nout of confusion!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
onOverlap(pokemon: Pokemon): void {
|
onOverlap(pokemon: Pokemon): void {
|
||||||
super.onOverlap(pokemon);
|
super.onOverlap(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready confused!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
const ret = lapseType !== BattlerTagLapseType.CUSTOM && super.lapse(pokemon, lapseType);
|
const ret = lapseType !== BattlerTagLapseType.CUSTOM && super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nconfused!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
|
||||||
|
|
||||||
// 1/3 chance of hitting self with a 40 base power move
|
// 1/3 chance of hitting self with a 40 base power move
|
||||||
@ -245,7 +249,7 @@ export class ConfusedTag extends BattlerTag {
|
|||||||
const atk = pokemon.getBattleStat(Stat.ATK);
|
const atk = pokemon.getBattleStat(Stat.ATK);
|
||||||
const def = pokemon.getBattleStat(Stat.DEF);
|
const def = pokemon.getBattleStat(Stat.DEF);
|
||||||
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
|
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
|
||||||
pokemon.scene.queueMessage("It hurt itself in its\nconfusion!");
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedLapseHurtItself"));
|
||||||
pokemon.damageAndUpdate(damage);
|
pokemon.damageAndUpdate(damage);
|
||||||
pokemon.battleData.hitCount++;
|
pokemon.battleData.hitCount++;
|
||||||
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
@ -292,14 +296,17 @@ export class DestinyBondTag extends BattlerTag {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetMessage = getPokemonMessage(pokemon, "");
|
|
||||||
|
|
||||||
if (pokemon.isBossImmune()) {
|
if (pokemon.isBossImmune()) {
|
||||||
pokemon.scene.queueMessage(`${targetMessage} is unaffected\nby the effects of Destiny Bond.`);
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsDestinyBondLapseIsBoss", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pokemon.scene.queueMessage(`${getPokemonMessage(source, ` took\n${targetMessage} down with it!`)}`);
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsDestinyBondLapse", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(source),
|
||||||
|
pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon)
|
||||||
|
})
|
||||||
|
);
|
||||||
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, false, true);
|
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, false, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -317,24 +324,34 @@ export class InfatuatedTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` fell in love\nwith ${pokemon.scene.getPokemonById(this.sourceId).name}!`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsInfatuatedOnAdd", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onOverlap(pokemon: Pokemon): void {
|
onOverlap(pokemon: Pokemon): void {
|
||||||
super.onOverlap(pokemon);
|
super.onOverlap(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready in love!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is in love\nwith ${pokemon.scene.getPokemonById(this.sourceId).name}!`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsInfatuatedLapse", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
|
||||||
|
})
|
||||||
|
);
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
|
||||||
|
|
||||||
if (pokemon.randSeedInt(2)) {
|
if (pokemon.randSeedInt(2)) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nimmobilized by love!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedLapseImmobilize", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,7 +362,7 @@ export class InfatuatedTag extends BattlerTag {
|
|||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " got over\nits infatuation."));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
isSourceLinked(): boolean {
|
isSourceLinked(): boolean {
|
||||||
@ -380,7 +397,7 @@ export class SeedTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was seeded!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSeededOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +417,7 @@ export class SeedTag extends BattlerTag {
|
|||||||
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
||||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
|
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
|
||||||
!reverseDrain ? damage : damage * -1,
|
!reverseDrain ? damage : damage * -1,
|
||||||
!reverseDrain ? getPokemonMessage(pokemon, "'s health is\nsapped by Leech Seed!") : getPokemonMessage(source, "'s Leech Seed\nsucked up the liquid ooze!"),
|
!reverseDrain ? i18next.t("battle:battlerTagsSeededLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }) : i18next.t("battle:battlerTagsSeededLapseShed", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
|
||||||
false, true));
|
false, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,20 +439,20 @@ export class NightmareTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " began\nhaving a Nightmare!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
onOverlap(pokemon: Pokemon): void {
|
onOverlap(pokemon: Pokemon): void {
|
||||||
super.onOverlap(pokemon);
|
super.onOverlap(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready locked in a Nightmare!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is locked\nin a Nightmare!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
|
||||||
|
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
@ -527,7 +544,7 @@ export class EncoreTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " got\nan Encore!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEncoreOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
|
||||||
const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon);
|
const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon);
|
||||||
if (movePhase) {
|
if (movePhase) {
|
||||||
@ -543,7 +560,7 @@ export class EncoreTag extends BattlerTag {
|
|||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, "'s Encore\nended!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEncoreOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +570,12 @@ export class HelpingHandTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` is ready to\nhelp ${pokemon.name}!`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsHelpingHandOnAdd", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
|
||||||
|
pokemonName: pokemon.name
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,15 +603,22 @@ export class IngrainTag extends TrappedTag {
|
|||||||
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), Math.floor(pokemon.getMaxHp() / 16),
|
pokemon.scene.unshiftPhase(
|
||||||
getPokemonMessage(pokemon, " absorbed\nnutrients with its roots!"), true));
|
new PokemonHealPhase(
|
||||||
|
pokemon.scene,
|
||||||
|
pokemon.getBattlerIndex(),
|
||||||
|
Math.floor(pokemon.getMaxHp() / 16),
|
||||||
|
i18next.t("battle:battlerTagsIngrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, " planted its roots!");
|
return i18next.t("battle:battlerTagsIngrainOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescriptor(): string {
|
getDescriptor(): string {
|
||||||
@ -605,15 +634,23 @@ export class AquaRingTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " surrounded\nitself with a veil of water!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsAquaRingOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
|
pokemon.scene.unshiftPhase(
|
||||||
Math.floor(pokemon.getMaxHp() / 16), `${this.getMoveName()} restored\n${pokemon.name}\'s HP!`, true));
|
new PokemonHealPhase(
|
||||||
|
pokemon.scene,
|
||||||
|
pokemon.getBattlerIndex(),
|
||||||
|
Math.floor(pokemon.getMaxHp() / 16),
|
||||||
|
i18next.t("battle:battlerTagsAquaRingLapse", {
|
||||||
|
moveName: this.getMoveName(),
|
||||||
|
pokemonName: pokemon.name
|
||||||
|
}),
|
||||||
|
true));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -659,7 +696,7 @@ export class DrowsyTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " grew drowsy!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsDrowsyOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -702,7 +739,12 @@ export abstract class DamagingTrapTag extends TrappedTag {
|
|||||||
const ret = super.lapse(pokemon, lapseType);
|
const ret = super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsDamagingTrapLapse", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
})
|
||||||
|
);
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
|
||||||
|
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
@ -723,7 +765,11 @@ export class BindTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, ` was squeezed by\n${pokemon.scene.getPokemonById(this.sourceId).name}'s ${this.getMoveName()}!`);
|
return i18next.t("battle:battlerTagsBindOnTrap", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name,
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +779,10 @@ export class WrapTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, ` was Wrapped\nby ${pokemon.scene.getPokemonById(this.sourceId).name}!`);
|
return i18next.t("battle:battlerTagsWrapOnTrap", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,7 +792,7 @@ export abstract class VortexTrapTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, " was trapped\nin the vortex!");
|
return i18next.t("battle:battlerTagsVortexOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +814,10 @@ export class ClampTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` Clamped\n${pokemon.name}!`);
|
return i18next.t("battle:battlerTagsClampOnTrap", {
|
||||||
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
|
||||||
|
pokemonName: pokemon.name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -775,7 +827,10 @@ export class SandTombTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, ` became trapped\nby ${this.getMoveName()}!`);
|
return i18next.t("battle:battlerTagsSandTombOnTrap", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -785,7 +840,7 @@ export class MagmaStormTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, " became trapped\nby swirling magma!");
|
return i18next.t("battle:battlerTagsMagmaStormOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,7 +850,7 @@ export class SnapTrapTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, " got trapped\nby a snap trap!");
|
return i18next.t("battle:battlerTagsSnapTrapOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,7 +860,10 @@ export class ThunderCageTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` trapped\n${getPokemonNameWithAffix(pokemon)}!`);
|
return i18next.t("battle:battlerTagsThunderCageOnTrap", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,7 +873,10 @@ export class InfestationTag extends DamagingTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return getPokemonMessage(pokemon, ` has been afflicted \nwith an infestation by ${getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))}!`);
|
return i18next.t("battle:battlerTagsInfestationOnTrap", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,13 +889,13 @@ export class ProtectedTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, "\nprotected itself!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsProtectedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
||||||
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play(pokemon.scene);
|
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play(pokemon.scene);
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, "\nprotected itself!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsProtectedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,12 +1020,12 @@ export class EnduringTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " braced\nitself!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEnduringOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " endured\nthe hit!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEnduringLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,7 +1040,7 @@ export class SturdyTag extends BattlerTag {
|
|||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " endured\nthe hit!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSturdyLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,7 +1061,12 @@ export class PerishSongTag extends BattlerTag {
|
|||||||
const ret = super.lapse(pokemon, lapseType);
|
const ret = super.lapse(pokemon, lapseType);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, `\'s perish count fell to ${this.turnCount}.`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsPerishSongLapse", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
turnCount: this.turnCount
|
||||||
|
})
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, true, true);
|
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, true, true);
|
||||||
}
|
}
|
||||||
@ -1009,6 +1075,33 @@ export class PerishSongTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the "Center of Attention" volatile status effect, the effect applied by Follow Me, Rage Powder, and Spotlight.
|
||||||
|
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Center_of_attention | Center of Attention}
|
||||||
|
*/
|
||||||
|
export class CenterOfAttentionTag extends BattlerTag {
|
||||||
|
public powder: boolean;
|
||||||
|
|
||||||
|
constructor(sourceMove: Moves) {
|
||||||
|
super(BattlerTagType.CENTER_OF_ATTENTION, BattlerTagLapseType.TURN_END, 1, sourceMove);
|
||||||
|
|
||||||
|
this.powder = (this.sourceMove === Moves.RAGE_POWDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** "Center of Attention" can't be added if an ally is already the Center of Attention. */
|
||||||
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
|
const activeTeam = pokemon.isPlayer() ? pokemon.scene.getPlayerField() : pokemon.scene.getEnemyField();
|
||||||
|
|
||||||
|
return !activeTeam.find(p => p.getTag(BattlerTagType.CENTER_OF_ATTENTION));
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " became the center\nof attention!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class AbilityBattlerTag extends BattlerTag {
|
export class AbilityBattlerTag extends BattlerTag {
|
||||||
public ability: Abilities;
|
public ability: Abilities;
|
||||||
|
|
||||||
@ -1044,7 +1137,7 @@ export class TruantTag extends AbilityBattlerTag {
|
|||||||
if (lastMove && lastMove.move !== Moves.NONE) {
|
if (lastMove && lastMove.move !== Moves.NONE) {
|
||||||
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive));
|
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive));
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nloafing around!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsTruantLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1059,7 +1152,7 @@ export class SlowStartTag extends AbilityBattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " can't\nget it going!"), null, false, null, true);
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSlowStartOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, false, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -1073,7 +1166,7 @@ export class SlowStartTag extends AbilityBattlerTag {
|
|||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " finally\ngot its act together!"), null, false, null);
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSlowStartOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1119,13 +1212,13 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, `'s ${getStatName(highestStat)}\nwas heightened!`), null, false, null, true);
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsHighestStatBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), statName: getStatName(highestStat) }), null, false, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(`The effects of ${getPokemonMessage(pokemon, `'s\n${allAbilities[this.ability].name} wore off!`)}`);
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsHighestStatBoostOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: allAbilities[this.ability].name }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,7 +1258,7 @@ export class TerrainHighestStatBoostTag extends HighestStatBoostTag implements T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HideSpriteTag extends BattlerTag {
|
export class SemiInvulnerableTag extends BattlerTag {
|
||||||
constructor(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves) {
|
constructor(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves) {
|
||||||
super(tagType, BattlerTagLapseType.MOVE_EFFECT, turnCount, sourceMove);
|
super(tagType, BattlerTagLapseType.MOVE_EFFECT, turnCount, sourceMove);
|
||||||
}
|
}
|
||||||
@ -1187,8 +1280,11 @@ export class HideSpriteTag extends BattlerTag {
|
|||||||
|
|
||||||
export class TypeImmuneTag extends BattlerTag {
|
export class TypeImmuneTag extends BattlerTag {
|
||||||
public immuneType: Type;
|
public immuneType: Type;
|
||||||
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) {
|
|
||||||
super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove);
|
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number = 1) {
|
||||||
|
super(tagType, BattlerTagLapseType.TURN_END, length, sourceMove);
|
||||||
|
|
||||||
|
this.immuneType = immuneType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1205,6 +1301,18 @@ export class MagnetRisenTag extends TypeImmuneTag {
|
|||||||
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
||||||
super(tagType, sourceMove, Type.GROUND, 5);
|
super(tagType, sourceMove, Type.GROUND, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " levitated with electromagnetism!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(pokemon: Pokemon): void {
|
||||||
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " stopped levitating!"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TypeBoostTag extends BattlerTag {
|
export class TypeBoostTag extends BattlerTag {
|
||||||
@ -1244,7 +1352,7 @@ export class CritBoostTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is getting\npumped!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCritBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -1254,7 +1362,7 @@ export class CritBoostTag extends BattlerTag {
|
|||||||
onRemove(pokemon: Pokemon): void {
|
onRemove(pokemon: Pokemon): void {
|
||||||
super.onRemove(pokemon);
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " relaxed."));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCritBoostOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1289,7 +1397,7 @@ export class SaltCuredTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is being salt cured!"));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSaltCuredOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1306,7 +1414,12 @@ export class SaltCuredTag extends BattlerTag {
|
|||||||
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
|
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
|
||||||
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
|
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsSaltCuredLapse", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1332,8 +1445,6 @@ export class CursedTag extends BattlerTag {
|
|||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " has been cursed!"));
|
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,7 +1459,7 @@ export class CursedTag extends BattlerTag {
|
|||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1));
|
pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1));
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by the ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1356,6 +1467,17 @@ export class CursedTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Battler tag for effects that ground the source, allowing Ground-type moves to hit them. Encompasses two tag types:
|
||||||
|
* @item IGNORE_FLYING: Persistent grounding effects (i.e. from Smack Down and Thousand Waves)
|
||||||
|
* @item ROOSTED: One-turn grounding effects (i.e. from Roost)
|
||||||
|
*/
|
||||||
|
export class GroundedTag extends BattlerTag {
|
||||||
|
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, sourceMove: Moves) {
|
||||||
|
super(tagType, lapseType, 1, sourceMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Ice Face ability's effects.
|
* Provides the Ice Face ability's effects.
|
||||||
*/
|
*/
|
||||||
@ -1479,6 +1601,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||||||
return new SturdyTag(sourceMove);
|
return new SturdyTag(sourceMove);
|
||||||
case BattlerTagType.PERISH_SONG:
|
case BattlerTagType.PERISH_SONG:
|
||||||
return new PerishSongTag(turnCount);
|
return new PerishSongTag(turnCount);
|
||||||
|
case BattlerTagType.CENTER_OF_ATTENTION:
|
||||||
|
return new CenterOfAttentionTag(sourceMove);
|
||||||
case BattlerTagType.TRUANT:
|
case BattlerTagType.TRUANT:
|
||||||
return new TruantTag();
|
return new TruantTag();
|
||||||
case BattlerTagType.SLOW_START:
|
case BattlerTagType.SLOW_START:
|
||||||
@ -1491,7 +1615,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||||||
case BattlerTagType.UNDERGROUND:
|
case BattlerTagType.UNDERGROUND:
|
||||||
case BattlerTagType.UNDERWATER:
|
case BattlerTagType.UNDERWATER:
|
||||||
case BattlerTagType.HIDDEN:
|
case BattlerTagType.HIDDEN:
|
||||||
return new HideSpriteTag(tagType, turnCount, sourceMove);
|
return new SemiInvulnerableTag(tagType, turnCount, sourceMove);
|
||||||
case BattlerTagType.FIRE_BOOST:
|
case BattlerTagType.FIRE_BOOST:
|
||||||
return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false);
|
return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false);
|
||||||
case BattlerTagType.CRIT_BOOST:
|
case BattlerTagType.CRIT_BOOST:
|
||||||
@ -1505,9 +1629,9 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||||||
case BattlerTagType.BYPASS_SLEEP:
|
case BattlerTagType.BYPASS_SLEEP:
|
||||||
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
||||||
case BattlerTagType.IGNORE_FLYING:
|
case BattlerTagType.IGNORE_FLYING:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
return new GroundedTag(tagType, BattlerTagLapseType.CUSTOM, sourceMove);
|
||||||
case BattlerTagType.GROUNDED:
|
case BattlerTagType.ROOSTED:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount - 1, sourceMove);
|
return new GroundedTag(tagType, BattlerTagLapseType.TURN_END, sourceMove);
|
||||||
case BattlerTagType.SALT_CURED:
|
case BattlerTagType.SALT_CURED:
|
||||||
return new SaltCuredTag(sourceId);
|
return new SaltCuredTag(sourceId);
|
||||||
case BattlerTagType.CURSED:
|
case BattlerTagType.CURSED:
|
||||||
|
@ -5,7 +5,7 @@ import { BattleStat } from "./battle-stat";
|
|||||||
import { getStatusEffectHealText } from "./status-effect";
|
import { getStatusEffectHealText } from "./status-effect";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
|
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
|
||||||
import i18next from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
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";
|
||||||
|
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import i18next from "#app/plugins/i18n.js";
|
import i18next from "i18next";
|
||||||
import { GameData } from "#app/system/game-data.js";
|
import { DexAttrProps, GameData } from "#app/system/game-data.js";
|
||||||
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
|
||||||
import Pokemon from "#app/field/pokemon.js";
|
import Pokemon from "#app/field/pokemon.js";
|
||||||
import { BattleType, FixedBattleConfig } from "#app/battle.js";
|
import { BattleType, FixedBattleConfig } from "#app/battle.js";
|
||||||
import Trainer, { TrainerVariant } from "#app/field/trainer.js";
|
import Trainer, { TrainerVariant } from "#app/field/trainer.js";
|
||||||
import { GameMode } from "#app/game-mode.js";
|
import { GameMode } from "#app/game-mode.js";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
|
import { pokemonEvolutions } from "./pokemon-evolutions";
|
||||||
|
import { pokemonFormChanges } from "./pokemon-forms";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
|
import { TypeColor, TypeShadow } from "#app/enums/color.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum for all the challenge types. The parameter entries on these describe the
|
* An enum for all the challenge types. The parameter entries on these describe the
|
||||||
@ -158,7 +161,7 @@ export abstract class Challenge {
|
|||||||
if (overrideValue === undefined) {
|
if (overrideValue === undefined) {
|
||||||
overrideValue = this.value;
|
overrideValue = this.value;
|
||||||
}
|
}
|
||||||
return i18next.t(`challenges:${this.geti18nKey()}.desc.${this.value}`);
|
return `${i18next.t("challenges:usePokemon")}${i18next.t(`challenges:${this.geti18nKey()}.desc.${this.value}`)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,8 +280,22 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
case ChallengeType.STARTER_CHOICE:
|
case ChallengeType.STARTER_CHOICE:
|
||||||
const species = args[0] as PokemonSpecies;
|
const species = args[0] as PokemonSpecies;
|
||||||
const isValidStarter = args[1] as Utils.BooleanHolder;
|
const isValidStarter = args[1] as Utils.BooleanHolder;
|
||||||
|
const amountOfPokemon = args[3] as number;
|
||||||
const starterGeneration = species.speciesId === Species.VICTINI ? 5 : species.generation;
|
const starterGeneration = species.speciesId === Species.VICTINI ? 5 : species.generation;
|
||||||
if (starterGeneration !== this.value) {
|
const generations = [starterGeneration];
|
||||||
|
if (amountOfPokemon > 0) {
|
||||||
|
const speciesToCheck = [species.speciesId];
|
||||||
|
while (speciesToCheck.length) {
|
||||||
|
const checking = speciesToCheck.pop();
|
||||||
|
if (pokemonEvolutions.hasOwnProperty(checking)) {
|
||||||
|
pokemonEvolutions[checking].forEach(e => {
|
||||||
|
speciesToCheck.push(e.speciesId);
|
||||||
|
generations.push(getPokemonSpecies(e.speciesId).generation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!generations.includes(this.value)) {
|
||||||
isValidStarter.value = false;
|
isValidStarter.value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -331,6 +348,37 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
return this.value > 0 ? 1 : 0;
|
return this.value > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the textual representation of a challenge's current value.
|
||||||
|
* @param {value} overrideValue The value to check for. If undefined, gets the current value.
|
||||||
|
* @returns {string} The localised name for the current value.
|
||||||
|
*/
|
||||||
|
getValue(overrideValue?: integer): string {
|
||||||
|
if (overrideValue === undefined) {
|
||||||
|
overrideValue = this.value;
|
||||||
|
}
|
||||||
|
if (this.value === 0) {
|
||||||
|
return i18next.t("settings:off");
|
||||||
|
}
|
||||||
|
return i18next.t(`starterSelectUiHandler:gen${this.value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of a challenge's current value.
|
||||||
|
* @param {value} overrideValue The value to check for. If undefined, gets the current value.
|
||||||
|
* @returns {string} The localised description for the current value.
|
||||||
|
*/
|
||||||
|
getDescription(overrideValue?: integer): string {
|
||||||
|
if (overrideValue === undefined) {
|
||||||
|
overrideValue = this.value;
|
||||||
|
}
|
||||||
|
if (this.value === 0) {
|
||||||
|
return i18next.t("challenges:singleGeneration.desc_default");
|
||||||
|
}
|
||||||
|
return i18next.t("challenges:singleGeneration.desc", { gen: i18next.t(`challenges:singleGeneration.gen_${this.value}`) });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static loadChallenge(source: SingleGenerationChallenge | any): SingleGenerationChallenge {
|
static loadChallenge(source: SingleGenerationChallenge | any): SingleGenerationChallenge {
|
||||||
const newChallenge = new SingleGenerationChallenge();
|
const newChallenge = new SingleGenerationChallenge();
|
||||||
newChallenge.value = source.value;
|
newChallenge.value = source.value;
|
||||||
@ -372,7 +420,32 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
case ChallengeType.STARTER_CHOICE:
|
case ChallengeType.STARTER_CHOICE:
|
||||||
const species = args[0] as PokemonSpecies;
|
const species = args[0] as PokemonSpecies;
|
||||||
const isValidStarter = args[1] as Utils.BooleanHolder;
|
const isValidStarter = args[1] as Utils.BooleanHolder;
|
||||||
if (!species.isOfType(this.value - 1)) {
|
const dexAttr = args[2] as DexAttrProps;
|
||||||
|
const amountOfPokemon = args[3] as number;
|
||||||
|
const speciesForm = getPokemonSpeciesForm(species.speciesId, dexAttr.formIndex);
|
||||||
|
const types = [speciesForm.type1, speciesForm.type2];
|
||||||
|
if (amountOfPokemon > 0) {
|
||||||
|
const speciesToCheck = [species.speciesId];
|
||||||
|
while (speciesToCheck.length) {
|
||||||
|
const checking = speciesToCheck.pop();
|
||||||
|
if (pokemonEvolutions.hasOwnProperty(checking)) {
|
||||||
|
pokemonEvolutions[checking].forEach(e => {
|
||||||
|
speciesToCheck.push(e.speciesId);
|
||||||
|
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (pokemonFormChanges.hasOwnProperty(checking)) {
|
||||||
|
pokemonFormChanges[checking].forEach(f1 => {
|
||||||
|
getPokemonSpecies(checking).forms.forEach(f2 => {
|
||||||
|
if (f1.formKey === f2.formKey) {
|
||||||
|
types.push(f2.type1, f2.type2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!types.includes(this.value - 1)) {
|
||||||
isValidStarter.value = false;
|
isValidStarter.value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -397,6 +470,34 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
return this.value > 0 ? 1 : 0;
|
return this.value > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the textual representation of a challenge's current value.
|
||||||
|
* @param {value} overrideValue The value to check for. If undefined, gets the current value.
|
||||||
|
* @returns {string} The localised name for the current value.
|
||||||
|
*/
|
||||||
|
getValue(overrideValue?: integer): string {
|
||||||
|
if (overrideValue === undefined) {
|
||||||
|
overrideValue = this.value;
|
||||||
|
}
|
||||||
|
return Type[this.value - 1].toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of a challenge's current value.
|
||||||
|
* @param {value} overrideValue The value to check for. If undefined, gets the current value.
|
||||||
|
* @returns {string} The localised description for the current value.
|
||||||
|
*/
|
||||||
|
getDescription(overrideValue?: integer): string {
|
||||||
|
if (overrideValue === undefined) {
|
||||||
|
overrideValue = this.value;
|
||||||
|
}
|
||||||
|
const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`);
|
||||||
|
const typeColor = `[color=${TypeColor[Type[this.value-1]]}][shadow=${TypeShadow[Type[this.value-1]]}]${type}[/shadow][/color]`;
|
||||||
|
const defaultDesc = i18next.t("challenges:singleType.desc_default");
|
||||||
|
const typeDesc = i18next.t("challenges:singleType.desc", {type: typeColor});
|
||||||
|
return this.value === 0 ? defaultDesc : typeDesc;
|
||||||
|
}
|
||||||
|
|
||||||
static loadChallenge(source: SingleTypeChallenge | any): SingleTypeChallenge {
|
static loadChallenge(source: SingleTypeChallenge | any): SingleTypeChallenge {
|
||||||
const newChallenge = new SingleTypeChallenge();
|
const newChallenge = new SingleTypeChallenge();
|
||||||
newChallenge.value = source.value;
|
newChallenge.value = source.value;
|
||||||
@ -535,7 +636,7 @@ export class LowerStarterPointsChallenge extends Challenge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply all challenges of a given challenge type.
|
* Apply all challenges of a given challenge type.
|
||||||
* @param {BattleScene} scene The current scene
|
* @param {GameMode} gameMode The current game mode
|
||||||
* @param {ChallengeType} challengeType What challenge type to apply
|
* @param {ChallengeType} challengeType What challenge type to apply
|
||||||
* @param {any[]} args Any args for that challenge type
|
* @param {any[]} args Any args for that challenge type
|
||||||
* @returns {boolean} True if any challenge was successfully applied.
|
* @returns {boolean} True if any challenge was successfully applied.
|
||||||
|
529
src/data/egg.ts
@ -1,61 +1,244 @@
|
|||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
||||||
import i18next from "../plugins/i18n";
|
import { VariantTier } from "../enums/variant-tiers";
|
||||||
|
import * as Utils from "../utils";
|
||||||
|
import * as Overrides from "../overrides";
|
||||||
|
import { pokemonPrevolutions } from "./pokemon-evolutions";
|
||||||
|
import { PlayerPokemon } from "#app/field/pokemon";
|
||||||
|
import i18next from "i18next";
|
||||||
import { EggTier } from "#enums/egg-type";
|
import { EggTier } from "#enums/egg-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { EggSourceType } from "#app/enums/egg-source-types.js";
|
||||||
|
|
||||||
export const EGG_SEED = 1073741824;
|
export const EGG_SEED = 1073741824;
|
||||||
|
|
||||||
export enum GachaType {
|
// Rates for specific random properties in 1/x
|
||||||
MOVE,
|
const DEFAULT_SHINY_RATE = 128;
|
||||||
LEGENDARY,
|
const GACHA_SHINY_UP_SHINY_RATE = 64;
|
||||||
SHINY
|
const SAME_SPECIES_EGG_SHINY_RATE = 32;
|
||||||
|
const SAME_SPECIES_EGG_HA_RATE = 16;
|
||||||
|
const MANAPHY_EGG_MANAPHY_RATE = 8;
|
||||||
|
|
||||||
|
// 1/x for legendary eggs, 1/x*2 for epic eggs, 1/x*4 for rare eggs, and 1/x*8 for common eggs
|
||||||
|
const DEFAULT_RARE_EGGMOVE_RATE = 6;
|
||||||
|
const SAME_SPECIES_EGG_RARE_EGGMOVE_RATE = 3;
|
||||||
|
const GACHA_MOVE_UP_RARE_EGGMOVE_RATE = 3;
|
||||||
|
|
||||||
|
/** Egg options to override egg properties */
|
||||||
|
export interface IEggOptions {
|
||||||
|
/** Id. Used to check if egg type will be manaphy (id % 204 === 0) */
|
||||||
|
id?: number;
|
||||||
|
/** Timestamp when this egg got created */
|
||||||
|
timestamp?: number;
|
||||||
|
/** Defines if the egg got pulled from a gacha or not. If true, egg pity and pull statistics will be applyed.
|
||||||
|
* Egg will be automaticly added to the game data.
|
||||||
|
* NEEDS scene eggOption to work.
|
||||||
|
*/
|
||||||
|
pulled?: boolean;
|
||||||
|
/** Defines where the egg comes from. Applies specific modifiers.
|
||||||
|
* Will also define the text displayed in the egg list.
|
||||||
|
*/
|
||||||
|
sourceType?: EggSourceType;
|
||||||
|
/** Needs to be defined if eggOption pulled is defined or if no species or isShiny is degined since this will be needed to generate them. */
|
||||||
|
scene?: BattleScene;
|
||||||
|
/** Sets the tier of the egg. Only species of this tier can be hatched from this egg.
|
||||||
|
* Tier will be overriden if species eggOption is set.
|
||||||
|
*/
|
||||||
|
tier?: EggTier;
|
||||||
|
/** Sets how many waves it will take till this egg hatches. */
|
||||||
|
hatchWaves?: number;
|
||||||
|
/** Sets the exact species that will hatch from this egg.
|
||||||
|
* Needs scene eggOption if not provided.
|
||||||
|
*/
|
||||||
|
species?: Species;
|
||||||
|
/** Defines if the hatched pokemon will be a shiny. */
|
||||||
|
isShiny?: boolean;
|
||||||
|
/** Defines the variant of the pokemon that will hatch from this egg. If no variantTier is given the normal variant rates will apply. */
|
||||||
|
variantTier?: VariantTier;
|
||||||
|
/** Defines which egg move will be unlocked. 3 = rare egg move. */
|
||||||
|
eggMoveIndex?: number;
|
||||||
|
/** Defines if the egg will hatch with the hidden ability of this species.
|
||||||
|
* If no hidden ability exist, a random one will get choosen.
|
||||||
|
*/
|
||||||
|
overrideHiddenAbility?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Egg {
|
export class Egg {
|
||||||
public id: integer;
|
|
||||||
public tier: EggTier;
|
|
||||||
public gachaType: GachaType;
|
|
||||||
public hatchWaves: integer;
|
|
||||||
public timestamp: integer;
|
|
||||||
|
|
||||||
constructor(id: integer, gachaType: GachaType, hatchWaves: integer, timestamp: integer) {
|
////
|
||||||
this.id = id;
|
// #region Privat properties
|
||||||
this.tier = Math.floor(id / EGG_SEED);
|
////
|
||||||
this.gachaType = gachaType;
|
|
||||||
this.hatchWaves = hatchWaves;
|
private _id: number;
|
||||||
this.timestamp = timestamp;
|
private _tier: EggTier;
|
||||||
|
private _sourceType: EggSourceType | undefined;
|
||||||
|
private _hatchWaves: number;
|
||||||
|
private _timestamp: number;
|
||||||
|
|
||||||
|
private _species: Species;
|
||||||
|
private _isShiny: boolean;
|
||||||
|
private _variantTier: VariantTier;
|
||||||
|
private _eggMoveIndex: number;
|
||||||
|
|
||||||
|
private _overrideHiddenAbility: boolean;
|
||||||
|
|
||||||
|
////
|
||||||
|
// #endregion
|
||||||
|
////
|
||||||
|
|
||||||
|
////
|
||||||
|
// #region Public facing properties
|
||||||
|
////
|
||||||
|
get id(): number {
|
||||||
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
isManaphyEgg(): boolean {
|
get tier(): EggTier {
|
||||||
return this.tier === EggTier.COMMON && !(this.id % 204);
|
return this._tier;
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey(): string {
|
get sourceType(): EggSourceType | undefined {
|
||||||
|
return this._sourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hatchWaves(): number {
|
||||||
|
return this._hatchWaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
set hatchWaves(value: number) {
|
||||||
|
this._hatchWaves = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get timestamp(): number {
|
||||||
|
return this._timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
get species(): Species {
|
||||||
|
return this._species;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isShiny(): boolean {
|
||||||
|
return this._isShiny;
|
||||||
|
}
|
||||||
|
|
||||||
|
get variantTier(): VariantTier {
|
||||||
|
return this._variantTier;
|
||||||
|
}
|
||||||
|
|
||||||
|
get eggMoveIndex(): number {
|
||||||
|
return this._eggMoveIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
get overrideHiddenAbility(): boolean {
|
||||||
|
return this._overrideHiddenAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// #endregion
|
||||||
|
////
|
||||||
|
|
||||||
|
constructor(eggOptions?: IEggOptions) {
|
||||||
|
//if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.")
|
||||||
|
|
||||||
|
this._sourceType = eggOptions.sourceType ?? undefined;
|
||||||
|
// Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced
|
||||||
|
this._tier = eggOptions.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier());
|
||||||
|
// If egg was pulled, check if egg pity needs to override the egg tier
|
||||||
|
if (eggOptions.pulled) {
|
||||||
|
// Needs this._tier and this._sourceType to work
|
||||||
|
this.checkForPityTierOverrides(eggOptions.scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._id = eggOptions.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
||||||
|
|
||||||
|
this._sourceType = eggOptions.sourceType ?? undefined;
|
||||||
|
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
|
this._timestamp = eggOptions.timestamp ?? new Date().getTime();
|
||||||
|
|
||||||
|
// First roll shiny and variant so we can filter if species with an variant exist
|
||||||
|
this._isShiny = eggOptions.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
|
||||||
|
this._variantTier = eggOptions.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant());
|
||||||
|
this._species = eggOptions.species ?? this.rollSpecies(eggOptions.scene);
|
||||||
|
|
||||||
|
this._overrideHiddenAbility = eggOptions.overrideHiddenAbility ?? false;
|
||||||
|
|
||||||
|
// Override egg tier and hatchwaves if species was given
|
||||||
|
if (eggOptions.species) {
|
||||||
|
this._tier = this.getEggTierFromSpeciesStarterValue();
|
||||||
|
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
|
// If species has no variant, set variantTier to common. This needs to
|
||||||
|
// be done because species with no variants get filtered at rollSpecies but since the
|
||||||
|
// species is set the check never happens
|
||||||
|
if (!getPokemonSpecies(this.species).hasVariants()) {
|
||||||
|
this._variantTier = VariantTier.COMMON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Needs this._tier so it needs to be generated afer the tier override if bought from same species
|
||||||
|
this._eggMoveIndex = eggOptions.eggMoveIndex ?? this.rollEggMoveIndex();
|
||||||
|
if (eggOptions.pulled) {
|
||||||
|
this.increasePullStatistic(eggOptions.scene);
|
||||||
|
this.addEggToGameData(eggOptions.scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// #region Public methodes
|
||||||
|
////
|
||||||
|
|
||||||
|
public isManaphyEgg(): boolean {
|
||||||
|
return (this._species === Species.PHIONE || this._species === Species.MANAPHY) ||
|
||||||
|
this._tier === EggTier.COMMON && !(this._id % 204) && !this._species;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getKey(): string {
|
||||||
if (this.isManaphyEgg()) {
|
if (this.isManaphyEgg()) {
|
||||||
return "manaphy";
|
return "manaphy";
|
||||||
}
|
}
|
||||||
return this.tier.toString();
|
return this._tier.toString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export function getEggTierDefaultHatchWaves(tier: EggTier): integer {
|
// Generates a PlayerPokemon from an egg
|
||||||
switch (tier) {
|
public generatePlayerPokemon(scene: BattleScene): PlayerPokemon {
|
||||||
case EggTier.COMMON:
|
// Legacy egg wants to hatch. Generate missing properties
|
||||||
return 10;
|
if (!this._species) {
|
||||||
case EggTier.GREAT:
|
this._isShiny = this.rollShiny();
|
||||||
return 25;
|
this._species = this.rollSpecies(scene);
|
||||||
case EggTier.ULTRA:
|
|
||||||
return 50;
|
|
||||||
}
|
}
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEggDescriptor(egg: Egg): string {
|
const pokemonSpecies = getPokemonSpecies(this._species);
|
||||||
if (egg.isManaphyEgg()) {
|
|
||||||
|
// Sets the hidden ability if a hidden ability exists and the override is set
|
||||||
|
// or if the same species egg hits the chance
|
||||||
|
let abilityIndex = undefined;
|
||||||
|
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility
|
||||||
|
|| (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE)))) {
|
||||||
|
abilityIndex = pokemonSpecies.ability2 ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function has way to many optional parameters
|
||||||
|
const ret: PlayerPokemon = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
|
||||||
|
ret.shiny = this._isShiny;
|
||||||
|
ret.variant = this._variantTier;
|
||||||
|
|
||||||
|
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
||||||
|
|
||||||
|
for (let s = 0; s < ret.ivs.length; s++) {
|
||||||
|
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doesn't need to be called if the egg got pulled by a gacha machiene
|
||||||
|
public addEggToGameData(scene: BattleScene): void {
|
||||||
|
scene.gameData.eggs.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEggDescriptor(): string {
|
||||||
|
if (this.isManaphyEgg()) {
|
||||||
return "Manaphy";
|
return "Manaphy";
|
||||||
}
|
}
|
||||||
switch (egg.tier) {
|
switch (this.tier) {
|
||||||
case EggTier.GREAT:
|
case EggTier.GREAT:
|
||||||
return i18next.t("egg:greatTier");
|
return i18next.t("egg:greatTier");
|
||||||
case EggTier.ULTRA:
|
case EggTier.ULTRA:
|
||||||
@ -65,33 +248,279 @@ export function getEggDescriptor(egg: Egg): string {
|
|||||||
default:
|
default:
|
||||||
return i18next.t("egg:defaultTier");
|
return i18next.t("egg:defaultTier");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEggHatchWavesMessage(hatchWaves: integer): string {
|
public getEggHatchWavesMessage(): string {
|
||||||
if (hatchWaves <= 5) {
|
if (this.hatchWaves <= 5) {
|
||||||
return i18next.t("egg:hatchWavesMessageSoon");
|
return i18next.t("egg:hatchWavesMessageSoon");
|
||||||
}
|
}
|
||||||
if (hatchWaves <= 15) {
|
if (this.hatchWaves <= 15) {
|
||||||
return i18next.t("egg:hatchWavesMessageClose");
|
return i18next.t("egg:hatchWavesMessageClose");
|
||||||
}
|
}
|
||||||
if (hatchWaves <= 50) {
|
if (this.hatchWaves <= 50) {
|
||||||
return i18next.t("egg:hatchWavesMessageNotClose");
|
return i18next.t("egg:hatchWavesMessageNotClose");
|
||||||
}
|
}
|
||||||
return i18next.t("egg:hatchWavesMessageLongTime");
|
return i18next.t("egg:hatchWavesMessageLongTime");
|
||||||
}
|
|
||||||
|
|
||||||
export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string {
|
|
||||||
switch (egg.gachaType) {
|
|
||||||
case GachaType.LEGENDARY:
|
|
||||||
return `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`;
|
|
||||||
case GachaType.MOVE:
|
|
||||||
return i18next.t("egg:gachaTypeMove");
|
|
||||||
case GachaType.SHINY:
|
|
||||||
return i18next.t("egg:gachaTypeShiny");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getEggTypeDescriptor(scene: BattleScene): string {
|
||||||
|
switch (this.sourceType) {
|
||||||
|
case EggSourceType.SAME_SPECIES_EGG:
|
||||||
|
return i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName()});
|
||||||
|
case EggSourceType.GACHA_LEGENDARY:
|
||||||
|
return `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`;
|
||||||
|
case EggSourceType.GACHA_SHINY:
|
||||||
|
return i18next.t("egg:gachaTypeShiny");
|
||||||
|
case EggSourceType.GACHA_MOVE:
|
||||||
|
return i18next.t("egg:gachaTypeMove");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// #endregion
|
||||||
|
////
|
||||||
|
|
||||||
|
////
|
||||||
|
// #region Private methodes
|
||||||
|
////
|
||||||
|
|
||||||
|
private rollEggMoveIndex() {
|
||||||
|
let baseChance = DEFAULT_RARE_EGGMOVE_RATE;
|
||||||
|
switch (this._sourceType) {
|
||||||
|
case EggSourceType.SAME_SPECIES_EGG:
|
||||||
|
baseChance = SAME_SPECIES_EGG_RARE_EGGMOVE_RATE;
|
||||||
|
break;
|
||||||
|
case EggSourceType.GACHA_MOVE:
|
||||||
|
baseChance = GACHA_MOVE_UP_RARE_EGGMOVE_RATE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.randSeedInt(baseChance * Math.pow(2, 3 - this.tier)) ? Utils.randSeedInt(3) : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
|
||||||
|
if (this._species === Species.PHIONE || this._species === Species.MANAPHY) {
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (eggTier ?? this._tier) {
|
||||||
|
case EggTier.COMMON:
|
||||||
|
return 10;
|
||||||
|
case EggTier.GREAT:
|
||||||
|
return 25;
|
||||||
|
case EggTier.ULTRA:
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private rollEggTier(): EggTier {
|
||||||
|
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? 1 : 0;
|
||||||
|
const tierValue = Utils.randInt(256);
|
||||||
|
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
private rollSpecies(scene: BattleScene): Species {
|
||||||
|
if (!scene) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione
|
||||||
|
* Legendary eggs pulled from the legendary gacha have a 50% of being converted into
|
||||||
|
* the species that was the legendary focus at the time
|
||||||
|
*/
|
||||||
|
if (this.isManaphyEgg()) {
|
||||||
|
const rand = Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE);
|
||||||
|
return rand ? Species.PHIONE : Species.MANAPHY;
|
||||||
|
} else if (this.tier === EggTier.MASTER
|
||||||
|
&& this._sourceType === EggSourceType.GACHA_LEGENDARY) {
|
||||||
|
if (!Utils.randSeedInt(2)) {
|
||||||
|
return getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let minStarterValue: integer;
|
||||||
|
let maxStarterValue: integer;
|
||||||
|
|
||||||
|
switch (this.tier) {
|
||||||
|
case EggTier.GREAT:
|
||||||
|
minStarterValue = 4;
|
||||||
|
maxStarterValue = 5;
|
||||||
|
break;
|
||||||
|
case EggTier.ULTRA:
|
||||||
|
minStarterValue = 6;
|
||||||
|
maxStarterValue = 7;
|
||||||
|
break;
|
||||||
|
case EggTier.MASTER:
|
||||||
|
minStarterValue = 8;
|
||||||
|
maxStarterValue = 9;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
minStarterValue = 1;
|
||||||
|
maxStarterValue = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ignoredSpecies = [Species.PHIONE, Species.MANAPHY, Species.ETERNATUS];
|
||||||
|
|
||||||
|
let speciesPool = Object.keys(speciesStarters)
|
||||||
|
.filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue)
|
||||||
|
.map(s => parseInt(s) as Species)
|
||||||
|
.filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
|
||||||
|
|
||||||
|
// If this is the 10th egg without unlocking something new, attempt to force it.
|
||||||
|
if (scene.gameData.unlockPity[this.tier] >= 9) {
|
||||||
|
const lockedPool = speciesPool.filter(s => !scene.gameData.dexData[s].caughtAttr && !scene.gameData.eggs.some(e => e.species === s));
|
||||||
|
if (lockedPool.length) { // Skip this if everything is unlocked
|
||||||
|
speciesPool = lockedPool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If egg variant is set to RARE or EPIC, filter species pool to only include ones with variants.
|
||||||
|
if (this.variantTier && (this.variantTier === VariantTier.RARE || this.variantTier === VariantTier.EPIC)) {
|
||||||
|
speciesPool = speciesPool.filter(s => getPokemonSpecies(s).hasVariants());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pokemon that are cheaper in their tier get a weight boost. Regionals get a weight penalty
|
||||||
|
* 1 cost mons get 2x
|
||||||
|
* 2 cost mons get 1.5x
|
||||||
|
* 4, 6, 8 cost mons get 1.75x
|
||||||
|
* 3, 5, 7, 9 cost mons get 1x
|
||||||
|
* Alolan, Galarian, and Paldean mons get 0.5x
|
||||||
|
* Hisui mons get 0.125x
|
||||||
|
*
|
||||||
|
* The total weight is also being calculated EACH time there is an egg hatch instead of being generated once
|
||||||
|
* and being the same each time
|
||||||
|
*/
|
||||||
|
let totalWeight = 0;
|
||||||
|
const speciesWeights = [];
|
||||||
|
for (const speciesId of speciesPool) {
|
||||||
|
let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
|
||||||
|
const species = getPokemonSpecies(speciesId);
|
||||||
|
if (species.isRegional()) {
|
||||||
|
weight = Math.floor(weight / (species.isRareRegional() ? 8 : 2));
|
||||||
|
}
|
||||||
|
speciesWeights.push(totalWeight + weight);
|
||||||
|
totalWeight += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let species: Species;
|
||||||
|
|
||||||
|
const rand = Utils.randSeedInt(totalWeight);
|
||||||
|
for (let s = 0; s < speciesWeights.length; s++) {
|
||||||
|
if (rand < speciesWeights[s]) {
|
||||||
|
species = speciesPool[s];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!scene.gameData.dexData[species].caughtAttr || scene.gameData.eggs.some(e => e.species === species)) {
|
||||||
|
scene.gameData.unlockPity[this.tier] = Math.min(scene.gameData.unlockPity[this.tier] + 1, 10);
|
||||||
|
} else {
|
||||||
|
scene.gameData.unlockPity[this.tier] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return species;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rolls whether the egg is shiny or not.
|
||||||
|
* @returns True if the egg is shiny
|
||||||
|
**/
|
||||||
|
private rollShiny(): boolean {
|
||||||
|
let shinyChance = DEFAULT_SHINY_RATE;
|
||||||
|
switch (this._sourceType) {
|
||||||
|
case EggSourceType.GACHA_SHINY:
|
||||||
|
shinyChance = GACHA_SHINY_UP_SHINY_RATE;
|
||||||
|
break;
|
||||||
|
case EggSourceType.SAME_SPECIES_EGG:
|
||||||
|
shinyChance = SAME_SPECIES_EGG_SHINY_RATE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Utils.randSeedInt(shinyChance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one
|
||||||
|
// place but I don't want to touch the pokemon class.
|
||||||
|
private rollVariant(): VariantTier {
|
||||||
|
if (!this.isShiny) {
|
||||||
|
return VariantTier.COMMON;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rand = Utils.randSeedInt(10);
|
||||||
|
if (rand >= 4) {
|
||||||
|
return VariantTier.COMMON; // 6/10
|
||||||
|
} else if (rand >= 1) {
|
||||||
|
return VariantTier.RARE; // 3/10
|
||||||
|
} else {
|
||||||
|
return VariantTier.EPIC; // 1/10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkForPityTierOverrides(scene: BattleScene): void {
|
||||||
|
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? 1 : 0;
|
||||||
|
scene.gameData.eggPity[EggTier.GREAT] += 1;
|
||||||
|
scene.gameData.eggPity[EggTier.ULTRA] += 1;
|
||||||
|
scene.gameData.eggPity[EggTier.MASTER] += 1 + tierValueOffset;
|
||||||
|
// These numbers are roughly the 80% mark. That is, 80% of the time you'll get an egg before this gets triggered.
|
||||||
|
if (scene.gameData.eggPity[EggTier.MASTER] >= 412 && this._tier === EggTier.COMMON) {
|
||||||
|
this._tier = EggTier.MASTER;
|
||||||
|
} else if (scene.gameData.eggPity[EggTier.ULTRA] >= 59 && this._tier === EggTier.COMMON) {
|
||||||
|
this._tier = EggTier.ULTRA;
|
||||||
|
} else if (scene.gameData.eggPity[EggTier.GREAT] >= 9 && this._tier === EggTier.COMMON) {
|
||||||
|
this._tier = EggTier.GREAT;
|
||||||
|
}
|
||||||
|
scene.gameData.eggPity[this._tier] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private increasePullStatistic(scene: BattleScene): void {
|
||||||
|
scene.gameData.gameStats.eggsPulled++;
|
||||||
|
if (this.isManaphyEgg()) {
|
||||||
|
scene.gameData.gameStats.manaphyEggsPulled++;
|
||||||
|
this._hatchWaves = this.getEggTierDefaultHatchWaves(EggTier.ULTRA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (this.tier) {
|
||||||
|
case EggTier.GREAT:
|
||||||
|
scene.gameData.gameStats.rareEggsPulled++;
|
||||||
|
break;
|
||||||
|
case EggTier.ULTRA:
|
||||||
|
scene.gameData.gameStats.epicEggsPulled++;
|
||||||
|
break;
|
||||||
|
case EggTier.MASTER:
|
||||||
|
scene.gameData.gameStats.legendaryEggsPulled++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEggTierFromSpeciesStarterValue(): EggTier {
|
||||||
|
const speciesStartValue = speciesStarters[this.species];
|
||||||
|
if (speciesStartValue >= 1 && speciesStartValue <= 3) {
|
||||||
|
return EggTier.COMMON;
|
||||||
|
}
|
||||||
|
if (speciesStartValue >= 4 && speciesStartValue <= 5) {
|
||||||
|
return EggTier.GREAT;
|
||||||
|
}
|
||||||
|
if (speciesStartValue >= 6 && speciesStartValue <= 7) {
|
||||||
|
return EggTier.ULTRA;
|
||||||
|
}
|
||||||
|
if (speciesStartValue >= 8) {
|
||||||
|
return EggTier.MASTER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// #endregion
|
||||||
|
////
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: integer): Species {
|
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
|
||||||
const legendarySpecies = Object.entries(speciesStarters)
|
const legendarySpecies = Object.entries(speciesStarters)
|
||||||
.filter(s => s[1] >= 8 && s[1] <= 9)
|
.filter(s => s[1] >= 8 && s[1] <= 9)
|
||||||
.map(s => parseInt(s[0]))
|
.map(s => parseInt(s[0]))
|
||||||
|
373
src/data/move.ts
@ -1,15 +1,16 @@
|
|||||||
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
||||||
import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
|
import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
|
||||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||||
import { EncoreTag } from "./battler-tags";
|
import { EncoreTag, SemiInvulnerableTag } from "./battler-tags";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
|
||||||
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
||||||
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect";
|
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
|
import { Constructor } from "#app/utils";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr } from "./ability";
|
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr, IgnoreMoveEffectsAbAttr, applyPreDefendAbAttrs, MoveEffectChanceMultiplierAbAttr } from "./ability";
|
||||||
import { allAbilities } from "./ability";
|
import { allAbilities } from "./ability";
|
||||||
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
|
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
@ -18,7 +19,8 @@ import { TerrainType } from "./terrain";
|
|||||||
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
|
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
|
||||||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||||
import { Command } from "../ui/command-ui-handler";
|
import { Command } from "../ui/command-ui-handler";
|
||||||
import i18next, { Localizable } from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
|
import { Localizable } from "#app/interfaces/locales";
|
||||||
import { getBerryEffectFunc } from "./berry";
|
import { getBerryEffectFunc } from "./berry";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
@ -156,7 +158,7 @@ export default class Move implements Localizable {
|
|||||||
* @param attrType any attribute that extends {@linkcode MoveAttr}
|
* @param attrType any attribute that extends {@linkcode MoveAttr}
|
||||||
* @returns Array of attributes that match `attrType`, Empty Array if none match.
|
* @returns Array of attributes that match `attrType`, Empty Array if none match.
|
||||||
*/
|
*/
|
||||||
getAttrs<T extends MoveAttr>(attrType: new(...args: any[]) => T): T[] {
|
getAttrs<T extends MoveAttr>(attrType: Constructor<T>): T[] {
|
||||||
return this.attrs.filter((a): a is T => a instanceof attrType);
|
return this.attrs.filter((a): a is T => a instanceof attrType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +167,7 @@ export default class Move implements Localizable {
|
|||||||
* @param attrType any attribute that extends {@linkcode MoveAttr}
|
* @param attrType any attribute that extends {@linkcode MoveAttr}
|
||||||
* @returns true if the move has attribute `attrType`
|
* @returns true if the move has attribute `attrType`
|
||||||
*/
|
*/
|
||||||
hasAttr<T extends MoveAttr>(attrType: new(...args: any[]) => T): boolean {
|
hasAttr<T extends MoveAttr>(attrType: Constructor<T>): boolean {
|
||||||
return this.attrs.some((attr) => attr instanceof attrType);
|
return this.attrs.some((attr) => attr instanceof attrType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +187,7 @@ export default class Move implements Localizable {
|
|||||||
* @param args the args needed to instantiate a the given class
|
* @param args the args needed to instantiate a the given class
|
||||||
* @returns the called object {@linkcode Move}
|
* @returns the called object {@linkcode Move}
|
||||||
*/
|
*/
|
||||||
attr<T extends new (...args: any[]) => MoveAttr>(AttrType: T, ...args: ConstructorParameters<T>): this {
|
attr<T extends Constructor<MoveAttr>>(AttrType: T, ...args: ConstructorParameters<T>): this {
|
||||||
const attr = new AttrType(...args);
|
const attr = new AttrType(...args);
|
||||||
this.attrs.push(attr);
|
this.attrs.push(attr);
|
||||||
let attrCondition = attr.getCondition();
|
let attrCondition = attr.getCondition();
|
||||||
@ -278,18 +280,29 @@ export default class Move implements Localizable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the move is immune to certain types
|
* Checks if the move is immune to certain types.
|
||||||
* currently only look at case of Grass types and powder moves
|
* Currently looks at cases of Grass types with powder moves and Dark types with moves affected by Prankster.
|
||||||
* @param type {@linkcode Type} enum
|
* @param {Pokemon} user the source of this move
|
||||||
|
* @param {Pokemon} target the target of this move
|
||||||
|
* @param {Type} type the type of the move's target
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
isTypeImmune(type: Type): boolean {
|
isTypeImmune(user: Pokemon, target: Pokemon, type: Type): boolean {
|
||||||
|
if (this.moveTarget === MoveTarget.USER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type.GRASS:
|
case Type.GRASS:
|
||||||
if (this.hasFlag(MoveFlags.POWDER_MOVE)) {
|
if (this.hasFlag(MoveFlags.POWDER_MOVE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Type.DARK:
|
||||||
|
if (user.hasAbility(Abilities.PRANKSTER) && this.category === MoveCategory.STATUS && (user.isPlayer() !== target.isPlayer())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -794,7 +807,7 @@ export enum MoveEffectTrigger {
|
|||||||
*/
|
*/
|
||||||
export class MoveEffectAttr extends MoveAttr {
|
export class MoveEffectAttr extends MoveAttr {
|
||||||
/** Defines when this effect should trigger in the move's effect order
|
/** Defines when this effect should trigger in the move's effect order
|
||||||
* @see {@linkcode MoveEffectPhase.start}
|
* @see {@linkcode phases.MoveEffectPhase.start}
|
||||||
*/
|
*/
|
||||||
public trigger: MoveEffectTrigger;
|
public trigger: MoveEffectTrigger;
|
||||||
/** Should this effect only apply on the first hit? */
|
/** Should this effect only apply on the first hit? */
|
||||||
@ -825,6 +838,22 @@ export class MoveEffectAttr extends MoveAttr {
|
|||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
||||||
return this.canApply(user, target, move, args);
|
return this.canApply(user, target, move, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the used move's additional effect chance.
|
||||||
|
* If user's ability has MoveEffectChanceMultiplierAbAttr or IgnoreMoveEffectsAbAttr modifies the base chance.
|
||||||
|
* @param user {@linkcode Pokemon} using this move
|
||||||
|
* @param target {@linkcode Pokemon} target of this move
|
||||||
|
* @param move {@linkcode Move} being used
|
||||||
|
* @param selfEffect {@linkcode Boolean} if move targets user.
|
||||||
|
* @returns Move chance value.
|
||||||
|
*/
|
||||||
|
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean): integer {
|
||||||
|
const moveChance = new Utils.NumberHolder(move.chance);
|
||||||
|
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect);
|
||||||
|
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr,target,user,null,null, moveChance);
|
||||||
|
return moveChance.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PreMoveMessageAttr extends MoveAttr {
|
export class PreMoveMessageAttr extends MoveAttr {
|
||||||
@ -1669,7 +1698,8 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const statusCheck = move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance;
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
|
const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance;
|
||||||
if (statusCheck) {
|
if (statusCheck) {
|
||||||
const pokemon = this.selfTarget ? user : target;
|
const pokemon = this.selfTarget ? user : target;
|
||||||
if (pokemon.status) {
|
if (pokemon.status) {
|
||||||
@ -1679,7 +1709,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0))
|
if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
|
||||||
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
|
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
|
||||||
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null,this.effect);
|
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null,this.effect);
|
||||||
return true;
|
return true;
|
||||||
@ -1689,7 +1719,8 @@ export class StatusEffectAttr 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(this.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0;
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
|
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1708,7 +1739,8 @@ export class MultiStatusEffectAttr extends StatusEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(this.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0;
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
|
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2311,7 +2343,8 @@ export class StatChangeAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) {
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
|
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
||||||
const levels = this.getLevels(user);
|
const levels = this.getLevels(user);
|
||||||
user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage));
|
user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage));
|
||||||
return true;
|
return true;
|
||||||
@ -3778,10 +3811,9 @@ export class NeutralDamageAgainstFlyingTypeMultiplierAttr extends VariableMoveTy
|
|||||||
if (!target.getTag(BattlerTagType.IGNORE_FLYING)) {
|
if (!target.getTag(BattlerTagType.IGNORE_FLYING)) {
|
||||||
const multiplier = args[0] as Utils.NumberHolder;
|
const multiplier = args[0] as Utils.NumberHolder;
|
||||||
//When a flying type is hit, the first hit is always 1x multiplier. Levitating pokemon are instantly affected by typing
|
//When a flying type is hit, the first hit is always 1x multiplier. Levitating pokemon are instantly affected by typing
|
||||||
if (target.isOfType(Type.FLYING)) {
|
if (target.isOfType(Type.FLYING) || target.hasAbility(Abilities.LEVITATE)) {
|
||||||
multiplier.value = 1;
|
multiplier.value = 1;
|
||||||
}
|
}
|
||||||
target.addTag(BattlerTagType.IGNORE_FLYING, 20, move.id, user.id); //TODO: Grounded effect should not have turn limit
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4036,18 +4068,14 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chance = this.getTagChance(user, target, move);
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
if (chance < 0 || chance === 100 || user.randSeedInt(100) < chance) {
|
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
||||||
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
|
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTagChance(user: Pokemon, target: Pokemon, move: Move): integer {
|
|
||||||
return move.chance;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return this.failOnOverlap
|
return this.failOnOverlap
|
||||||
? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType)
|
? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType)
|
||||||
@ -4084,6 +4112,8 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
return -3;
|
return -3;
|
||||||
case BattlerTagType.ENCORE:
|
case BattlerTagType.ENCORE:
|
||||||
return -2;
|
return -2;
|
||||||
|
case BattlerTagType.MINIMIZED:
|
||||||
|
return 0;
|
||||||
case BattlerTagType.INGRAIN:
|
case BattlerTagType.INGRAIN:
|
||||||
case BattlerTagType.IGNORE_ACCURACY:
|
case BattlerTagType.IGNORE_ACCURACY:
|
||||||
case BattlerTagType.AQUA_RING:
|
case BattlerTagType.AQUA_RING:
|
||||||
@ -4097,11 +4127,11 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||||
let chance = this.getTagChance(user, target, move);
|
let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
if (chance < 0) {
|
if (moveChance < 0) {
|
||||||
chance = 100;
|
moveChance = 100;
|
||||||
}
|
}
|
||||||
return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (chance / 100));
|
return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (moveChance / 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4110,12 +4140,18 @@ export class CurseAttr extends MoveEffectAttr {
|
|||||||
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
|
||||||
if (user.getTypes(true).includes(Type.GHOST)) {
|
if (user.getTypes(true).includes(Type.GHOST)) {
|
||||||
if (target.getTag(BattlerTagType.CURSED)) {
|
if (target.getTag(BattlerTagType.CURSED)) {
|
||||||
user.scene.queueMessage("But it failed!");
|
user.scene.queueMessage(i18next.t("battle:attackFailed"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
|
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
|
||||||
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
|
||||||
user.scene.queueMessage(getPokemonMessage(user, ` cut its own HP\nand laid a curse on the ${target.name}!`));
|
user.scene.queueMessage(
|
||||||
|
i18next.t("battle:battlerTagsCursedOnAdd", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(user),
|
||||||
|
pokemonName: target.name
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
|
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -4366,15 +4402,42 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr {
|
|||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => {
|
return (user, target, move) => {
|
||||||
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
if (move.category !== MoveCategory.STATUS || !user.scene.arena.getTagOnSide(this.tagType, side)) {
|
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
|
||||||
|
if (!tag) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
|
|
||||||
return tag.layers < tag.maxLayers;
|
return tag.layers < tag.maxLayers;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used for Stone Axe and Ceaseless Edge.
|
||||||
|
* Applies the given ArenaTrapTag when move is used.
|
||||||
|
* @extends AddArenaTagAttr
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class AddArenaTrapTagHitAttr extends AddArenaTagAttr {
|
||||||
|
/**
|
||||||
|
* @param user {@linkcode Pokemon} using this move
|
||||||
|
* @param target {@linkcode Pokemon} target of this move
|
||||||
|
* @param move {@linkcode Move} being used
|
||||||
|
*/
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
|
||||||
|
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
|
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
|
||||||
|
if ((moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance)) {
|
||||||
|
user.scene.arena.addTag(this.tagType, 0, move.id, user.id, side);
|
||||||
|
if (!tag) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return tag.layers < tag.maxLayers;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class RemoveArenaTrapAttr extends MoveEffectAttr {
|
export class RemoveArenaTrapAttr extends MoveEffectAttr {
|
||||||
|
|
||||||
private targetBothSides: boolean;
|
private targetBothSides: boolean;
|
||||||
@ -4534,7 +4597,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
resolve(true);
|
resolve(true);
|
||||||
} else {
|
} else {
|
||||||
user.scene.queueMessage("But it failed!");
|
user.scene.queueMessage(i18next.t("battle:attackFailed"));
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -4700,7 +4763,7 @@ export class RemoveTypeAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
export class CopyTypeAttr extends MoveEffectAttr {
|
export class CopyTypeAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true);
|
super(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -5066,14 +5129,36 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used for moves that reduce PP of the target's last used move.
|
||||||
|
* Used for Spite.
|
||||||
|
*/
|
||||||
export class ReducePpMoveAttr extends MoveEffectAttr {
|
export class ReducePpMoveAttr extends MoveEffectAttr {
|
||||||
|
protected reduction: number;
|
||||||
|
constructor(reduction: number) {
|
||||||
|
super();
|
||||||
|
this.reduction = reduction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the PP of the target's last-used move by an amount based on this attribute instance's {@linkcode reduction}.
|
||||||
|
*
|
||||||
|
* @param user {@linkcode Pokemon} that used the attack
|
||||||
|
* @param target {@linkcode Pokemon} targeted by the attack
|
||||||
|
* @param move {@linkcode Move} being used
|
||||||
|
* @param args N/A
|
||||||
|
* @returns {boolean} true
|
||||||
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
// Null checks can be skipped due to condition function
|
// Null checks can be skipped due to condition function
|
||||||
const lastMove = target.getLastXMoves().find(() => true);
|
const lastMove = target.getLastXMoves().find(() => true);
|
||||||
const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move);
|
const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move);
|
||||||
const lastPpUsed = movesetMove.ppUsed;
|
const lastPpUsed = movesetMove.ppUsed;
|
||||||
movesetMove.ppUsed = Math.min(movesetMove.ppUsed + 4, movesetMove.getMovePp());
|
movesetMove.ppUsed = Math.min(movesetMove.ppUsed + this.reduction, movesetMove.getMovePp());
|
||||||
user.scene.queueMessage(`It reduced the PP of ${getPokemonMessage(target, `'s\n${movesetMove.getName()} by ${movesetMove.ppUsed - lastPpUsed}!`)}`);
|
|
||||||
|
const message = i18next.t("battle:ppReduced", {targetName: target.name, moveName: movesetMove.getName(), reduction: movesetMove.ppUsed - lastPpUsed});
|
||||||
|
|
||||||
|
user.scene.queueMessage(message);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -5108,6 +5193,42 @@ export class ReducePpMoveAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used for moves that damage target, and then reduce PP of the target's last used move.
|
||||||
|
* Used for Eerie Spell.
|
||||||
|
*/
|
||||||
|
export class AttackReducePpMoveAttr extends ReducePpMoveAttr {
|
||||||
|
constructor(reduction: number) {
|
||||||
|
super(reduction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the target has used a move prior to the attack. PP-reduction is applied through the super class if so.
|
||||||
|
*
|
||||||
|
* @param user {@linkcode Pokemon} that used the attack
|
||||||
|
* @param target {@linkcode Pokemon} targeted by the attack
|
||||||
|
* @param move {@linkcode Move} being used
|
||||||
|
* @param args N/A
|
||||||
|
* @returns {boolean} true
|
||||||
|
*/
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const lastMove = target.getLastXMoves().find(() => true);
|
||||||
|
if (lastMove) {
|
||||||
|
const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move);
|
||||||
|
if (Boolean(movesetMove?.getPpRatio())) {
|
||||||
|
super.apply(user, target, move, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override condition function to always perform damage. Instead, perform pp-reduction condition check in apply function above
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
|
return (user, target, move) => true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Review this
|
// TODO: Review this
|
||||||
const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
|
const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
|
||||||
const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
|
const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
|
||||||
@ -5319,7 +5440,16 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used for moves that suppress abilities like {@linkcode Moves.GASTRO_ACID}.
|
||||||
|
* A suppressed ability cannot be activated.
|
||||||
|
*
|
||||||
|
* @extends MoveEffectAttr
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
* @see {@linkcode getCondition}
|
||||||
|
*/
|
||||||
export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
||||||
|
/** Sets ability suppression for the target pokemon and displays a message. */
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!super.apply(user, target, move, args)) {
|
if (!super.apply(user, target, move, args)) {
|
||||||
return false;
|
return false;
|
||||||
@ -5332,8 +5462,9 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Causes the effect to fail when the target's ability is unsupressable or already suppressed. */
|
||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr);
|
return (user, target, move) => !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !target.summonData.abilitySuppressed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5348,7 +5479,7 @@ export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr {
|
|||||||
* abillity cannot be suppressed. This is a secondary effect and has no bearing on the success or failure of the move.
|
* abillity cannot be suppressed. This is a secondary effect and has no bearing on the success or failure of the move.
|
||||||
*
|
*
|
||||||
* @returns True if the move occurred, otherwise false. Note that true will be returned even if the target has not
|
* @returns True if the move occurred, otherwise false. Note that true will be returned even if the target has not
|
||||||
* yet moved or if the target's abiilty is un-suppressable.
|
* yet moved or if the suppression failed to apply.
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!super.apply(user, target, move, args)) {
|
if (!super.apply(user, target, move, args)) {
|
||||||
@ -5537,7 +5668,7 @@ function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon, targe
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyMoveAttrs(attrType: { new(...args: any[]): MoveAttr }, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
export function applyMoveAttrs(attrType: Constructor<MoveAttr>, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
||||||
return applyMoveAttrsInternal((attr: MoveAttr) => attr instanceof attrType, user, target, move, args);
|
return applyMoveAttrsInternal((attr: MoveAttr) => attr instanceof attrType, user, target, move, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5703,7 +5834,7 @@ export function initMoves() {
|
|||||||
.attr(ChargeAttr, ChargeAnim.FLY_CHARGING, "flew\nup high!", BattlerTagType.FLYING)
|
.attr(ChargeAttr, ChargeAnim.FLY_CHARGING, "flew\nup high!", BattlerTagType.FLYING)
|
||||||
.condition(failOnGravityCondition)
|
.condition(failOnGravityCondition)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new AttackMove(Moves.BIND, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, 100, 0, 1)
|
new AttackMove(Moves.BIND, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, 0, 1)
|
||||||
.attr(TrapAttr, BattlerTagType.BIND),
|
.attr(TrapAttr, BattlerTagType.BIND),
|
||||||
new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1),
|
new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1),
|
||||||
new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1),
|
new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1),
|
||||||
@ -5736,7 +5867,7 @@ export function initMoves() {
|
|||||||
.attr(MinimizeAccuracyAttr)
|
.attr(MinimizeAccuracyAttr)
|
||||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
||||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
||||||
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, 100, 0, 1)
|
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1)
|
||||||
.attr(TrapAttr, BattlerTagType.WRAP),
|
.attr(TrapAttr, BattlerTagType.WRAP),
|
||||||
new AttackMove(Moves.TAKE_DOWN, Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, 0, 1)
|
new AttackMove(Moves.TAKE_DOWN, Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, 0, 1)
|
||||||
.attr(RecoilAttr)
|
.attr(RecoilAttr)
|
||||||
@ -5761,7 +5892,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.PIN_MISSILE, Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, 0, 1)
|
new AttackMove(Moves.PIN_MISSILE, Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, 0, 1)
|
||||||
.attr(MultiHitAttr)
|
.attr(MultiHitAttr)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new StatusMove(Moves.LEER, Type.NORMAL, 100, 30, 100, 0, 1)
|
new StatusMove(Moves.LEER, Type.NORMAL, 100, 30, -1, 0, 1)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1)
|
.attr(StatChangeAttr, BattleStat.DEF, -1)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.BITE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 30, 0, 1)
|
new AttackMove(Moves.BITE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 30, 0, 1)
|
||||||
@ -5870,7 +6001,7 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.DRAGON_RAGE, Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 1)
|
new AttackMove(Moves.DRAGON_RAGE, Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 1)
|
||||||
.attr(FixedDamageAttr, 40),
|
.attr(FixedDamageAttr, 40),
|
||||||
new AttackMove(Moves.FIRE_SPIN, Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, 100, 0, 1)
|
new AttackMove(Moves.FIRE_SPIN, Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 1)
|
||||||
.attr(TrapAttr, BattlerTagType.FIRE_SPIN),
|
.attr(TrapAttr, BattlerTagType.FIRE_SPIN),
|
||||||
new AttackMove(Moves.THUNDER_SHOCK, Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1)
|
new AttackMove(Moves.THUNDER_SHOCK, Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1)
|
||||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
||||||
@ -5986,11 +6117,11 @@ export function initMoves() {
|
|||||||
.attr(StatusEffectAttr, StatusEffect.BURN),
|
.attr(StatusEffectAttr, StatusEffect.BURN),
|
||||||
new AttackMove(Moves.WATERFALL, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 20, 0, 1)
|
new AttackMove(Moves.WATERFALL, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 20, 0, 1)
|
||||||
.attr(FlinchAttr),
|
.attr(FlinchAttr),
|
||||||
new AttackMove(Moves.CLAMP, Type.WATER, MoveCategory.PHYSICAL, 35, 85, 15, 100, 0, 1)
|
new AttackMove(Moves.CLAMP, Type.WATER, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 1)
|
||||||
.attr(TrapAttr, BattlerTagType.CLAMP),
|
.attr(TrapAttr, BattlerTagType.CLAMP),
|
||||||
new AttackMove(Moves.SWIFT, Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, -1, 0, 1)
|
new AttackMove(Moves.SWIFT, Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, -1, 0, 1)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.SKULL_BASH, Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, 100, 0, 1)
|
new AttackMove(Moves.SKULL_BASH, Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, -1, 0, 1)
|
||||||
.attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, "lowered\nits head!", null, true)
|
.attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, "lowered\nits head!", null, true)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, 1, true)
|
.attr(StatChangeAttr, BattleStat.DEF, 1, true)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
@ -6139,7 +6270,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
|
new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
|
||||||
.attr(LowHpPowerAttr),
|
.attr(LowHpPowerAttr),
|
||||||
new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2)
|
new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2)
|
||||||
.attr(ReducePpMoveAttr),
|
.attr(ReducePpMoveAttr, 4),
|
||||||
new AttackMove(Moves.POWDER_SNOW, Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, 10, 0, 2)
|
new AttackMove(Moves.POWDER_SNOW, Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, 10, 0, 2)
|
||||||
.attr(StatusEffectAttr, StatusEffect.FREEZE)
|
.attr(StatusEffectAttr, StatusEffect.FREEZE)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
@ -6339,7 +6470,7 @@ export function initMoves() {
|
|||||||
.attr(DelayedAttackAttr, ArenaTagType.FUTURE_SIGHT, ChargeAnim.FUTURE_SIGHT_CHARGING, "foresaw\nan attack!"),
|
.attr(DelayedAttackAttr, ArenaTagType.FUTURE_SIGHT, ChargeAnim.FUTURE_SIGHT_CHARGING, "foresaw\nan attack!"),
|
||||||
new AttackMove(Moves.ROCK_SMASH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, 50, 0, 2)
|
new AttackMove(Moves.ROCK_SMASH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, 50, 0, 2)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1),
|
.attr(StatChangeAttr, BattleStat.DEF, -1),
|
||||||
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, 100, 0, 2)
|
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2)
|
||||||
.attr(TrapAttr, BattlerTagType.WHIRLPOOL)
|
.attr(TrapAttr, BattlerTagType.WHIRLPOOL)
|
||||||
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
|
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
|
||||||
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
|
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
|
||||||
@ -6391,7 +6522,7 @@ export function initMoves() {
|
|||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS),
|
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS),
|
||||||
new SelfStatusMove(Moves.FOLLOW_ME, Type.NORMAL, -1, 20, -1, 2, 3)
|
new SelfStatusMove(Moves.FOLLOW_ME, Type.NORMAL, -1, 20, -1, 2, 3)
|
||||||
.unimplemented(),
|
.attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, true),
|
||||||
new StatusMove(Moves.NATURE_POWER, Type.NORMAL, -1, 20, -1, 0, 3)
|
new StatusMove(Moves.NATURE_POWER, Type.NORMAL, -1, 20, -1, 0, 3)
|
||||||
.attr(NaturePowerAttr)
|
.attr(NaturePowerAttr)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
@ -6415,7 +6546,7 @@ export function initMoves() {
|
|||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new SelfStatusMove(Moves.INGRAIN, Type.GRASS, -1, 20, -1, 0, 3)
|
new SelfStatusMove(Moves.INGRAIN, Type.GRASS, -1, 20, -1, 0, 3)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true),
|
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true),
|
||||||
new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 3)
|
new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 3)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
|
||||||
new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3)
|
new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
@ -6517,7 +6648,7 @@ export function initMoves() {
|
|||||||
.slicingMove()
|
.slicingMove()
|
||||||
.windMove()
|
.windMove()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 3)
|
new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 3)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2, true)
|
.attr(StatChangeAttr, BattleStat.SPATK, -2, true)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE),
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE),
|
||||||
new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3)
|
new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3)
|
||||||
@ -6550,7 +6681,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
|
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
|
||||||
.attr(HitsTagAttr, BattlerTagType.FLYING)
|
.attr(HitsTagAttr, BattlerTagType.FLYING)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, 100, 0, 3)
|
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3)
|
||||||
.attr(TrapAttr, BattlerTagType.SAND_TOMB)
|
.attr(TrapAttr, BattlerTagType.SAND_TOMB)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 20, 5, -1, 0, 3)
|
new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 20, 5, -1, 0, 3)
|
||||||
@ -6620,11 +6751,11 @@ export function initMoves() {
|
|||||||
.pulseMove(),
|
.pulseMove(),
|
||||||
new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3)
|
new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3)
|
||||||
.attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, "chose\nDoom Desire as its destiny!"),
|
.attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, "chose\nDoom Desire as its destiny!"),
|
||||||
new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, 100, 0, 3)
|
new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, -1, 0, 3)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
||||||
new SelfStatusMove(Moves.ROOST, Type.FLYING, -1, 5, -1, 0, 4)
|
new SelfStatusMove(Moves.ROOST, Type.FLYING, -1, 5, -1, 0, 4)
|
||||||
.attr(HealAttr, 0.5)
|
.attr(HealAttr, 0.5)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.GROUNDED, true, false, 1)
|
.attr(AddBattlerTagAttr, BattlerTagType.ROOSTED, true, false)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new StatusMove(Moves.GRAVITY, Type.PSYCHIC, -1, 5, -1, 0, 4)
|
new StatusMove(Moves.GRAVITY, Type.PSYCHIC, -1, 5, -1, 0, 4)
|
||||||
.attr(AddArenaTagAttr, ArenaTagType.GRAVITY, 5)
|
.attr(AddArenaTagAttr, ArenaTagType.GRAVITY, 5)
|
||||||
@ -6634,7 +6765,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4)
|
new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => targetSleptOrComatoseCondition(user, target, move) ? 2 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => targetSleptOrComatoseCondition(user, target, move) ? 2 : 1)
|
||||||
.attr(HealStatusEffectAttr, false, StatusEffect.SLEEP),
|
.attr(HealStatusEffectAttr, false, StatusEffect.SLEEP),
|
||||||
new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 4)
|
new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 4)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
|
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.GYRO_BALL, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
new AttackMove(Moves.GYRO_BALL, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
||||||
@ -6668,7 +6799,7 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ATTACKER),
|
.target(MoveTarget.ATTACKER),
|
||||||
new AttackMove(Moves.U_TURN, Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 4)
|
new AttackMove(Moves.U_TURN, Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 4)
|
||||||
.attr(ForceSwitchOutAttr, true, false),
|
.attr(ForceSwitchOutAttr, true, false),
|
||||||
new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 4)
|
new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 4)
|
||||||
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
|
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
|
||||||
new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4)
|
new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1),
|
||||||
@ -6712,9 +6843,9 @@ export function initMoves() {
|
|||||||
new SelfStatusMove(Moves.COPYCAT, Type.NORMAL, -1, 20, -1, 0, 4)
|
new SelfStatusMove(Moves.COPYCAT, Type.NORMAL, -1, 20, -1, 0, 4)
|
||||||
.attr(CopyMoveAttr)
|
.attr(CopyMoveAttr)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new StatusMove(Moves.POWER_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
new StatusMove(Moves.POWER_SWAP, Type.PSYCHIC, -1, 10, 100, 0, 4)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new StatusMove(Moves.GUARD_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
new StatusMove(Moves.GUARD_SWAP, Type.PSYCHIC, -1, 10, 100, 0, 4)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.PUNISHMENT, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
new AttackMove(Moves.PUNISHMENT, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
||||||
.makesContact(true)
|
.makesContact(true)
|
||||||
@ -6734,10 +6865,7 @@ export function initMoves() {
|
|||||||
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
|
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
|
||||||
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
|
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true)
|
.attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true)
|
||||||
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) &&
|
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && [BattlerTagType.MAGNET_RISEN, BattlerTagType.IGNORE_FLYING, BattlerTagType.INGRAIN].every((tag) => !user.getTag(tag))),
|
||||||
!user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) &&
|
|
||||||
!user.getTag(BattlerTagType.MAGNET_RISEN))
|
|
||||||
.unimplemented(),
|
|
||||||
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
|
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
|
||||||
.attr(RecoilAttr, false, 0.33)
|
.attr(RecoilAttr, false, 0.33)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||||
@ -6845,7 +6973,7 @@ export function initMoves() {
|
|||||||
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
|
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
|
||||||
.ignoresProtect()
|
.ignoresProtect()
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4)
|
new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
||||||
new AttackMove(Moves.DISCHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
|
new AttackMove(Moves.DISCHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
|
||||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
|
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
|
||||||
@ -6853,7 +6981,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.LAVA_PLUME, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
|
new AttackMove(Moves.LAVA_PLUME, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
|
||||||
.attr(StatusEffectAttr, StatusEffect.BURN)
|
.attr(StatusEffectAttr, StatusEffect.BURN)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4)
|
new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
||||||
new AttackMove(Moves.POWER_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 4),
|
new AttackMove(Moves.POWER_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 4),
|
||||||
new AttackMove(Moves.ROCK_WRECKER, Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, 0, 4)
|
new AttackMove(Moves.ROCK_WRECKER, Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, 0, 4)
|
||||||
@ -6923,7 +7051,7 @@ export function initMoves() {
|
|||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
||||||
.attr(OpponentHighHpPowerAttr),
|
.attr(OpponentHighHpPowerAttr),
|
||||||
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, 100, 0, 4)
|
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
|
||||||
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
|
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
|
||||||
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
|
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
|
||||||
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
||||||
@ -6959,7 +7087,7 @@ export function initMoves() {
|
|||||||
.partial(),
|
.partial(),
|
||||||
new SelfStatusMove(Moves.RAGE_POWDER, Type.BUG, -1, 20, -1, 2, 5)
|
new SelfStatusMove(Moves.RAGE_POWDER, Type.BUG, -1, 20, -1, 2, 5)
|
||||||
.powderMove()
|
.powderMove()
|
||||||
.unimplemented(),
|
.attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, true),
|
||||||
new StatusMove(Moves.TELEKINESIS, Type.PSYCHIC, -1, 15, -1, 0, 5)
|
new StatusMove(Moves.TELEKINESIS, Type.PSYCHIC, -1, 15, -1, 0, 5)
|
||||||
.condition(failOnGravityCondition)
|
.condition(failOnGravityCondition)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
@ -6968,9 +7096,9 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.BOTH_SIDES)
|
.target(MoveTarget.BOTH_SIDES)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5)
|
new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5)
|
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING])
|
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
|
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
|
||||||
@ -7183,7 +7311,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.ICICLE_CRASH, Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, 30, 0, 5)
|
new AttackMove(Moves.ICICLE_CRASH, Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, 30, 0, 5)
|
||||||
.attr(FlinchAttr)
|
.attr(FlinchAttr)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, 100, 0, 5)
|
new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, -1, 0, 5)
|
||||||
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true),
|
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true),
|
||||||
new AttackMove(Moves.FUSION_FLARE, Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 5)
|
new AttackMove(Moves.FUSION_FLARE, Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 5)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||||
@ -7202,7 +7330,7 @@ export function initMoves() {
|
|||||||
.condition(new FirstMoveCondition()),
|
.condition(new FirstMoveCondition()),
|
||||||
new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6)
|
new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6)
|
||||||
.condition((user, target, move) => user.battleData.berriesEaten.length > 0),
|
.condition((user, target, move) => user.battleData.berriesEaten.length > 0),
|
||||||
new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, 100, 0, 6)
|
new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, -1, 0, 6)
|
||||||
.target(MoveTarget.ALL)
|
.target(MoveTarget.ALL)
|
||||||
.condition((user,target,move) => {
|
.condition((user,target,move) => {
|
||||||
// If any fielded pokémon is grass-type and grounded.
|
// If any fielded pokémon is grass-type and grounded.
|
||||||
@ -7221,7 +7349,7 @@ export function initMoves() {
|
|||||||
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)
|
||||||
.partial(),
|
.partial(),
|
||||||
new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, 100, 0, 6)
|
new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6)
|
new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6)
|
||||||
@ -7244,7 +7372,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
|
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new StatusMove(Moves.PARTING_SHOT, Type.DARK, 100, 20, 100, 0, 6)
|
new StatusMove(Moves.PARTING_SHOT, Type.DARK, 100, 20, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, false, null, true, true, MoveEffectTrigger.PRE_APPLY)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, false, null, true, true, MoveEffectTrigger.PRE_APPLY)
|
||||||
.attr(ForceSwitchOutAttr, true, false)
|
.attr(ForceSwitchOutAttr, true, false)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
@ -7257,9 +7385,9 @@ export function initMoves() {
|
|||||||
new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6)
|
new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6)
|
||||||
.target(MoveTarget.USER_SIDE)
|
.target(MoveTarget.USER_SIDE)
|
||||||
.attr(AddArenaTagAttr, ArenaTagType.CRAFTY_SHIELD, 1, true, true),
|
.attr(AddArenaTagAttr, ArenaTagType.CRAFTY_SHIELD, 1, true, true),
|
||||||
new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, 100, 0, 6)
|
new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, -1, 0, 6)
|
||||||
.target(MoveTarget.ALL)
|
.target(MoveTarget.ALL)
|
||||||
.unimplemented(),
|
.attr(StatChangeAttr, BattleStat.DEF, 1, false, (user, target, move) => target.getTypes().includes(Type.GRASS) && !target.getTag(SemiInvulnerableTag)),
|
||||||
new StatusMove(Moves.GRASSY_TERRAIN, Type.GRASS, -1, 10, -1, 0, 6)
|
new StatusMove(Moves.GRASSY_TERRAIN, Type.GRASS, -1, 10, -1, 0, 6)
|
||||||
.attr(TerrainChangeAttr, TerrainType.GRASSY)
|
.attr(TerrainChangeAttr, TerrainType.GRASSY)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
@ -7282,9 +7410,9 @@ export function initMoves() {
|
|||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new SelfStatusMove(Moves.KINGS_SHIELD, Type.STEEL, -1, 10, -1, 4, 6)
|
new SelfStatusMove(Moves.KINGS_SHIELD, Type.STEEL, -1, 10, -1, 4, 6)
|
||||||
.attr(ProtectAttr, BattlerTagType.KINGS_SHIELD),
|
.attr(ProtectAttr, BattlerTagType.KINGS_SHIELD),
|
||||||
new StatusMove(Moves.PLAY_NICE, Type.NORMAL, -1, 20, 100, 0, 6)
|
new StatusMove(Moves.PLAY_NICE, Type.NORMAL, -1, 20, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
||||||
new StatusMove(Moves.CONFIDE, Type.NORMAL, -1, 20, 100, 0, 6)
|
new StatusMove(Moves.CONFIDE, Type.NORMAL, -1, 20, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -1)
|
.attr(StatChangeAttr, BattleStat.SPATK, -1)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6)
|
new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6)
|
||||||
@ -7310,7 +7438,7 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.NEAR_ALLY),
|
.target(MoveTarget.NEAR_ALLY),
|
||||||
new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6)
|
new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2),
|
.attr(StatChangeAttr, BattleStat.SPATK, -2),
|
||||||
new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, 100, 0, 6)
|
new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6)
|
new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6)
|
||||||
@ -7325,8 +7453,8 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.USER_AND_ALLIES)
|
.target(MoveTarget.USER_AND_ALLIES)
|
||||||
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))),
|
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))),
|
||||||
new StatusMove(Moves.HAPPY_HOUR, Type.NORMAL, -1, 30, -1, 0, 6) // No animation
|
new StatusMove(Moves.HAPPY_HOUR, Type.NORMAL, -1, 30, -1, 0, 6) // No animation
|
||||||
.target(MoveTarget.USER_SIDE)
|
.attr(AddArenaTagAttr, ArenaTagType.HAPPY_HOUR, null, true)
|
||||||
.unimplemented(),
|
.target(MoveTarget.USER_SIDE),
|
||||||
new StatusMove(Moves.ELECTRIC_TERRAIN, Type.ELECTRIC, -1, 10, -1, 0, 6)
|
new StatusMove(Moves.ELECTRIC_TERRAIN, Type.ELECTRIC, -1, 10, -1, 0, 6)
|
||||||
.attr(TerrainChangeAttr, TerrainType.ELECTRIC)
|
.attr(TerrainChangeAttr, TerrainType.ELECTRIC)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
@ -7341,7 +7469,7 @@ export function initMoves() {
|
|||||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
||||||
new AttackMove(Moves.HOLD_BACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 6)
|
new AttackMove(Moves.HOLD_BACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 6)
|
||||||
.attr(SurviveDamageAttr),
|
.attr(SurviveDamageAttr),
|
||||||
new AttackMove(Moves.INFESTATION, Type.BUG, MoveCategory.SPECIAL, 20, 100, 20, 100, 0, 6)
|
new AttackMove(Moves.INFESTATION, Type.BUG, MoveCategory.SPECIAL, 20, 100, 20, -1, 0, 6)
|
||||||
.makesContact()
|
.makesContact()
|
||||||
.attr(TrapAttr, BattlerTagType.INFESTATION),
|
.attr(TrapAttr, BattlerTagType.INFESTATION),
|
||||||
new AttackMove(Moves.POWER_UP_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 20, 100, 0, 6)
|
new AttackMove(Moves.POWER_UP_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 20, 100, 0, 6)
|
||||||
@ -7350,11 +7478,12 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.OBLIVION_WING, Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
|
new AttackMove(Moves.OBLIVION_WING, Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
|
||||||
.attr(HitHealAttr, 0.75)
|
.attr(HitHealAttr, 0.75)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, 100, 0, 6)
|
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
||||||
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
||||||
|
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false)
|
||||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING])
|
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
||||||
@ -7373,9 +7502,9 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.PRECIPICE_BLADES, Type.GROUND, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 6)
|
new AttackMove(Moves.PRECIPICE_BLADES, Type.GROUND, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 6)
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 6)
|
new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
|
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
|
||||||
new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, 100, 0, 6)
|
new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, -1, 0, 6)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.ignoresProtect(),
|
.ignoresProtect(),
|
||||||
@ -7499,23 +7628,23 @@ export function initMoves() {
|
|||||||
.condition(new FirstMoveCondition()),
|
.condition(new FirstMoveCondition()),
|
||||||
new SelfStatusMove(Moves.BANEFUL_BUNKER, Type.POISON, -1, 10, -1, 4, 7)
|
new SelfStatusMove(Moves.BANEFUL_BUNKER, Type.POISON, -1, 10, -1, 4, 7)
|
||||||
.attr(ProtectAttr, BattlerTagType.BANEFUL_BUNKER),
|
.attr(ProtectAttr, BattlerTagType.BANEFUL_BUNKER),
|
||||||
new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 7)
|
new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 7)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.DARKEST_LARIAT, Type.DARK, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
|
new AttackMove(Moves.DARKEST_LARIAT, Type.DARK, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
|
||||||
.attr(IgnoreOpponentStatChangesAttr),
|
.attr(IgnoreOpponentStatChangesAttr),
|
||||||
new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, -1, 0, 7)
|
new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, 100, 0, 7)
|
||||||
.attr(HealStatusEffectAttr, false, StatusEffect.BURN)
|
.attr(HealStatusEffectAttr, false, StatusEffect.BURN)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7)
|
new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
|
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7)
|
new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7)
|
||||||
.attr(BoostHealAttr, 0.5, 2/3, true, false, (user, target, move) => user.scene.arena.terrain?.terrainType === TerrainType.GRASSY)
|
.attr(BoostHealAttr, 0.5, 2/3, true, false, (user, target, move) => user.scene.arena.terrain?.terrainType === TerrainType.GRASSY)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7),
|
new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7),
|
||||||
new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, 100, 0, 7)
|
new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, -1, 0, 7)
|
||||||
.attr(HitHealAttr, null, Stat.ATK)
|
.attr(HitHealAttr, null, Stat.ATK)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
||||||
.condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6)
|
.condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6)
|
||||||
@ -7527,8 +7656,8 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7)
|
new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7)
|
new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7)
|
||||||
.unimplemented(),
|
.attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, false),
|
||||||
new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, 100, 0, 7)
|
new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, -1, 0, 7)
|
||||||
.attr(StatusEffectAttr, StatusEffect.POISON)
|
.attr(StatusEffectAttr, StatusEffect.POISON)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
||||||
new SelfStatusMove(Moves.LASER_FOCUS, Type.NORMAL, -1, 30, -1, 0, 7)
|
new SelfStatusMove(Moves.LASER_FOCUS, Type.NORMAL, -1, 30, -1, 0, 7)
|
||||||
@ -7543,7 +7672,7 @@ export function initMoves() {
|
|||||||
.attr(StatusCategoryOnAllyAttr)
|
.attr(StatusCategoryOnAllyAttr)
|
||||||
.attr(HealOnAllyAttr, 0.5, true, false)
|
.attr(HealOnAllyAttr, 0.5, true, false)
|
||||||
.ballBombMove(),
|
.ballBombMove(),
|
||||||
new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, -1, 0, 7)
|
new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
|
||||||
new StatusMove(Moves.PSYCHIC_TERRAIN, Type.PSYCHIC, -1, 10, -1, 0, 7)
|
new StatusMove(Moves.PSYCHIC_TERRAIN, Type.PSYCHIC, -1, 10, -1, 0, 7)
|
||||||
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
|
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
|
||||||
@ -7587,7 +7716,7 @@ export function initMoves() {
|
|||||||
.ballBombMove()
|
.ballBombMove()
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.partial(),
|
.partial(),
|
||||||
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, 100, 0, 7)
|
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, -1, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
@ -7621,17 +7750,17 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.PULVERIZING_PANCAKE, Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, -1, 0, 7)
|
new AttackMove(Moves.PULVERIZING_PANCAKE, Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, -1, 0, 7)
|
||||||
.partial()
|
.partial()
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new SelfStatusMove(Moves.EXTREME_EVOBOOST, Type.NORMAL, -1, 1, 100, 0, 7)
|
new SelfStatusMove(Moves.EXTREME_EVOBOOST, Type.NORMAL, -1, 1, -1, 0, 7)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, -1, 0, 7)
|
new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, 100, 0, 7)
|
||||||
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
|
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
/* End Unused */
|
/* End Unused */
|
||||||
new AttackMove(Moves.SHELL_TRAP, Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, -3, 7)
|
new AttackMove(Moves.SHELL_TRAP, Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, -3, 7)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||||
.partial(),
|
.partial(),
|
||||||
new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 7)
|
new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
|
||||||
new AttackMove(Moves.PSYCHIC_FANGS, Type.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
|
new AttackMove(Moves.PSYCHIC_FANGS, Type.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
|
||||||
.bitingMove()
|
.bitingMove()
|
||||||
@ -7654,7 +7783,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||||
.ignoresAbilities()
|
.ignoresAbilities()
|
||||||
.partial(),
|
.partial(),
|
||||||
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7)
|
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, -1, 0, 7)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1),
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1),
|
||||||
new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7)
|
new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7)
|
||||||
.attr(FlinchAttr),
|
.attr(FlinchAttr),
|
||||||
@ -7753,7 +7882,7 @@ export function initMoves() {
|
|||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1)
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1)
|
||||||
.bitingMove(),
|
.bitingMove(),
|
||||||
new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, 100, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
|
new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, -1, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
|
||||||
.attr(EatBerryAttr)
|
.attr(EatBerryAttr)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, 2, true)
|
.attr(StatChangeAttr, BattleStat.DEF, 2, true)
|
||||||
.condition((user) => {
|
.condition((user) => {
|
||||||
@ -7761,10 +7890,10 @@ export function initMoves() {
|
|||||||
return userBerries.length > 0;
|
return userBerries.length > 0;
|
||||||
})
|
})
|
||||||
.partial(),
|
.partial(),
|
||||||
new SelfStatusMove(Moves.NO_RETREAT, Type.FIGHTING, -1, 5, 100, 0, 8)
|
new SelfStatusMove(Moves.NO_RETREAT, Type.FIGHTING, -1, 5, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1),
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1),
|
||||||
new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, 100, 0, 8)
|
new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
||||||
.partial(),
|
.partial(),
|
||||||
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
|
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
|
||||||
@ -7860,18 +7989,18 @@ export function initMoves() {
|
|||||||
.unimplemented()
|
.unimplemented()
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
/* End Unused */
|
/* End Unused */
|
||||||
new SelfStatusMove(Moves.CLANGOROUS_SOUL, Type.DRAGON, 100, 5, 100, 0, 8)
|
new SelfStatusMove(Moves.CLANGOROUS_SOUL, Type.DRAGON, 100, 5, -1, 0, 8)
|
||||||
.attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, 3)
|
.attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, 3)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.danceMove(),
|
.danceMove(),
|
||||||
new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
|
new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
|
||||||
.attr(DefAtkAttr),
|
.attr(DefAtkAttr),
|
||||||
new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, 100, 0, 8)
|
new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2),
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2),
|
||||||
new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8)
|
new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.SNAP_TRAP, Type.GRASS, MoveCategory.PHYSICAL, 35, 100, 15, 100, 0, 8)
|
new AttackMove(Moves.SNAP_TRAP, Type.GRASS, MoveCategory.PHYSICAL, 35, 100, 15, -1, 0, 8)
|
||||||
.attr(TrapAttr, BattlerTagType.SNAP_TRAP),
|
.attr(TrapAttr, BattlerTagType.SNAP_TRAP),
|
||||||
new AttackMove(Moves.PYRO_BALL, Type.FIRE, MoveCategory.PHYSICAL, 120, 90, 5, 10, 0, 8)
|
new AttackMove(Moves.PYRO_BALL, Type.FIRE, MoveCategory.PHYSICAL, 120, 90, 5, 10, 0, 8)
|
||||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||||
@ -7923,7 +8052,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
||||||
.attr(ClearTerrainAttr)
|
.attr(ClearTerrainAttr)
|
||||||
.condition((user, target, move) => !!user.scene.arena.terrain),
|
.condition((user, target, move) => !!user.scene.arena.terrain),
|
||||||
new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, 100, 0, 8)
|
new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, -1, 0, 8)
|
||||||
//.attr(StatChangeAttr, BattleStat.SPD, 1, true) // TODO: Have boosts only apply at end of move, not after every hit
|
//.attr(StatChangeAttr, BattleStat.SPD, 1, true) // TODO: Have boosts only apply at end of move, not after every hit
|
||||||
//.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
//.attr(StatChangeAttr, BattleStat.DEF, -1, true)
|
||||||
.attr(MultiHitAttr)
|
.attr(MultiHitAttr)
|
||||||
@ -7964,7 +8093,7 @@ export function initMoves() {
|
|||||||
new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8)
|
new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS)
|
.target(MoveTarget.ALL_NEAR_OTHERS)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, 100, 0, 8)
|
new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1)
|
||||||
.target(MoveTarget.NEAR_ALLY),
|
.target(MoveTarget.NEAR_ALLY),
|
||||||
new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
|
new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
|
||||||
@ -7990,7 +8119,7 @@ export function initMoves() {
|
|||||||
.attr(MultiHitAttr, MultiHitType._3)
|
.attr(MultiHitAttr, MultiHitType._3)
|
||||||
.attr(CritOnlyAttr)
|
.attr(CritOnlyAttr)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.THUNDER_CAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 90, 15, 100, 0, 8)
|
new AttackMove(Moves.THUNDER_CAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 90, 15, -1, 0, 8)
|
||||||
.attr(TrapAttr, BattlerTagType.THUNDER_CAGE),
|
.attr(TrapAttr, BattlerTagType.THUNDER_CAGE),
|
||||||
new AttackMove(Moves.DRAGON_ENERGY, Type.DRAGON, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 8)
|
new AttackMove(Moves.DRAGON_ENERGY, Type.DRAGON, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 8)
|
||||||
.attr(HpPowerAttr)
|
.attr(HpPowerAttr)
|
||||||
@ -8008,16 +8137,16 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.ASTRAL_BARRAGE, Type.GHOST, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 8)
|
new AttackMove(Moves.ASTRAL_BARRAGE, Type.GHOST, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 8)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.EERIE_SPELL, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 5, 100, 0, 8)
|
new AttackMove(Moves.EERIE_SPELL, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 5, 100, 0, 8)
|
||||||
.soundBased()
|
.attr(AttackReducePpMoveAttr, 3)
|
||||||
.partial(),
|
.soundBased(),
|
||||||
new AttackMove(Moves.DIRE_CLAW, Type.POISON, MoveCategory.PHYSICAL, 80, 100, 15, 50, 0, 8)
|
new AttackMove(Moves.DIRE_CLAW, Type.POISON, MoveCategory.PHYSICAL, 80, 100, 15, 50, 0, 8)
|
||||||
.attr(MultiStatusEffectAttr, [StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP]),
|
.attr(MultiStatusEffectAttr, [StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP]),
|
||||||
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, 1, true),
|
.attr(StatChangeAttr, BattleStat.DEF, 1, true),
|
||||||
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, 100, 0, 8)
|
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
||||||
.attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK)
|
.attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
|
||||||
.slicingMove(),
|
.slicingMove(),
|
||||||
new AttackMove(Moves.SPRINGTIDE_STORM, Type.FAIRY, MoveCategory.SPECIAL, 100, 80, 5, 30, 0, 8)
|
new AttackMove(Moves.SPRINGTIDE_STORM, Type.FAIRY, MoveCategory.SPECIAL, 100, 80, 5, 30, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
||||||
@ -8035,11 +8164,12 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.CHLOROBLAST, Type.GRASS, MoveCategory.SPECIAL, 150, 95, 5, -1, 0, 8)
|
new AttackMove(Moves.CHLOROBLAST, Type.GRASS, MoveCategory.SPECIAL, 150, 95, 5, -1, 0, 8)
|
||||||
.attr(RecoilAttr, true, 0.5),
|
.attr(RecoilAttr, true, 0.5),
|
||||||
new AttackMove(Moves.MOUNTAIN_GALE, Type.ICE, MoveCategory.PHYSICAL, 100, 85, 10, 30, 0, 8)
|
new AttackMove(Moves.MOUNTAIN_GALE, Type.ICE, MoveCategory.PHYSICAL, 100, 85, 10, 30, 0, 8)
|
||||||
|
.makesContact(false)
|
||||||
.attr(FlinchAttr),
|
.attr(FlinchAttr),
|
||||||
new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, 100, 0, 8)
|
new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true)
|
||||||
.danceMove(),
|
.danceMove(),
|
||||||
new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 8)
|
new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 8)
|
||||||
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true)
|
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.BARB_BARRAGE, Type.POISON, MoveCategory.PHYSICAL, 60, 100, 10, 50, 0, 8)
|
new AttackMove(Moves.BARB_BARRAGE, Type.POISON, MoveCategory.PHYSICAL, 60, 100, 10, 50, 0, 8)
|
||||||
@ -8061,7 +8191,7 @@ export function initMoves() {
|
|||||||
.attr(StatusEffectAttr, StatusEffect.BURN)
|
.attr(StatusEffectAttr, StatusEffect.BURN)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status ? 2 : 1),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status ? 2 : 1),
|
||||||
new AttackMove(Moves.CEASELESS_EDGE, Type.DARK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
new AttackMove(Moves.CEASELESS_EDGE, Type.DARK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
||||||
.attr(AddArenaTrapTagAttr, ArenaTagType.SPIKES)
|
.attr(AddArenaTrapTagHitAttr, ArenaTagType.SPIKES)
|
||||||
.slicingMove(),
|
.slicingMove(),
|
||||||
new AttackMove(Moves.BLEAKWIND_STORM, Type.FLYING, MoveCategory.SPECIAL, 100, 80, 10, 30, 0, 8)
|
new AttackMove(Moves.BLEAKWIND_STORM, Type.FLYING, MoveCategory.SPECIAL, 100, 80, 10, 30, 0, 8)
|
||||||
.attr(ThunderAccuracyAttr)
|
.attr(ThunderAccuracyAttr)
|
||||||
@ -8202,15 +8332,15 @@ export function initMoves() {
|
|||||||
.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)
|
||||||
.attr(StatChangeAttr, BattleStat.SPDEF, -2),
|
.attr(StatChangeAttr, BattleStat.SPDEF, -2),
|
||||||
new AttackMove(Moves.ORDER_UP, Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 9)
|
new AttackMove(Moves.ORDER_UP, Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 9)
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.partial(),
|
.partial(),
|
||||||
new AttackMove(Moves.JET_PUNCH, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9)
|
new AttackMove(Moves.JET_PUNCH, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, 100, 0, 9)
|
new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, -1, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, 2)
|
.attr(StatChangeAttr, BattleStat.ATK, 2)
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -2),
|
.attr(StatChangeAttr, BattleStat.DEF, -2),
|
||||||
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9)
|
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -2, true),
|
.attr(StatChangeAttr, BattleStat.SPD, -2, true),
|
||||||
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
|
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
|
||||||
.attr(MultiHitAttr, MultiHitType._10)
|
.attr(MultiHitAttr, MultiHitType._10)
|
||||||
@ -8224,7 +8354,7 @@ export function initMoves() {
|
|||||||
.triageMove()
|
.triageMove()
|
||||||
.attr(RevivalBlessingAttr)
|
.attr(RevivalBlessingAttr)
|
||||||
.target(MoveTarget.USER),
|
.target(MoveTarget.USER),
|
||||||
new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, -1, 0, 9)
|
new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, 100, 0, 9)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED)
|
.attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.TRIPLE_DIVE, Type.WATER, MoveCategory.PHYSICAL, 30, 95, 10, -1, 0, 9)
|
new AttackMove(Moves.TRIPLE_DIVE, Type.WATER, MoveCategory.PHYSICAL, 30, 95, 10, -1, 0, 9)
|
||||||
@ -8287,7 +8417,7 @@ export function initMoves() {
|
|||||||
.attr(WeatherChangeAttr, WeatherType.SNOW)
|
.attr(WeatherChangeAttr, WeatherType.SNOW)
|
||||||
.attr(ForceSwitchOutAttr, true, false)
|
.attr(ForceSwitchOutAttr, true, false)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, 100, 0, 9)
|
new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, -1, 0, 9)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true, null, true, true)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true, null, true, true)
|
||||||
.attr(RemoveArenaTrapAttr)
|
.attr(RemoveArenaTrapAttr)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
@ -8298,7 +8428,7 @@ export function initMoves() {
|
|||||||
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
||||||
new AttackMove(Moves.TRAILBLAZE, Type.GRASS, MoveCategory.PHYSICAL, 50, 100, 20, 100, 0, 9)
|
new AttackMove(Moves.TRAILBLAZE, Type.GRASS, MoveCategory.PHYSICAL, 50, 100, 20, 100, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, 1, true),
|
.attr(StatChangeAttr, BattleStat.SPD, 1, true),
|
||||||
new AttackMove(Moves.CHILLING_WATER, Type.WATER, MoveCategory.SPECIAL, 50, 100, 20, -1, 0, 9)
|
new AttackMove(Moves.CHILLING_WATER, Type.WATER, MoveCategory.SPECIAL, 50, 100, 20, 100, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
||||||
new AttackMove(Moves.HYPER_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
|
new AttackMove(Moves.HYPER_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
|
||||||
.ignoresProtect(),
|
.ignoresProtect(),
|
||||||
@ -8360,8 +8490,7 @@ export function initMoves() {
|
|||||||
.attr(HealStatusEffectAttr, false, StatusEffect.FREEZE)
|
.attr(HealStatusEffectAttr, false, StatusEffect.FREEZE)
|
||||||
.attr(StatusEffectAttr, StatusEffect.BURN)
|
.attr(StatusEffectAttr, StatusEffect.BURN)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||||
.triageMove()
|
.triageMove(),
|
||||||
.partial(),
|
|
||||||
new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9)
|
new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1) //Temporary
|
.attr(StatChangeAttr, BattleStat.SPD, -1) //Temporary
|
||||||
.ballBombMove()
|
.ballBombMove()
|
||||||
@ -8379,7 +8508,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
|
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
|
||||||
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
|
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
|
||||||
.attr(DoublePowerChanceAttr),
|
.attr(DoublePowerChanceAttr),
|
||||||
new SelfStatusMove(Moves.BURNING_BULWARK, Type.FIRE, -1, 10, 100, 4, 9)
|
new SelfStatusMove(Moves.BURNING_BULWARK, Type.FIRE, -1, 10, -1, 4, 9)
|
||||||
.attr(ProtectAttr, BattlerTagType.BURNING_BULWARK),
|
.attr(ProtectAttr, BattlerTagType.BURNING_BULWARK),
|
||||||
new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9)
|
new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9)
|
||||||
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS),
|
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS),
|
||||||
@ -8391,7 +8520,7 @@ export function initMoves() {
|
|||||||
.slicingMove(),
|
.slicingMove(),
|
||||||
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
|
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
|
||||||
.attr(OpponentHighHpPowerAttr),
|
.attr(OpponentHighHpPowerAttr),
|
||||||
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, 100, 0, 9)
|
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
|
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
|
||||||
.target(MoveTarget.NEAR_ALLY)
|
.target(MoveTarget.NEAR_ALLY)
|
||||||
.partial(),
|
.partial(),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import i18next from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export enum PokeballType {
|
export enum PokeballType {
|
||||||
POKEBALL,
|
POKEBALL,
|
||||||
|
@ -3,6 +3,7 @@ import Pokemon from "../field/pokemon";
|
|||||||
import { SpeciesFormKey } from "./pokemon-species";
|
import { SpeciesFormKey } from "./pokemon-species";
|
||||||
import { StatusEffect } from "./status-effect";
|
import { StatusEffect } from "./status-effect";
|
||||||
import { MoveCategory, allMoves } from "./move";
|
import { MoveCategory, allMoves } from "./move";
|
||||||
|
import { Constructor } from "#app/utils";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -178,7 +179,7 @@ export class SpeciesFormChange {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
findTrigger(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): SpeciesFormChangeTrigger {
|
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger {
|
||||||
if (!this.trigger.hasTriggerType(triggerType)) {
|
if (!this.trigger.hasTriggerType(triggerType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -208,7 +209,7 @@ export abstract class SpeciesFormChangeTrigger {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
|
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
|
||||||
return this instanceof triggerType;
|
return this instanceof triggerType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +237,7 @@ export class SpeciesFormChangeCompoundTrigger {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
|
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
|
||||||
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
|
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ import { speciesEggMoves } from "./egg-moves";
|
|||||||
import { GameMode } from "../game-mode";
|
import { GameMode } from "../game-mode";
|
||||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
||||||
import { VariantSet } from "./variant";
|
import { VariantSet } from "./variant";
|
||||||
import i18next, { Localizable } from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
|
import { Localizable } from "#app/interfaces/locales";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
@ -818,6 +819,10 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
|||||||
return super.isObtainable();
|
return super.isObtainable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasVariants() {
|
||||||
|
return variantData.hasOwnProperty(this.speciesId);
|
||||||
|
}
|
||||||
|
|
||||||
getFormSpriteKey(formIndex?: integer) {
|
getFormSpriteKey(formIndex?: integer) {
|
||||||
if (this.forms.length && formIndex >= this.forms.length) {
|
if (this.forms.length && formIndex >= this.forms.length) {
|
||||||
console.warn(`Attempted accessing form with index ${formIndex} of species ${this.getName()} with only ${this.forms.length || 0} forms`);
|
console.warn(`Attempted accessing form with index ${formIndex} of species ${this.getName()} with only ${this.forms.length || 0} forms`);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import i18next from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export enum Stat {
|
export enum Stat {
|
||||||
HP = 0,
|
HP = 0,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import i18next from "../plugins/i18n";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export function getBattleCountSplashMessage(): string {
|
export function getBattleCountSplashMessage(): string {
|
||||||
return `{COUNT} ${i18next.t("splashMessages:battlesWon")}`;
|
return `{COUNT} ${i18next.t("splashMessages:battlesWon")}`;
|
||||||
|
1011
src/data/tms.ts
@ -531,13 +531,18 @@ export class TrainerConfig {
|
|||||||
* Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though.
|
* Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though.
|
||||||
* @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader.
|
* @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader.
|
||||||
* @param {Type[]} specialtyTypes - The specialty types for the evil team Leader.
|
* @param {Type[]} specialtyTypes - The specialty types for the evil team Leader.
|
||||||
|
* @param boolean whether or not this is the rematch fight
|
||||||
* @returns {TrainerConfig} - The updated TrainerConfig instance.
|
* @returns {TrainerConfig} - The updated TrainerConfig instance.
|
||||||
* **/
|
* **/
|
||||||
initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], ...specialtyTypes: Type[]): TrainerConfig {
|
initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], rematch: boolean = false, ...specialtyTypes: Type[]): TrainerConfig {
|
||||||
if (!getIsInitialized()) {
|
if (!getIsInitialized()) {
|
||||||
initI18n();
|
initI18n();
|
||||||
}
|
}
|
||||||
|
if (rematch) {
|
||||||
|
this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR);
|
||||||
|
} else {
|
||||||
this.setPartyTemplates(trainerPartyTemplates.RIVAL_5);
|
this.setPartyTemplates(trainerPartyTemplates.RIVAL_5);
|
||||||
|
}
|
||||||
signatureSpecies.forEach((speciesPool, s) => {
|
signatureSpecies.forEach((speciesPool, s) => {
|
||||||
if (!Array.isArray(speciesPool)) {
|
if (!Array.isArray(speciesPool)) {
|
||||||
speciesPool = [speciesPool];
|
speciesPool = [speciesPool];
|
||||||
@ -551,11 +556,11 @@ export class TrainerConfig {
|
|||||||
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
const nameForCall = this.name.toLowerCase().replace(/\s/g, "_");
|
||||||
this.name = i18next.t(`trainerNames:${nameForCall}`);
|
this.name = i18next.t(`trainerNames:${nameForCall}`);
|
||||||
this.setTitle(title);
|
this.setTitle(title);
|
||||||
this.setMoneyMultiplier(2.5);
|
this.setMoneyMultiplier(2.25);
|
||||||
this.setBoss();
|
this.setBoss();
|
||||||
this.setStaticParty();
|
this.setStaticParty();
|
||||||
this.setBattleBgm("battle_unova_gym"); // TODO: change
|
this.setBattleBgm("battle_plasma_boss");
|
||||||
this.setVictoryBgm("victory_gym"); // TODO: change
|
this.setVictoryBgm("victory_team_plasma");
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -814,7 +819,7 @@ interface TrainerConfigs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The function to get variable strength grutns
|
* The function to get variable strength grunts
|
||||||
* @param scene the singleton scene being passed in
|
* @param scene the singleton scene being passed in
|
||||||
* @returns the correct TrainerPartyTemplate
|
* @returns the correct TrainerPartyTemplate
|
||||||
*/
|
*/
|
||||||
@ -822,23 +827,15 @@ function getEvilGruntPartyTemplate(scene: BattleScene): TrainerPartyTemplate {
|
|||||||
const waveIndex = scene.currentBattle?.waveIndex;
|
const waveIndex = scene.currentBattle?.waveIndex;
|
||||||
if (waveIndex < 40) {
|
if (waveIndex < 40) {
|
||||||
return trainerPartyTemplates.TWO_AVG;
|
return trainerPartyTemplates.TWO_AVG;
|
||||||
} else if (waveIndex < 80) {
|
} else if (waveIndex < 63) {
|
||||||
switch (waveIndex) {
|
|
||||||
case 62:
|
|
||||||
return trainerPartyTemplates.THREE_AVG;
|
return trainerPartyTemplates.THREE_AVG;
|
||||||
case 64:
|
} else if (waveIndex < 65) {
|
||||||
return trainerPartyTemplates.TWO_AVG_ONE_STRONG;
|
return trainerPartyTemplates.TWO_AVG_ONE_STRONG;
|
||||||
case 65:
|
} else if (waveIndex < 112) {
|
||||||
return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger
|
return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch (waveIndex) {
|
|
||||||
case 112:
|
|
||||||
return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger
|
|
||||||
case 114:
|
|
||||||
return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger
|
return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWavePartyTemplate(scene: BattleScene, ...templates: TrainerPartyTemplate[]) {
|
function getWavePartyTemplate(scene: BattleScene, ...templates: TrainerPartyTemplate[]) {
|
||||||
@ -1183,53 +1180,47 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
.setSpeciesPools(
|
.setSpeciesPools(
|
||||||
[Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP]
|
[Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP]
|
||||||
),
|
),
|
||||||
[TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING],
|
[TrainerPoolTier.COMMON]: [ Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING, Species.GRIMER, Species.ODDISH],
|
||||||
[TrainerPoolTier.UNCOMMON]: [Species.GRIMER, Species.CUBONE, Species.ODDISH, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB],
|
[TrainerPoolTier.UNCOMMON]: [ Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB],
|
||||||
[TrainerPoolTier.RARE]: [Species.GYARADOS, Species.TAUROS, Species.SCYTHER],
|
[TrainerPoolTier.RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE],
|
[TrainerPoolTier.SUPER_RARE]: [Species.DRATINI, Species.LARVITAR]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: [Species.DRATINI, Species.LARVITAR]
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY],
|
[TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.BALTOY, Species.BARBOACH],
|
||||||
[TrainerPoolTier.UNCOMMON]: [Species.PHANPY, Species.SWINUB, Species.GLIGAR, Species.TORKOAL, Species.BALTOY, Species.BARBOACH],
|
[TrainerPoolTier.UNCOMMON]: [Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.SWINUB, Species.GLIGAR],
|
||||||
[TrainerPoolTier.RARE]: [Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA],
|
[TrainerPoolTier.RARE]: [Species.TRAPINCH, Species.HEATMOR],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.TRAPINCH, Species.HEATMOR],
|
[TrainerPoolTier.SUPER_RARE]: [Species.TURTONATOR, Species.CHARCADET]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: [Species.TURTONATOR, Species.CHARCADET]
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH],
|
[TrainerPoolTier.COMMON]: [ Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH, Species.SPHEAL ],
|
||||||
[TrainerPoolTier.UNCOMMON]: [Species.SPHEAL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL ],
|
[TrainerPoolTier.UNCOMMON]: [Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH ],
|
||||||
[TrainerPoolTier.RARE]: [Species.CLAMPERL, Species.REMORAID, Species.ARROKUDA],
|
[TrainerPoolTier.RARE]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.MANTINE, Species.BASCULEGION],
|
[TrainerPoolTier.SUPER_RARE]: [Species.DONDOZO]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: [Species.DONDOZO]
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE],
|
[TrainerPoolTier.COMMON]: [ Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE, Species.BRONZOR, Species.DRIFLOON, Species.BURMY],
|
||||||
[TrainerPoolTier.UNCOMMON]: [Species.BRONZOR, Species.DRIFLOON, Species.BURMY],
|
[TrainerPoolTier.UNCOMMON]: [ Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL ],
|
||||||
[TrainerPoolTier.RARE]: [Species.CARNIVINE],
|
[TrainerPoolTier.RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL],
|
[TrainerPoolTier.SUPER_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO]
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE],
|
[TrainerPoolTier.COMMON]: [ Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE, Species.SANDILE, Species.TRUBBISH],
|
||||||
[TrainerPoolTier.UNCOMMON]: [ Species.FRILLISH, Species.VENIPEDE, Species.SANDILE, Species.TRUBBISH, Species.GOLETT],
|
[TrainerPoolTier.UNCOMMON]: [ Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS],
|
||||||
[TrainerPoolTier.RARE]: [Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS, Species.DRILBUR, Species.KLINK, Species.VULLABY],
|
[TrainerPoolTier.RARE]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.PAWNIARD, Species.VULLABY, Species.DRUDDIGON, Species.BOUFFALANT, Species.ZORUA],
|
[TrainerPoolTier.SUPER_RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: [Species.AXEW, Species.DEINO, Species.DURANT]
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
[TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene))
|
||||||
.setSpeciesPools({
|
.setSpeciesPools({
|
||||||
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI],
|
[TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK],
|
||||||
[TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN],
|
[TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG],
|
||||||
[TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL],
|
[TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD],
|
||||||
[TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN],
|
[TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN, Species.DRUDDIGON]
|
||||||
[TrainerPoolTier.ULTRA_RARE]: []
|
|
||||||
}),
|
}),
|
||||||
[TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"],true, Type.ROCK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
[TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"],true, Type.ROCK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
||||||
[TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"],false, Type.WATER).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
[TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"],false, Type.WATER).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"),
|
||||||
@ -1509,7 +1500,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier];
|
return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
[TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss",[])
|
[TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss",[]).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN , Species.ALOLA_PERSIAN]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN , Species.ALOLA_PERSIAN]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NIDOKING , Species.NIDOQUEEN ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NIDOKING , Species.NIDOQUEEN ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RHYPERIOR ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RHYPERIOR ]))
|
||||||
@ -1521,14 +1512,14 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
})),
|
})),
|
||||||
[TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", [])
|
[TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", [], true).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.TYRANITAR , Species.IRON_THORNS], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.TYRANITAR , Species.IRON_THORNS], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.EXCADRILL ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HIPPOWDON ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HIPPOWDON ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.EXCADRILL ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
@ -1541,7 +1532,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[])
|
[TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[]).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIGHTYENA ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIGHTYENA ]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WEEZING, Species.GALAR_WEEZING ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WEEZING, Species.GALAR_WEEZING ]))
|
||||||
@ -1553,33 +1544,33 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
})),
|
})),
|
||||||
[TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[])
|
[TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.TYPHLOSION ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GREAT_TUSK ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.TORKOAL, Species.NINETALES ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.abilityIndex = 2; // DROUGHT
|
||||||
|
}))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SHIFTRY, Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SHIFTRY, Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.abilityIndex = 0; // Chlorophyll
|
p.abilityIndex = 0; // Chlorophyll
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TORKOAL, Species.NINETALES ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GREAT_TUSK ]))
|
||||||
p.generateAndPopulateMoveset();
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.abilityIndex = 2; // DROUGHT
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.setBoss(true, 2);
|
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.setBoss(true, 2);
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[])
|
[TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[]).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LINOONE ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LINOONE ]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.PELIPPER ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.PELIPPER ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MUK, Species.ALOLA_MUK ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MUK, Species.ALOLA_MUK ]))
|
||||||
@ -1591,36 +1582,36 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
})),
|
})),
|
||||||
[TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[])
|
[TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.KINGDRA, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.KINGDRA, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BEARTIC, Species.ARMALDO ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.POLITOED, Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.abilityIndex = 2; // Swift Swim
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HUNTAIL, Species.GOREBYSS ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.abilityIndex = 0; // Swift Swim
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.POLITOED, Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.abilityIndex = 2; // Drizzle
|
p.abilityIndex = 2; // Drizzle
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.BEARTIC, Species.ARMALDO ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
p.abilityIndex = 2; // Swift Swim
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HUNTAIL, Species.GOREBYSS ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.abilityIndex = 0; // Swift Swim
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.setBoss(true, 2);
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[])
|
[TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[]).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.BASCULEGION ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.BASCULEGION ]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.OVERQWIL ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.OVERQWIL ]))
|
||||||
@ -1635,25 +1626,29 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[])
|
[TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ELECTRODE, Species.HISUI_ELECTRODE ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ELECTRODE, Species.HISUI_ELECTRODE ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.ROARING_MOON ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.ROARING_MOON ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HISUI_ZOROARK ]))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => {
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.setBoss(true, 2);
|
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
p.formIndex = 1;
|
||||||
}))
|
}))
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.setBoss(true, 2);
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[])
|
[TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[]).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS, Species.RUNERIGUS ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS, Species.RUNERIGUS ]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BOUFFALANT ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BOUFFALANT ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SEISMITOAD, Species.CARRACOSTA ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SEISMITOAD, Species.CARRACOSTA ]))
|
||||||
@ -1664,7 +1659,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[])
|
[TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SLITHER_WING, Species.IRON_MOTH ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SLITHER_WING, Species.IRON_MOTH ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
@ -1673,17 +1668,17 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DURANT ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DURANT ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DARMANITAN, Species.GALAR_DARMANITAN ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DARMANITAN, Species.GALAR_DARMANITAN ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KINGAMBIT ]))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KINGAMBIT ]))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.setBoss(true, 2);
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
[TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[])
|
[TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[]).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ]))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ]))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ]))
|
||||||
@ -1695,7 +1690,7 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
})),
|
})),
|
||||||
[TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[])
|
[TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma")
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
@ -1704,15 +1699,15 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GHOLDENGO, Species.AEGISLASH ]))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GHOLDENGO, Species.AEGISLASH ]))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ]))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ]))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ]))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ]))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => {
|
||||||
p.setBoss(true, 2);
|
|
||||||
p.generateAndPopulateMoveset();
|
|
||||||
p.pokeball = PokeballType.MASTER_BALL;
|
|
||||||
}))
|
|
||||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => {
|
|
||||||
p.setBoss(true, 2);
|
p.setBoss(true, 2);
|
||||||
p.generateAndPopulateMoveset();
|
p.generateAndPopulateMoveset();
|
||||||
p.pokeball = PokeballType.ULTRA_BALL;
|
p.pokeball = PokeballType.ULTRA_BALL;
|
||||||
p.formIndex = 1;
|
p.formIndex = 1;
|
||||||
|
}))
|
||||||
|
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
p.setBoss(true, 2);
|
||||||
|
p.generateAndPopulateMoveset();
|
||||||
|
p.pokeball = PokeballType.MASTER_BALL;
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { VariantTier } from "#app/enums/variant-tier.js";
|
||||||
|
|
||||||
export type Variant = 0 | 1 | 2;
|
export type Variant = 0 | 1 | 2;
|
||||||
|
|
||||||
export type VariantSet = [Variant, Variant, Variant];
|
export type VariantSet = [Variant, Variant, Variant];
|
||||||
@ -16,3 +18,14 @@ export function getVariantTint(variant: Variant): integer {
|
|||||||
return 0xe81048;
|
return 0xe81048;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getVariantIcon(variant: Variant): integer {
|
||||||
|
switch (variant) {
|
||||||
|
case 0:
|
||||||
|
return VariantTier.STANDARD;
|
||||||
|
case 1:
|
||||||
|
return VariantTier.RARE;
|
||||||
|
case 2:
|
||||||
|
return VariantTier.EPIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||||
|
import i18next from "i18next";
|
||||||
import { Phase } from "./phase";
|
import { Phase } from "./phase";
|
||||||
import BattleScene, { AnySound } from "./battle-scene";
|
import BattleScene, { AnySound } from "./battle-scene";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
import { Mode } from "./ui/ui";
|
import { Mode } from "./ui/ui";
|
||||||
import { EGG_SEED, Egg, GachaType, getLegendaryGachaSpeciesForTimestamp } from "./data/egg";
|
import { EGG_SEED, Egg } from "./data/egg";
|
||||||
import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler";
|
import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler";
|
||||||
import { PlayerPokemon } from "./field/pokemon";
|
import { PlayerPokemon } from "./field/pokemon";
|
||||||
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
|
||||||
import { achvs } from "./system/achv";
|
import { achvs } from "./system/achv";
|
||||||
import { pokemonPrevolutions } from "./data/pokemon-evolutions";
|
|
||||||
import PokemonInfoContainer from "./ui/pokemon-info-container";
|
import PokemonInfoContainer from "./ui/pokemon-info-container";
|
||||||
import EggCounterContainer from "./ui/egg-counter-container";
|
import EggCounterContainer from "./ui/egg-counter-container";
|
||||||
import { EggCountChangedEvent } from "./events/egg";
|
import { EggCountChangedEvent } from "./events/egg";
|
||||||
import { EggTier } from "#enums/egg-type";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents egg hatching
|
* Class that represents egg hatching
|
||||||
@ -345,7 +342,7 @@ export class EggHatchPhase extends Phase {
|
|||||||
|
|
||||||
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
this.scene.playSoundWithoutBgm("evolution_fanfare");
|
||||||
|
|
||||||
this.scene.ui.showText(`${this.pokemon.name} hatched from the egg!`, null, () => {
|
this.scene.ui.showText(i18next.t("egg:hatchFromTheEgg", { pokemonName: this.pokemon.name }), null, () => {
|
||||||
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
||||||
this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => {
|
this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => {
|
||||||
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => {
|
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => {
|
||||||
@ -442,135 +439,10 @@ export class EggHatchPhase extends Phase {
|
|||||||
*/
|
*/
|
||||||
generatePokemon(): PlayerPokemon {
|
generatePokemon(): PlayerPokemon {
|
||||||
let ret: PlayerPokemon;
|
let ret: PlayerPokemon;
|
||||||
let speciesOverride: Species; // SpeciesOverride should probably be a passed in parameter for future species-eggs
|
|
||||||
|
|
||||||
this.scene.executeWithSeedOffset(() => {
|
this.scene.executeWithSeedOffset(() => {
|
||||||
|
ret = this.egg.generatePlayerPokemon(this.scene);
|
||||||
/**
|
this.eggMoveIndex = this.egg.eggMoveIndex;
|
||||||
* Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione
|
|
||||||
* Legendary eggs pulled from the legendary gacha have a 50% of being converted into
|
|
||||||
* the species that was the legendary focus at the time
|
|
||||||
*/
|
|
||||||
if (this.egg.isManaphyEgg()) {
|
|
||||||
const rand = Utils.randSeedInt(8);
|
|
||||||
|
|
||||||
speciesOverride = rand ? Species.PHIONE : Species.MANAPHY;
|
|
||||||
} else if (this.egg.tier === EggTier.MASTER
|
|
||||||
&& this.egg.gachaType === GachaType.LEGENDARY) {
|
|
||||||
if (!Utils.randSeedInt(2)) {
|
|
||||||
speciesOverride = getLegendaryGachaSpeciesForTimestamp(this.scene, this.egg.timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speciesOverride) {
|
|
||||||
const pokemonSpecies = getPokemonSpecies(speciesOverride);
|
|
||||||
ret = this.scene.addPlayerPokemon(pokemonSpecies, 1, undefined, undefined, undefined, false);
|
|
||||||
} else {
|
|
||||||
let minStarterValue: integer;
|
|
||||||
let maxStarterValue: integer;
|
|
||||||
|
|
||||||
switch (this.egg.tier) {
|
|
||||||
case EggTier.GREAT:
|
|
||||||
minStarterValue = 4;
|
|
||||||
maxStarterValue = 5;
|
|
||||||
break;
|
|
||||||
case EggTier.ULTRA:
|
|
||||||
minStarterValue = 6;
|
|
||||||
maxStarterValue = 7;
|
|
||||||
break;
|
|
||||||
case EggTier.MASTER:
|
|
||||||
minStarterValue = 8;
|
|
||||||
maxStarterValue = 9;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
minStarterValue = 1;
|
|
||||||
maxStarterValue = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ];
|
|
||||||
|
|
||||||
let speciesPool = Object.keys(speciesStarters)
|
|
||||||
.filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue)
|
|
||||||
.map(s => parseInt(s) as Species)
|
|
||||||
.filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
|
|
||||||
|
|
||||||
// If this is the 10th egg without unlocking something new, attempt to force it.
|
|
||||||
if (this.scene.gameData.unlockPity[this.egg.tier] >= 9) {
|
|
||||||
const lockedPool = speciesPool.filter(s => !this.scene.gameData.dexData[s].caughtAttr);
|
|
||||||
if (lockedPool.length) { // Skip this if everything is unlocked
|
|
||||||
speciesPool = lockedPool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pokemon that are cheaper in their tier get a weight boost. Regionals get a weight penalty
|
|
||||||
* 1 cost mons get 2x
|
|
||||||
* 2 cost mons get 1.5x
|
|
||||||
* 4, 6, 8 cost mons get 1.75x
|
|
||||||
* 3, 5, 7, 9 cost mons get 1x
|
|
||||||
* Alolan, Galarian, and Paldean mons get 0.5x
|
|
||||||
* Hisui mons get 0.125x
|
|
||||||
*
|
|
||||||
* The total weight is also being calculated EACH time there is an egg hatch instead of being generated once
|
|
||||||
* and being the same each time
|
|
||||||
*/
|
|
||||||
let totalWeight = 0;
|
|
||||||
const speciesWeights = [];
|
|
||||||
for (const speciesId of speciesPool) {
|
|
||||||
let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
|
|
||||||
const species = getPokemonSpecies(speciesId);
|
|
||||||
if (species.isRegional()) {
|
|
||||||
weight = Math.floor(weight / (species.isRareRegional() ? 8 : 2));
|
|
||||||
}
|
|
||||||
speciesWeights.push(totalWeight + weight);
|
|
||||||
totalWeight += weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
let species: Species;
|
|
||||||
|
|
||||||
const rand = Utils.randSeedInt(totalWeight);
|
|
||||||
for (let s = 0; s < speciesWeights.length; s++) {
|
|
||||||
if (rand < speciesWeights[s]) {
|
|
||||||
species = speciesPool[s];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!this.scene.gameData.dexData[species].caughtAttr) {
|
|
||||||
this.scene.gameData.unlockPity[this.egg.tier] = Math.min(this.scene.gameData.unlockPity[this.egg.tier] + 1, 10);
|
|
||||||
} else {
|
|
||||||
this.scene.gameData.unlockPity[this.egg.tier] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pokemonSpecies = getPokemonSpecies(species);
|
|
||||||
|
|
||||||
ret = this.scene.addPlayerPokemon(pokemonSpecies, 1, undefined, undefined, undefined, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Non Shiny gacha Pokemon have a 1/128 chance of being shiny
|
|
||||||
* Shiny gacha Pokemon have a 1/64 chance of being shiny
|
|
||||||
* IVs are rolled twice and the higher of each stat's IV is taken
|
|
||||||
* The egg move gacha doubles the rate of rare egg moves but the base rates are
|
|
||||||
* Common: 1/48
|
|
||||||
* Rare: 1/24
|
|
||||||
* Epic: 1/12
|
|
||||||
* Legendary: 1/6
|
|
||||||
*/
|
|
||||||
ret.trySetShiny(this.egg.gachaType === GachaType.SHINY ? 1024 : 512);
|
|
||||||
ret.variant = ret.shiny ? ret.generateVariant() : 0;
|
|
||||||
|
|
||||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
|
||||||
|
|
||||||
for (let s = 0; s < ret.ivs.length; s++) {
|
|
||||||
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseChance = this.egg.gachaType === GachaType.MOVE ? 3 : 6;
|
|
||||||
this.eggMoveIndex = Utils.randSeedInt(baseChance * Math.pow(2, 3 - this.egg.tier))
|
|
||||||
? Utils.randSeedInt(3)
|
|
||||||
: 3;
|
|
||||||
|
|
||||||
}, this.egg.id, EGG_SEED.toString());
|
}, this.egg.id, EGG_SEED.toString());
|
||||||
|
|
||||||
|
@ -20,5 +20,6 @@ export enum ArenaTagType {
|
|||||||
WIDE_GUARD = "WIDE_GUARD",
|
WIDE_GUARD = "WIDE_GUARD",
|
||||||
MAT_BLOCK = "MAT_BLOCK",
|
MAT_BLOCK = "MAT_BLOCK",
|
||||||
CRAFTY_SHIELD = "CRAFTY_SHIELD",
|
CRAFTY_SHIELD = "CRAFTY_SHIELD",
|
||||||
TAILWIND = "TAILWIND"
|
TAILWIND = "TAILWIND",
|
||||||
|
HAPPY_HOUR = "HAPPY_HOUR"
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,10 @@ export enum BattlerTagType {
|
|||||||
SALT_CURED = "SALT_CURED",
|
SALT_CURED = "SALT_CURED",
|
||||||
CURSED = "CURSED",
|
CURSED = "CURSED",
|
||||||
CHARGED = "CHARGED",
|
CHARGED = "CHARGED",
|
||||||
GROUNDED = "GROUNDED",
|
ROOSTED = "ROOSTED",
|
||||||
MAGNET_RISEN = "MAGNET_RISEN",
|
MAGNET_RISEN = "MAGNET_RISEN",
|
||||||
MINIMIZED = "MINIMIZED",
|
MINIMIZED = "MINIMIZED",
|
||||||
DESTINY_BOND = "DESTINY_BOND",
|
DESTINY_BOND = "DESTINY_BOND",
|
||||||
|
CENTER_OF_ATTENTION = "CENTER_OF_ATTENTION",
|
||||||
ICE_FACE = "ICE_FACE"
|
ICE_FACE = "ICE_FACE"
|
||||||
}
|
}
|
||||||
|
83
src/enums/color.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
export enum Color {
|
||||||
|
WHITE = "#ffffff",
|
||||||
|
OFF_WHITE = "#f8f8f8",
|
||||||
|
LIGHT_GREY = "#a0a0a0",
|
||||||
|
GREY = "#484848",
|
||||||
|
DARK_GREY = "#404040",
|
||||||
|
PINK = "#f89890",
|
||||||
|
RED = "#e13d3d",
|
||||||
|
RED2 = "#e70808",
|
||||||
|
REDORANGE = "#d64b00",
|
||||||
|
ORANGE = "#f8b050",
|
||||||
|
LIGHT_YELLOW = "#e8e8a8",
|
||||||
|
YELLOW = "#ccbe00",
|
||||||
|
DARK_YELLOW = "#a68e17",
|
||||||
|
GREEN = "#78c850",
|
||||||
|
BLUE = "#40c8f8",
|
||||||
|
COMMON = "#ffffff",
|
||||||
|
GREAT = "#3890f8",
|
||||||
|
ULTRA = "#f8d038",
|
||||||
|
ROGUE = "#d52929",
|
||||||
|
MASTER = "#e020c0",
|
||||||
|
LUXURY = "#e64a18"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TypeColor {
|
||||||
|
NORMAL = "#ADA594",
|
||||||
|
FIGHTING = "#A55239",
|
||||||
|
FLYING = "#9CADF7",
|
||||||
|
POISON = "#9141CB",
|
||||||
|
GROUND = "#AE7A3B",
|
||||||
|
ROCK = "#BDA55A",
|
||||||
|
BUG = "#ADBD21",
|
||||||
|
GHOST = "#6363B5",
|
||||||
|
STEEL = "#81A6BE",
|
||||||
|
FIRE = "#F75231",
|
||||||
|
WATER = "#399CFF",
|
||||||
|
GRASS = "#7BCE52",
|
||||||
|
ELECTRIC = "#FFC631",
|
||||||
|
PSYCHIC = "#EF4179",
|
||||||
|
ICE = "#5ACEE7",
|
||||||
|
DRAGON = "#7B63E7",
|
||||||
|
DARK = "#735A4A",
|
||||||
|
FAIRY = "#EF70EF",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TypeShadow {
|
||||||
|
NORMAL = "#574F4A",
|
||||||
|
FIGHTING = "#4E637C",
|
||||||
|
FLYING = "#4E637C",
|
||||||
|
POISON = "#352166",
|
||||||
|
GROUND = "#572D1E",
|
||||||
|
ROCK = "#5F442D",
|
||||||
|
BUG = "#5F5010",
|
||||||
|
GHOST = "#323D5B",
|
||||||
|
STEEL = "#415C5F",
|
||||||
|
FIRE = "#7C1818",
|
||||||
|
WATER = "#1C4E80",
|
||||||
|
GRASS = "#4F6729",
|
||||||
|
ELECTRIC = "#804618",
|
||||||
|
PSYCHIC = "#782155",
|
||||||
|
ICE = "#2D5C74",
|
||||||
|
DRAGON = "#313874",
|
||||||
|
DARK = "#392725",
|
||||||
|
FAIRY = "#663878",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ShadowColor {
|
||||||
|
GREY = "#636363",
|
||||||
|
PURPLE = "#6b5a73",
|
||||||
|
LIGHT_GREY = "#d0d0c8",
|
||||||
|
BROWN = "#69402a",
|
||||||
|
PINK = "#fca2a2",
|
||||||
|
BRIGHT_RED = "#f83018",
|
||||||
|
RED = "#984038",
|
||||||
|
MAROON = "#632929",
|
||||||
|
GREEN = "#306850",
|
||||||
|
BLUE = "#006090",
|
||||||
|
LIGHT_YELLOW = "#ded6b5",
|
||||||
|
YELLOW = "#ebd773",
|
||||||
|
DARK_YELLOW = "#a0a060",
|
||||||
|
ORANGE = "#c07800",
|
||||||
|
LIGHT_ORANGE = "#ffbd73",
|
||||||
|
}
|
7
src/enums/egg-source-types.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export enum EggSourceType {
|
||||||
|
GACHA_MOVE,
|
||||||
|
GACHA_LEGENDARY,
|
||||||
|
GACHA_SHINY,
|
||||||
|
SAME_SPECIES_EGG,
|
||||||
|
EVENT
|
||||||
|
}
|
5
src/enums/gacha-types.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum GachaType {
|
||||||
|
MOVE,
|
||||||
|
LEGENDARY,
|
||||||
|
SHINY
|
||||||
|
}
|
5
src/enums/variant-tier.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum VariantTier {
|
||||||
|
STANDARD,
|
||||||
|
RARE,
|
||||||
|
EPIC
|
||||||
|
}
|
5
src/enums/variant-tiers.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum VariantTier {
|
||||||
|
COMMON,
|
||||||
|
RARE,
|
||||||
|
EPIC
|
||||||
|
}
|