|
@ -46,6 +46,7 @@ export default [
|
|||
"computed-property-spacing": ["error", "never" ], // Enforces consistent spacing inside computed property brackets
|
||||
"space-infix-ops": ["error", { "int32Hint": false }], // Enforces spacing around infix operators
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], // Disallows multiple empty lines
|
||||
"@typescript-eslint/consistent-type-imports": "error", // Enforces type-only imports wherever possible
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.4.3",
|
||||
"version": "1.5.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.4.3",
|
||||
"version": "1.5.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "^0.2.7",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"private": true,
|
||||
"version": "1.4.3",
|
||||
"version": "1.5.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
|
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 748 B |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 713 B After Width: | Height: | Size: 748 B |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
|
@ -4,6 +4,8 @@
|
|||
"ffee52": "37d6de",
|
||||
"debd29": "078a8f",
|
||||
"833100": "002112",
|
||||
"830009": "23033b",
|
||||
"189d87": "c2247b",
|
||||
"ff7b73": "712f8f",
|
||||
"de4141": "3f1375",
|
||||
"ffbdbd": "a266b0",
|
||||
|
@ -11,6 +13,7 @@
|
|||
"107b6a": "9e1976",
|
||||
"105241": "4f2800",
|
||||
"83de7b": "a37707",
|
||||
"2e5529": "38001c",
|
||||
"5a9c39": "705207",
|
||||
"20b49c": "de3592",
|
||||
"fdfdfd": "fdfdfd",
|
||||
|
@ -21,14 +24,17 @@
|
|||
"ffee52": "f75ea8",
|
||||
"debd29": "a30a66",
|
||||
"833100": "0b2e01",
|
||||
"830009": "154205",
|
||||
"189d87": "f17f05",
|
||||
"ff7b73": "9db042",
|
||||
"de4141": "3c8227",
|
||||
"ffbdbd": "e7e385",
|
||||
"101010": "101010",
|
||||
"107b6a": "d44300",
|
||||
"105241": "030129",
|
||||
"83de7b": "433d99",
|
||||
"5a9c39": "19164f",
|
||||
"105241": "381601",
|
||||
"83de7b": "80ced9",
|
||||
"2e5519": "011c38",
|
||||
"5a9c39": "446b94",
|
||||
"20b49c": "fa8405",
|
||||
"fdfdfd": "fdfdfd",
|
||||
"5ad5c5": "faa405"
|
||||
|
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"1": {
|
||||
"843100": "033b22",
|
||||
"830009": "23033b",
|
||||
"ff7b73": "712f8f",
|
||||
"ffbdbd": "a266b0",
|
||||
"debd29": "078a8f",
|
||||
|
@ -13,11 +14,13 @@
|
|||
"5a9c3a": "b34952",
|
||||
"84de7b": "ff745e",
|
||||
"5ad6c5": "f062a4",
|
||||
"2e5519": "38001c",
|
||||
"21b59c": "de3592",
|
||||
"ffffff": "ffffff"
|
||||
},
|
||||
"2": {
|
||||
"843100": "420514",
|
||||
"830009": "154205",
|
||||
"ff7b73": "9db042",
|
||||
"ffbdbd": "e7e385",
|
||||
"debd29": "a30a66",
|
||||
|
@ -30,6 +33,7 @@
|
|||
"5a9c3a": "446b94",
|
||||
"84de7b": "80ced9",
|
||||
"5ad6c5": "faa405",
|
||||
"2e5519": "011c38",
|
||||
"21b59c": "fa8405",
|
||||
"ffffff": "ffffff"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"3f4447": "466698",
|
||||
"de3431": "3fca9f",
|
||||
"f8f8f8": "a1e9f0",
|
||||
"f4f4f4": "d7eff4",
|
||||
"7b282e": "0e3e81",
|
||||
"6b1d1d": "206d74",
|
||||
"4ebdd9": "41a7b0",
|
||||
|
@ -11,7 +12,7 @@
|
|||
"bfbfbf": "8cc7d4",
|
||||
"ffb2bf": "b7e9ff",
|
||||
"bf4c60": "4386df",
|
||||
"fff0a6": "271f4c",
|
||||
"fff0a6": "208698",
|
||||
"3e7acc": "6b4592",
|
||||
"18335c": "170738",
|
||||
"f2798d": "8dcfff",
|
||||
|
@ -25,6 +26,7 @@
|
|||
"3f4447": "466698",
|
||||
"de3431": "9ceec6",
|
||||
"f8f8f8": "89d2b8",
|
||||
"f4f4f4": "d7eff4",
|
||||
"7b282e": "152a5c",
|
||||
"6b1d1d": "356e8d",
|
||||
"4ebdd9": "2f6e74",
|
||||
|
|
|
@ -835,7 +835,7 @@
|
|||
"6713": [0, 1, 1],
|
||||
"8901": [1, 1, 1],
|
||||
"female": {
|
||||
"3": [0, 2, 1],
|
||||
"3": [0, 1, 1],
|
||||
"19": [0, 1, 1],
|
||||
"20": [0, 1, 1],
|
||||
"25": [0, 1, 1],
|
||||
|
@ -869,6 +869,7 @@
|
|||
"198": [0, 1, 1],
|
||||
"203": [0, 1, 1],
|
||||
"207": [0, 1, 1],
|
||||
"212": [1, 1, 1],
|
||||
"215": [0, 1, 1],
|
||||
"217": [1, 1, 1],
|
||||
"229": [0, 1, 1],
|
||||
|
@ -1778,6 +1779,7 @@
|
|||
"198": [0, 1, 1],
|
||||
"203": [0, 1, 1],
|
||||
"207": [0, 1, 1],
|
||||
"212": [1, 1, 1],
|
||||
"215": [0, 1, 1],
|
||||
"217": [1, 1, 1],
|
||||
"229": [0, 1, 1],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"1": {
|
||||
"833100": "180136",
|
||||
"830009": "23033b",
|
||||
"bd6a31": "012729",
|
||||
"ffee52": "37d6de",
|
||||
"debd29": "078a8f",
|
||||
|
@ -8,15 +9,18 @@
|
|||
"de4141": "3f1375",
|
||||
"ff7b73": "712f8f",
|
||||
"ffbdbd": "a266b0",
|
||||
"5a9c39": "705207",
|
||||
"105241": "4f2800",
|
||||
"83de7b": "a37707",
|
||||
"e8a3a3": "91579e",
|
||||
"5a9c39": "b34952",
|
||||
"105241": "190038",
|
||||
"2e5519": "38001c",
|
||||
"83de7b": "ff745e",
|
||||
"107b6a": "b80479",
|
||||
"20b49c": "de3592",
|
||||
"fdfdfd": "fdfdfd"
|
||||
},
|
||||
"2": {
|
||||
"833100": "0b2e01",
|
||||
"830009": "154205",
|
||||
"bd6a31": "420514",
|
||||
"ffee52": "f75ea8",
|
||||
"debd29": "a30a66",
|
||||
|
@ -24,9 +28,11 @@
|
|||
"de4141": "3c8227",
|
||||
"ff7b73": "9db042",
|
||||
"ffbdbd": "e7e385",
|
||||
"5a9c39": "19164f",
|
||||
"105241": "030129",
|
||||
"83de7b": "433d99",
|
||||
"e8a3a3": "ced76f",
|
||||
"5a9c39": "446b94",
|
||||
"105241": "381601",
|
||||
"2e5519": "011c38",
|
||||
"83de7b": "80ced9",
|
||||
"107b6a": "d15d04",
|
||||
"20b49c": "fa8405",
|
||||
"fdfdfd": "fdfdfd"
|
||||
|
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"1": {
|
||||
"843100": "033b22",
|
||||
"830009": "23033b",
|
||||
"ffbdbd": "a266b0",
|
||||
"ff7b73": "712f8f",
|
||||
"debd29": "078a8f",
|
||||
|
@ -11,6 +12,7 @@
|
|||
"105242": "190038",
|
||||
"107b6b": "c21f7e",
|
||||
"5a9c3a": "b34952",
|
||||
"2e5519": "38001c",
|
||||
"5ad6c5": "f062a4",
|
||||
"21b59c": "de3592",
|
||||
"84de7b": "ff745e",
|
||||
|
@ -18,6 +20,7 @@
|
|||
},
|
||||
"2": {
|
||||
"843100": "420514",
|
||||
"830009": "154205",
|
||||
"ffbdbd": "e7e385",
|
||||
"ff7b73": "9db042",
|
||||
"debd29": "a30a66",
|
||||
|
@ -25,7 +28,8 @@
|
|||
"de4242": "3c8227",
|
||||
"101010": "101010",
|
||||
"ffef52": "f75ea8",
|
||||
"105242": "001a33",
|
||||
"105242": "381601",
|
||||
"2e5519": "011c38",
|
||||
"107b6b": "d15d04",
|
||||
"5a9c3a": "446b94",
|
||||
"5ad6c5": "faa405",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"de62a4": "ffc668",
|
||||
"4a83a4": "387fa7",
|
||||
"314a62": "244260",
|
||||
"70bbb4": "f8d371",
|
||||
"548e88": "2d60bb",
|
||||
"a4295a": "cc762f"
|
||||
},
|
||||
"1": {
|
||||
|
@ -22,7 +22,7 @@
|
|||
"de62a4": "ffdf90",
|
||||
"4a83a4": "a1c8db",
|
||||
"314a62": "7396b4",
|
||||
"70bbb4": "70bbb4",
|
||||
"548e88": "a9c0c6",
|
||||
"a4295a": "e28c27"
|
||||
},
|
||||
"2": {
|
||||
|
@ -35,7 +35,7 @@
|
|||
"de62a4": "e25038",
|
||||
"4a83a4": "e6aa47",
|
||||
"314a62": "b56f2a",
|
||||
"70bbb4": "f8d371",
|
||||
"548e88": "e0b544",
|
||||
"a4295a": "a62a21"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"0": {
|
||||
"632929": "215a2d",
|
||||
"f76b6b": "8cce73",
|
||||
"a52929": "2f794e",
|
||||
"101010": "101010",
|
||||
"d63a3a": "4a9c53",
|
||||
"9494a5": "9494a5",
|
||||
"ffffff": "ffffff",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"3a3a4a": "3a3a4a",
|
||||
"9c6b21": "9c6b21",
|
||||
"dec510": "dec510"
|
||||
},
|
||||
"1": {
|
||||
"632929": "2f2962",
|
||||
"f76b6b": "639cf7",
|
||||
"a52929": "29429c",
|
||||
"101010": "101010",
|
||||
"d63a3a": "4263ef",
|
||||
"9494a5": "6262a4",
|
||||
"ffffff": "ffffff",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"3a3a4a": "3c3c50",
|
||||
"9c6b21": "131387",
|
||||
"dec510": "10bdde"
|
||||
},
|
||||
"2": {
|
||||
"632929": "645117",
|
||||
"f76b6b": "c59f29",
|
||||
"a52929": "b88619",
|
||||
"101010": "101010",
|
||||
"d63a3a": "ffca2a",
|
||||
"9494a5": "3c4543",
|
||||
"ffffff": "ffffff",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"3a3a4a": "282d2c",
|
||||
"9c6b21": "9c6b21",
|
||||
"dec510": "dec510"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"1": {
|
||||
"843100": "033b22",
|
||||
"830009": "23033b",
|
||||
"ffbdbd": "a266b0",
|
||||
"ffef52": "37d6de",
|
||||
"debd29": "078a8f",
|
||||
|
@ -10,6 +11,7 @@
|
|||
"101010": "101010",
|
||||
"105242": "190038",
|
||||
"107b6b": "9e1976",
|
||||
"2e5519": "38001c",
|
||||
"5a9c3a": "b34952",
|
||||
"5ad6c5": "f062a4",
|
||||
"21b59c": "de3592",
|
||||
|
@ -18,6 +20,7 @@
|
|||
},
|
||||
"2": {
|
||||
"843100": "420514",
|
||||
"830009": "154205",
|
||||
"ffbdbd": "e7e385",
|
||||
"ffef52": "f75ea8",
|
||||
"debd29": "a30a66",
|
||||
|
@ -27,6 +30,7 @@
|
|||
"101010": "101010",
|
||||
"105242": "381601",
|
||||
"107b6b": "d15d04",
|
||||
"2e5519": "011c38",
|
||||
"5a9c3a": "446b94",
|
||||
"5ad6c5": "faa405",
|
||||
"21b59c": "fa8405",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"3f4447": "466698",
|
||||
"de3431": "3fca9f",
|
||||
"f8f8f8": "a1e9f0",
|
||||
"f4f4f4": "d7effa",
|
||||
"7b282e": "0e3e81",
|
||||
"6b1d1d": "206d74",
|
||||
"4ebdd9": "41a7b0",
|
||||
|
@ -25,6 +26,7 @@
|
|||
"3f4447": "466698",
|
||||
"de3431": "9ceec6",
|
||||
"f8f8f8": "89d2b8",
|
||||
"f4f4f4": "d7effa",
|
||||
"7b282e": "152a5c",
|
||||
"6b1d1d": "356e8d",
|
||||
"4ebdd9": "2f6e74",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"0f0f0f": "0f0f0f",
|
||||
"314a62": "244260",
|
||||
"621841": "71370f",
|
||||
"70bbb4": "f8d371",
|
||||
"548e88": "2d60bb",
|
||||
"de62a4": "ffc668",
|
||||
"a4295a": "cc762f"
|
||||
},
|
||||
|
@ -21,7 +21,7 @@
|
|||
"0f0f0f": "0f0f0f",
|
||||
"314a62": "7396b4",
|
||||
"621841": "7b3c08",
|
||||
"70bbb4": "70bbb4",
|
||||
"548e88": "a9c0c6",
|
||||
"de62a4": "ffdf90",
|
||||
"a4295a": "e28c27"
|
||||
},
|
||||
|
@ -34,7 +34,7 @@
|
|||
"0f0f0f": "0f0f0f",
|
||||
"314a62": "b56f2a",
|
||||
"621841": "5a0a05",
|
||||
"70bbb4": "f8d371",
|
||||
"548e88": "e0b544",
|
||||
"de62a4": "e25038",
|
||||
"a4295a": "a62a21"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"0": {
|
||||
"632929": "215a2d",
|
||||
"f76b6b": "8cce73",
|
||||
"101010": "101010",
|
||||
"3a3a4a": "3a3a4a",
|
||||
"ffffff": "ffffff",
|
||||
"d63a3a": "4a9c53",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"9494a5": "9494a5",
|
||||
"a52929": "2f794e",
|
||||
"dec510": "dec510",
|
||||
"9c6b21": "9c6b21"
|
||||
},
|
||||
"1": {
|
||||
"632929": "2f2962",
|
||||
"f76b6b": "639cf7",
|
||||
"101010": "101010",
|
||||
"3a3a4a": "3c3c50",
|
||||
"ffffff": "ffffff",
|
||||
"d63a3a": "4263ef",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"9494a5": "6262a4",
|
||||
"a52929": "29429c",
|
||||
"dec510": "10bdde",
|
||||
"9c6b21": "131387"
|
||||
},
|
||||
"2": {
|
||||
"632929": "645117",
|
||||
"f76b6b": "c59f29",
|
||||
"101010": "101010",
|
||||
"3a3a4a": "282d2c",
|
||||
"ffffff": "ffffff",
|
||||
"d63a3a": "ffca2a",
|
||||
"b5b5ce": "b5b5ce",
|
||||
"9494a5": "3c4543",
|
||||
"a52929": "b88619",
|
||||
"dec510": "dec510",
|
||||
"9c6b21": "9c6b21"
|
||||
}
|
||||
}
|
|
@ -1,19 +1,41 @@
|
|||
{
|
||||
"1": {
|
||||
"843100": "033b22",
|
||||
"830009": "23033b",
|
||||
"ffbdbd": "a266b0",
|
||||
"ffef52": "37d6de",
|
||||
"debd29": "078a8f",
|
||||
"ff7b73": "712f8f",
|
||||
"bd6b31": "168a69",
|
||||
"de4242": "3f1375",
|
||||
"101010": "101010",
|
||||
"105242": "190038",
|
||||
"107b6b": "9e1976",
|
||||
"2e5519": "38001c",
|
||||
"5a9c3a": "b34952",
|
||||
"5ad6c5": "f062a4",
|
||||
"21b59c": "de3592",
|
||||
"84de7b": "ff745e",
|
||||
"ffffff": "ffffff"
|
||||
},
|
||||
"2": {
|
||||
"843100": "420514",
|
||||
"ff7b73": "9db042",
|
||||
"830009": "154205",
|
||||
"ffbdbd": "e7e385",
|
||||
"ffef52": "f75ea8",
|
||||
"debd29": "a30a66",
|
||||
"ff7b73": "9db042",
|
||||
"bd6b31": "852a41",
|
||||
"de4242": "3c8227",
|
||||
"101010": "101010",
|
||||
"105242": "381601",
|
||||
"107b6b": "d44300",
|
||||
"107b6b": "d15d04",
|
||||
"2e5519": "011c38",
|
||||
"5a9c3a": "446b94",
|
||||
"84de7b": "80ced9",
|
||||
"5ad6c5": "faa405",
|
||||
"21b59c": "fa8405",
|
||||
"ffffff": "ffffff"
|
||||
"84de7b": "80ced9",
|
||||
"ffffff": "ffffff",
|
||||
"2f561a": "011b34"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 985 B |
|
@ -1 +1 @@
|
|||
Subproject commit 2e03bc8f2736269bfa365faad587c3ec54a37621
|
||||
Subproject commit 5ef993b95fa8248adc0fb7d9489baccf546bf8e3
|
|
@ -1,3 +1 @@
|
|||
import BattleScene from "#app/battle-scene";
|
||||
|
||||
export type ConditionFn = (scene: BattleScene, args?: any[]) => boolean;
|
||||
export type ConditionFn = (args?: any[]) => boolean;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { TOptions } from "i18next";
|
||||
import type { TOptions } from "i18next";
|
||||
|
||||
// Module declared to make referencing keys in the localization files type-safe.
|
||||
declare module "i18next" {
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
import Phaser from "phaser";
|
||||
import UI from "#app/ui/ui";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } from "#app/data/pokemon-species";
|
||||
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PokemonSpeciesFilter } from "#app/data/pokemon-species";
|
||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import type { Constructor } from "#app/utils";
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import * as Utils from "#app/utils";
|
||||
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, ModifierBar, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier, TerastallizeModifier } from "./modifier/modifier";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "#app/data/battle-anims";
|
||||
import { Phase } from "#app/phase";
|
||||
import type { Phase } from "#app/phase";
|
||||
import { initGameSpeed } from "#app/system/game-speed";
|
||||
import { Arena, ArenaBase } from "#app/field/arena";
|
||||
import { GameData } from "#app/system/game-data";
|
||||
|
@ -17,26 +22,32 @@ import { MusicPreference } from "#app/system/settings/settings";
|
|||
import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getModifierType, getPartyLuckValue, ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import AbilityBar from "#app/ui/ability-bar";
|
||||
import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, PostBattleInitAbAttr, PostItemLostAbAttr } from "#app/data/ability";
|
||||
import Battle, { BattleType, FixedBattleConfig } from "#app/battle";
|
||||
import { GameMode, GameModes, getGameMode } from "#app/game-mode";
|
||||
import type { FixedBattleConfig } from "#app/battle";
|
||||
import Battle, { BattleType } from "#app/battle";
|
||||
import type { GameMode } from "#app/game-mode";
|
||||
import { GameModes, getGameMode } from "#app/game-mode";
|
||||
import FieldSpritePipeline from "#app/pipelines/field-sprite";
|
||||
import SpritePipeline from "#app/pipelines/sprite";
|
||||
import PartyExpBar from "#app/ui/party-exp-bar";
|
||||
import { trainerConfigs, TrainerSlot } from "#app/data/trainer-config";
|
||||
import type { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { trainerConfigs } from "#app/data/trainer-config";
|
||||
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||
import TrainerData from "#app/system/trainer-data";
|
||||
import type TrainerData from "#app/system/trainer-data";
|
||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import PokeballTray from "#app/ui/pokeball-tray";
|
||||
import InvertPostFX from "#app/pipelines/invert";
|
||||
import { Achv, achvs, ModifierAchv, MoneyAchv } from "#app/system/achv";
|
||||
import { Voucher, vouchers } from "#app/system/voucher";
|
||||
import type { Achv } from "#app/system/achv";
|
||||
import { achvs, ModifierAchv, MoneyAchv } from "#app/system/achv";
|
||||
import type { Voucher } from "#app/system/voucher";
|
||||
import { vouchers } from "#app/system/voucher";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
|
||||
import type UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
|
||||
import { addUiThemeOverrides } from "#app/ui/ui-theme";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import type PokemonData from "#app/system/pokemon-data";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms";
|
||||
import type { SpeciesFormChange, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms";
|
||||
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger } from "#app/data/pokemon-forms";
|
||||
import { FormChangePhase } from "#app/phases/form-change-phase";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { Type } from "#enums/type";
|
||||
|
@ -47,8 +58,9 @@ import PokemonInfoContainer from "#app/ui/pokemon-info-container";
|
|||
import { biomeDepths, getBiomeName } from "#app/data/balance/biomes";
|
||||
import { SceneBase } from "#app/scene-base";
|
||||
import CandyBar from "#app/ui/candy-bar";
|
||||
import { Variant, variantColorCache, variantData, VariantSet } from "#app/data/variant";
|
||||
import { Localizable } from "#app/interfaces/locales";
|
||||
import type { Variant, VariantSet } from "#app/data/variant";
|
||||
import { variantColorCache, variantData } from "#app/data/variant";
|
||||
import type { Localizable } from "#app/interfaces/locales";
|
||||
import Overrides from "#app/overrides";
|
||||
import { InputsController } from "#app/inputs-controller";
|
||||
import { UiInputs } from "#app/ui-inputs";
|
||||
|
@ -58,14 +70,14 @@ import { EaseType } from "#enums/ease-type";
|
|||
import { BattleSpec } from "#enums/battle-spec";
|
||||
import { BattleStyle } from "#enums/battle-style";
|
||||
import { Biome } from "#enums/biome";
|
||||
import { ExpNotification } from "#enums/exp-notification";
|
||||
import type { ExpNotification } from "#enums/exp-notification";
|
||||
import { MoneyFormat } from "#enums/money-format";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { Species } from "#enums/species";
|
||||
import { UiTheme } from "#enums/ui-theme";
|
||||
import { TimedEventManager } from "#app/timed-event-manager";
|
||||
import { PokemonAnimType } from "#enums/pokemon-anim-type";
|
||||
import type { PokemonAnimType } from "#enums/pokemon-anim-type";
|
||||
import i18next from "i18next";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { battleSpecDialogue } from "#app/data/dialogue";
|
||||
|
@ -92,7 +104,7 @@ import { allMysteryEncounters, ANTI_VARIANCE_WEIGHT_MODIFIER, AVERAGE_ENCOUNTERS
|
|||
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
import { ExpPhase } from "#app/phases/exp-phase";
|
||||
import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
@ -100,6 +112,7 @@ import { ExpGainsSpeed } from "#enums/exp-gains-speed";
|
|||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { initGlobalScene } from "#app/global-scene";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
|
@ -330,6 +343,7 @@ export default class BattleScene extends SceneBase {
|
|||
this.nextCommandPhaseQueue = [];
|
||||
this.eventManager = new TimedEventManager();
|
||||
this.updateGameInfo();
|
||||
initGlobalScene(this);
|
||||
}
|
||||
|
||||
loadPokemonAtlas(key: string, atlasPath: string, experimental?: boolean) {
|
||||
|
@ -349,40 +363,41 @@ export default class BattleScene extends SceneBase {
|
|||
/**
|
||||
* Load the variant assets for the given sprite and stores them in {@linkcode variantColorCache}
|
||||
*/
|
||||
loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant) {
|
||||
public async loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant): Promise<void> {
|
||||
const useExpSprite = this.experimentalSprites && this.hasExpSprite(spriteKey);
|
||||
if (useExpSprite) {
|
||||
fileRoot = `exp/${fileRoot}`;
|
||||
}
|
||||
let variantConfig = variantData;
|
||||
fileRoot.split("/").map(p => variantConfig ? variantConfig = variantConfig[p] : null);
|
||||
fileRoot.split("/").map((p) => (variantConfig ? (variantConfig = variantConfig[p]) : null));
|
||||
const variantSet = variantConfig as VariantSet;
|
||||
if (variantSet && (variant !== undefined && variantSet[variant] === 1)) {
|
||||
const populateVariantColors = (key: string): Promise<void> => {
|
||||
return new Promise(resolve => {
|
||||
if (variantColorCache.hasOwnProperty(key)) {
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
if (variantSet && variant !== undefined && variantSet[variant] === 1) {
|
||||
if (variantColorCache.hasOwnProperty(spriteKey)) {
|
||||
return resolve();
|
||||
}
|
||||
this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`).then(res => res.json()).then(c => {
|
||||
variantColorCache[key] = c;
|
||||
this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`)
|
||||
.then((res) => res.json())
|
||||
.then((c) => {
|
||||
variantColorCache[spriteKey] = c;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
populateVariantColors(spriteKey);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async preload() {
|
||||
if (DEBUG_RNG) {
|
||||
const scene = this;
|
||||
const originalRealInRange = Phaser.Math.RND.realInRange;
|
||||
Phaser.Math.RND.realInRange = function (min: number, max: number): number {
|
||||
const ret = originalRealInRange.apply(this, [ min, max ]);
|
||||
const args = [ "RNG", ++scene.rngCounter, ret / (max - min), `min: ${min} / max: ${max}` ];
|
||||
args.push(`seed: ${scene.rngSeedOverride || scene.waveSeed || scene.seed}`);
|
||||
if (scene.rngOffset) {
|
||||
args.push(`offset: ${scene.rngOffset}`);
|
||||
const args = [ "RNG", ++this.rngCounter, ret / (max - min), `min: ${min} / max: ${max}` ];
|
||||
args.push(`seed: ${this.rngSeedOverride || this.waveSeed || this.seed}`);
|
||||
if (this.rngOffset) {
|
||||
args.push(`offset: ${this.rngOffset}`);
|
||||
}
|
||||
console.log(...args);
|
||||
return ret;
|
||||
|
@ -397,12 +412,12 @@ export default class BattleScene extends SceneBase {
|
|||
create() {
|
||||
this.scene.remove(LoadingScene.KEY);
|
||||
initGameSpeed.apply(this);
|
||||
this.inputController = new InputsController(this);
|
||||
this.uiInputs = new UiInputs(this, this.inputController);
|
||||
this.inputController = new InputsController();
|
||||
this.uiInputs = new UiInputs(this.inputController);
|
||||
|
||||
this.gameData = new GameData(this);
|
||||
this.gameData = new GameData();
|
||||
|
||||
addUiThemeOverrides(this);
|
||||
addUiThemeOverrides();
|
||||
|
||||
this.load.setBaseURL();
|
||||
|
||||
|
@ -489,76 +504,76 @@ export default class BattleScene extends SceneBase {
|
|||
this.modifiers = [];
|
||||
this.enemyModifiers = [];
|
||||
|
||||
this.modifierBar = new ModifierBar(this);
|
||||
this.modifierBar = new ModifierBar();
|
||||
this.modifierBar.setName("modifier-bar");
|
||||
this.add.existing(this.modifierBar);
|
||||
uiContainer.add(this.modifierBar);
|
||||
|
||||
this.enemyModifierBar = new ModifierBar(this, true);
|
||||
this.enemyModifierBar = new ModifierBar(true);
|
||||
this.enemyModifierBar.setName("enemy-modifier-bar");
|
||||
this.add.existing(this.enemyModifierBar);
|
||||
uiContainer.add(this.enemyModifierBar);
|
||||
|
||||
this.charSprite = new CharSprite(this);
|
||||
this.charSprite = new CharSprite();
|
||||
this.charSprite.setName("sprite-char");
|
||||
this.charSprite.setup();
|
||||
|
||||
this.fieldUI.add(this.charSprite);
|
||||
|
||||
this.pbTray = new PokeballTray(this, true);
|
||||
this.pbTray = new PokeballTray(true);
|
||||
this.pbTray.setName("pb-tray");
|
||||
this.pbTray.setup();
|
||||
|
||||
this.pbTrayEnemy = new PokeballTray(this, false);
|
||||
this.pbTrayEnemy = new PokeballTray(false);
|
||||
this.pbTrayEnemy.setName("enemy-pb-tray");
|
||||
this.pbTrayEnemy.setup();
|
||||
|
||||
this.fieldUI.add(this.pbTray);
|
||||
this.fieldUI.add(this.pbTrayEnemy);
|
||||
|
||||
this.abilityBar = new AbilityBar(this);
|
||||
this.abilityBar = new AbilityBar();
|
||||
this.abilityBar.setName("ability-bar");
|
||||
this.abilityBar.setup();
|
||||
this.fieldUI.add(this.abilityBar);
|
||||
|
||||
this.partyExpBar = new PartyExpBar(this);
|
||||
this.partyExpBar = new PartyExpBar();
|
||||
this.partyExpBar.setName("party-exp-bar");
|
||||
this.partyExpBar.setup();
|
||||
this.fieldUI.add(this.partyExpBar);
|
||||
|
||||
this.candyBar = new CandyBar(this);
|
||||
this.candyBar = new CandyBar();
|
||||
this.candyBar.setName("candy-bar");
|
||||
this.candyBar.setup();
|
||||
this.fieldUI.add(this.candyBar);
|
||||
|
||||
this.biomeWaveText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
||||
this.biomeWaveText = addTextObject((this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
||||
this.biomeWaveText.setName("text-biome-wave");
|
||||
this.biomeWaveText.setOrigin(1, 0.5);
|
||||
this.fieldUI.add(this.biomeWaveText);
|
||||
|
||||
this.moneyText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, "", TextStyle.MONEY);
|
||||
this.moneyText = addTextObject((this.game.canvas.width / 6) - 2, 0, "", TextStyle.MONEY);
|
||||
this.moneyText.setName("text-money");
|
||||
this.moneyText.setOrigin(1, 0.5);
|
||||
this.fieldUI.add(this.moneyText);
|
||||
|
||||
this.scoreText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, "", TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.scoreText = addTextObject((this.game.canvas.width / 6) - 2, 0, "", TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.scoreText.setName("text-score");
|
||||
this.scoreText.setOrigin(1, 0.5);
|
||||
this.fieldUI.add(this.scoreText);
|
||||
|
||||
this.luckText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, "", TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.luckText = addTextObject((this.game.canvas.width / 6) - 2, 0, "", TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.luckText.setName("text-luck");
|
||||
this.luckText.setOrigin(1, 0.5);
|
||||
this.luckText.setVisible(false);
|
||||
this.fieldUI.add(this.luckText);
|
||||
|
||||
this.luckLabelText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, i18next.t("common:luckIndicator"), TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.luckLabelText = addTextObject((this.game.canvas.width / 6) - 2, 0, i18next.t("common:luckIndicator"), TextStyle.PARTY, { fontSize: "54px" });
|
||||
this.luckLabelText.setName("text-luck-label");
|
||||
this.luckLabelText.setOrigin(1, 0.5);
|
||||
this.luckLabelText.setVisible(false);
|
||||
this.fieldUI.add(this.luckLabelText);
|
||||
|
||||
this.arenaFlyout = new ArenaFlyout(this);
|
||||
this.arenaFlyout = new ArenaFlyout();
|
||||
this.fieldUI.add(this.arenaFlyout);
|
||||
this.fieldUI.moveBelow<Phaser.GameObjects.GameObject>(this.arenaFlyout, this.fieldOverlay);
|
||||
|
||||
|
@ -567,9 +582,9 @@ export default class BattleScene extends SceneBase {
|
|||
this.damageNumberHandler = new DamageNumberHandler();
|
||||
|
||||
this.spriteSparkleHandler = new PokemonSpriteSparkleHandler();
|
||||
this.spriteSparkleHandler.setup(this);
|
||||
this.spriteSparkleHandler.setup();
|
||||
|
||||
this.pokemonInfoContainer = new PokemonInfoContainer(this, (this.game.canvas.width / 6) + 52, -(this.game.canvas.height / 6) + 66);
|
||||
this.pokemonInfoContainer = new PokemonInfoContainer((this.game.canvas.width / 6) + 52, -(this.game.canvas.height / 6) + 66);
|
||||
this.pokemonInfoContainer.setup();
|
||||
|
||||
this.fieldUI.add(this.pokemonInfoContainer);
|
||||
|
@ -578,13 +593,13 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
const loadPokemonAssets = [];
|
||||
|
||||
this.arenaPlayer = new ArenaBase(this, true);
|
||||
this.arenaPlayer = new ArenaBase(true);
|
||||
this.arenaPlayer.setName("arena-player");
|
||||
this.arenaPlayerTransition = new ArenaBase(this, true);
|
||||
this.arenaPlayerTransition = new ArenaBase(true);
|
||||
this.arenaPlayerTransition.setName("arena-player-transition");
|
||||
this.arenaEnemy = new ArenaBase(this, false);
|
||||
this.arenaEnemy = new ArenaBase(false);
|
||||
this.arenaEnemy.setName("arena-enemy");
|
||||
this.arenaNextEnemy = new ArenaBase(this, false);
|
||||
this.arenaNextEnemy = new ArenaBase(false);
|
||||
this.arenaNextEnemy.setName("arena-next-enemy");
|
||||
|
||||
this.arenaBgTransition.setVisible(false);
|
||||
|
@ -625,7 +640,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
this.reset(false, false, true);
|
||||
|
||||
const ui = new UI(this);
|
||||
const ui = new UI();
|
||||
this.uiContainer.add(ui);
|
||||
|
||||
this.ui = ui;
|
||||
|
@ -636,12 +651,12 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
Promise.all([
|
||||
Promise.all(loadPokemonAssets),
|
||||
initCommonAnims(this).then(() => loadCommonAnimAssets(this, true)),
|
||||
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(this, m))).then(() => loadMoveAnimAssets(this, defaultMoves, true)),
|
||||
initCommonAnims().then(() => loadCommonAnimAssets(true)),
|
||||
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(m))).then(() => loadMoveAnimAssets(defaultMoves, true)),
|
||||
this.initStarterColors()
|
||||
]).then(() => {
|
||||
this.pushPhase(new LoginPhase(this));
|
||||
this.pushPhase(new TitlePhase(this));
|
||||
this.pushPhase(new LoginPhase());
|
||||
this.pushPhase(new TitlePhase());
|
||||
|
||||
this.shiftPhase();
|
||||
});
|
||||
|
@ -911,7 +926,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon {
|
||||
const pokemon = new PlayerPokemon(this, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
||||
const pokemon = new PlayerPokemon(species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
||||
if (postProcess) {
|
||||
postProcess(pokemon);
|
||||
}
|
||||
|
@ -929,7 +944,7 @@ export default class BattleScene extends SceneBase {
|
|||
boss = this.getEncounterBossSegments(this.currentBattle.waveIndex, level, species) > 1;
|
||||
}
|
||||
|
||||
const pokemon = new EnemyPokemon(this, species, level, trainerSlot, boss, shinyLock, dataSource);
|
||||
const pokemon = new EnemyPokemon(species, level, trainerSlot, boss, shinyLock, dataSource);
|
||||
if (Overrides.OPP_FUSION_OVERRIDE) {
|
||||
pokemon.generateFusionSpecies();
|
||||
}
|
||||
|
@ -1064,7 +1079,7 @@ export default class BattleScene extends SceneBase {
|
|||
/**
|
||||
* Generates a random number using the current battle's seed
|
||||
*
|
||||
* This calls {@linkcode Battle.randSeedInt}(`scene`, {@linkcode range}, {@linkcode min}) in `src/battle.ts`
|
||||
* This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts`
|
||||
* which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`
|
||||
*
|
||||
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
|
||||
|
@ -1072,12 +1087,12 @@ export default class BattleScene extends SceneBase {
|
|||
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||
*/
|
||||
randBattleSeedInt(range: integer, min: integer = 0): integer {
|
||||
return this.currentBattle?.randSeedInt(this, range, min);
|
||||
return this.currentBattle?.randSeedInt(range, min);
|
||||
}
|
||||
|
||||
reset(clearScene: boolean = false, clearData: boolean = false, reloadI18n: boolean = false): void {
|
||||
if (clearData) {
|
||||
this.gameData = new GameData(this);
|
||||
this.gameData = new GameData();
|
||||
}
|
||||
|
||||
this.gameMode = getGameMode(GameModes.CLASSIC);
|
||||
|
@ -1178,6 +1193,9 @@ export default class BattleScene extends SceneBase {
|
|||
onComplete: () => {
|
||||
this.clearPhaseQueue();
|
||||
|
||||
this.ui.freeUIData();
|
||||
this.uiContainer.remove(this.ui, true);
|
||||
this.uiContainer.destroy();
|
||||
this.children.removeAll(true);
|
||||
this.game.domContainer.innerHTML = "";
|
||||
this.launchBattle();
|
||||
|
@ -1210,7 +1228,7 @@ export default class BattleScene extends SceneBase {
|
|||
battleConfig = this.gameMode.getFixedBattle(newWaveIndex);
|
||||
newDouble = battleConfig.double;
|
||||
newBattleType = battleConfig.battleType;
|
||||
this.executeWithSeedOffset(() => newTrainer = battleConfig?.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8);
|
||||
this.executeWithSeedOffset(() => newTrainer = battleConfig?.getTrainer(), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8);
|
||||
if (newTrainer) {
|
||||
this.field.add(newTrainer);
|
||||
}
|
||||
|
@ -1236,7 +1254,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
}
|
||||
const variant = doubleTrainer ? TrainerVariant.DOUBLE : (Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, variant);
|
||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant);
|
||||
this.field.add(newTrainer);
|
||||
}
|
||||
|
||||
|
@ -1314,7 +1332,7 @@ export default class BattleScene extends SceneBase {
|
|||
this.executeWithSeedOffset(() => {
|
||||
this.currentBattle = new Battle(this.gameMode, newWaveIndex, newBattleType, newTrainer, newDouble);
|
||||
}, newWaveIndex << 3, this.waveSeed);
|
||||
this.currentBattle.incrementTurn(this);
|
||||
this.currentBattle.incrementTurn();
|
||||
|
||||
if (newBattleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
// Will generate the actual Mystery Encounter during NextEncounterPhase, to ensure it uses proper biome
|
||||
|
@ -1342,7 +1360,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
playerField.forEach((pokemon, p) => {
|
||||
if (pokemon.isOnField()) {
|
||||
this.pushPhase(new ReturnPhase(this, p));
|
||||
this.pushPhase(new ReturnPhase(p));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1352,7 +1370,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
if (!this.trainer.visible) {
|
||||
this.pushPhase(new ShowTrainerPhase(this));
|
||||
this.pushPhase(new ShowTrainerPhase());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1361,14 +1379,14 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
|
||||
this.pushPhase(new NextEncounterPhase(this));
|
||||
this.pushPhase(new NextEncounterPhase());
|
||||
} else {
|
||||
this.pushPhase(new SelectBiomePhase(this));
|
||||
this.pushPhase(new NewBiomeEncounterPhase(this));
|
||||
this.pushPhase(new SelectBiomePhase());
|
||||
this.pushPhase(new NewBiomeEncounterPhase());
|
||||
|
||||
const newMaxExpLevel = this.getMaxExpLevel();
|
||||
if (newMaxExpLevel > maxExpLevel) {
|
||||
this.pushPhase(new LevelCapPhase(this));
|
||||
this.pushPhase(new LevelCapPhase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1377,7 +1395,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
newArena(biome: Biome): Arena {
|
||||
this.arena = new Arena(this, biome, Biome[biome].toLowerCase());
|
||||
this.arena = new Arena(biome, Biome[biome].toLowerCase());
|
||||
this.eventTarget.dispatchEvent(new NewArenaEvent());
|
||||
|
||||
this.arenaBg.pipelineData = { terrainColorRatio: this.arena.getBgTerrainColorRatioForBiome() };
|
||||
|
@ -1424,6 +1442,8 @@ export default class BattleScene extends SceneBase {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const isEggPhase: boolean = [ "EggLapsePhase", "EggHatchPhase" ].includes(this.getCurrentPhase()?.constructor.name ?? "");
|
||||
|
||||
switch (species.speciesId) {
|
||||
case Species.UNOWN:
|
||||
case Species.SHELLOS:
|
||||
|
@ -1455,7 +1475,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
return Utils.randSeedInt(8);
|
||||
case Species.EEVEE:
|
||||
if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) {
|
||||
if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30 && !isEggPhase) {
|
||||
return 0; // No Partner Eevee for Wave 12 Preschoolers
|
||||
}
|
||||
return Utils.randSeedInt(2);
|
||||
|
@ -1483,7 +1503,7 @@ export default class BattleScene extends SceneBase {
|
|||
return 0;
|
||||
case Species.GIMMIGHOUL:
|
||||
// Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs
|
||||
if (this.gameMode.hasMysteryEncounters) {
|
||||
if (this.gameMode.hasMysteryEncounters && !isEggPhase) {
|
||||
return 1; // Wandering form
|
||||
} else {
|
||||
return Utils.randSeedInt(species.forms.length);
|
||||
|
@ -1791,7 +1811,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
updateUIPositions(): void {
|
||||
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible(this)).length;
|
||||
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible()).length;
|
||||
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
|
||||
this.biomeWaveText.setY(
|
||||
-(this.game.canvas.height / 6) + (enemyModifierCount ? enemyModifierCount <= 12 ? 15 : 24 : 0) + (biomeWaveTextHeight / 2)
|
||||
|
@ -1823,8 +1843,10 @@ export default class BattleScene extends SceneBase {
|
|||
this.currentBattle.battleScore += Math.ceil(scoreIncrease);
|
||||
}
|
||||
|
||||
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
|
||||
if (ignoreLevelCap) {
|
||||
getMaxExpLevel(ignoreLevelCap: boolean = false): integer {
|
||||
if (Overrides.LEVEL_CAP_OVERRIDE > 0) {
|
||||
return Overrides.LEVEL_CAP_OVERRIDE;
|
||||
} else if (ignoreLevelCap || Overrides.LEVEL_CAP_OVERRIDE < 0) {
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
const waveIndex = Math.ceil((this.currentBattle?.waveIndex || 1) / 10) * 10;
|
||||
|
@ -1850,7 +1872,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
generateRandomBiome(waveIndex: integer): Biome {
|
||||
const relWave = waveIndex % 250;
|
||||
const biomes = Utils.getEnumValues(Biome).slice(1, Utils.getEnumValues(Biome).filter(b => b >= 40).length * -1);
|
||||
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
|
||||
const maxDepth = biomeDepths[Biome.END][0] - 2;
|
||||
const depthWeights = new Array(maxDepth + 1).fill(null)
|
||||
.map((_, i: integer) => ((1 - Math.min(Math.abs((i / (maxDepth - 1)) - (relWave / 250)) + 0.25, 1)) / 0.75) * 250);
|
||||
|
@ -1863,9 +1885,9 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
const randInt = Utils.randSeedInt(totalWeight);
|
||||
|
||||
for (const biome of biomes) {
|
||||
if (randInt < biomeThresholds[biome]) {
|
||||
return biome;
|
||||
for (let i = 0; i < biomes.length; i++) {
|
||||
if (randInt < biomeThresholds[i]) {
|
||||
return biomes[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1878,7 +1900,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
playBgm(bgmName?: string, fadeOut?: boolean): void {
|
||||
if (bgmName === undefined) {
|
||||
bgmName = this.currentBattle?.getBgmOverride(this) || this.arena?.bgm;
|
||||
bgmName = this.currentBattle?.getBgmOverride() || this.arena?.bgm;
|
||||
}
|
||||
if (this.bgm && bgmName === this.bgm.key) {
|
||||
if (!this.bgm.isPlaying) {
|
||||
|
@ -2497,7 +2519,7 @@ export default class BattleScene extends SceneBase {
|
|||
* @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue
|
||||
*/
|
||||
queueMessage(message: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null, defer?: boolean | null) {
|
||||
const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay);
|
||||
const phase = new MessagePhase(message, callbackDelay, prompt, promptDelay);
|
||||
if (!defer) {
|
||||
// adds to the end of PhaseQueuePrepend
|
||||
this.unshiftPhase(phase);
|
||||
|
@ -2515,7 +2537,7 @@ export default class BattleScene extends SceneBase {
|
|||
this.phaseQueue.push(...this.nextCommandPhaseQueue);
|
||||
this.nextCommandPhaseQueue.splice(0, this.nextCommandPhaseQueue.length);
|
||||
}
|
||||
this.phaseQueue.push(new TurnInitPhase(this));
|
||||
this.phaseQueue.push(new TurnInitPhase());
|
||||
}
|
||||
|
||||
addMoney(amount: integer): void {
|
||||
|
@ -2546,7 +2568,7 @@ export default class BattleScene extends SceneBase {
|
|||
if (modifier instanceof TerastallizeModifier) {
|
||||
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId)));
|
||||
}
|
||||
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) {
|
||||
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual)) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
|
||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
||||
if (pokemon) {
|
||||
|
@ -2627,7 +2649,7 @@ export default class BattleScene extends SceneBase {
|
|||
if (modifier instanceof TerastallizeModifier) {
|
||||
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId, false)));
|
||||
}
|
||||
if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) {
|
||||
if ((modifier as PersistentModifier).add(this.enemyModifiers, false)) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
|
||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
||||
if (pokemon) {
|
||||
|
@ -2662,7 +2684,7 @@ export default class BattleScene extends SceneBase {
|
|||
*/
|
||||
tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, playSound: boolean, transferQuantity: number = 1, instant?: boolean, ignoreUpdate?: boolean, itemLost: boolean = true): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null;
|
||||
const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null;
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => {
|
||||
if (cancelled.value) {
|
||||
|
@ -2670,11 +2692,11 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
|
||||
newItemModifier.pokemonId = target.id;
|
||||
const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier
|
||||
const matchingModifier = this.findModifier(m => m instanceof PokemonHeldItemModifier
|
||||
&& (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier;
|
||||
let removeOld = true;
|
||||
if (matchingModifier) {
|
||||
const maxStackCount = matchingModifier.getMaxStackCount(target.scene);
|
||||
const maxStackCount = matchingModifier.getMaxStackCount();
|
||||
if (matchingModifier.stackCount >= maxStackCount) {
|
||||
return resolve(false);
|
||||
}
|
||||
|
@ -2791,7 +2813,7 @@ export default class BattleScene extends SceneBase {
|
|||
count = Math.max(count, Math.floor(chances / 2));
|
||||
}
|
||||
getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance)
|
||||
.map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
|
||||
.map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
@ -2815,7 +2837,7 @@ export default class BattleScene extends SceneBase {
|
|||
* @param pokemon - If specified, only removes held items from that {@linkcode Pokemon}
|
||||
*/
|
||||
clearEnemyHeldItemModifiers(pokemon?: Pokemon): void {
|
||||
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PokemonHeldItemModifier && (!pokemon || m.getPokemon(this) === pokemon));
|
||||
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PokemonHeldItemModifier && (!pokemon || m.getPokemon() === pokemon));
|
||||
for (const m of modifiersToRemove) {
|
||||
this.enemyModifiers.splice(this.enemyModifiers.indexOf(m), 1);
|
||||
}
|
||||
|
@ -2864,9 +2886,7 @@ export default class BattleScene extends SceneBase {
|
|||
updatePartyForModifiers(party: Pokemon[], instant?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
Promise.allSettled(party.map(p => {
|
||||
if (p.scene) {
|
||||
p.calculateStats();
|
||||
}
|
||||
return p.updateInfo(instant);
|
||||
})).then(() => resolve());
|
||||
});
|
||||
|
@ -2929,15 +2949,14 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
/**
|
||||
* Apply all modifiers that match `modifierType` in a random order
|
||||
* @param scene {@linkcode BattleScene} used to randomize the order of modifiers
|
||||
* @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`
|
||||
* @param ...args The list of arguments needed to invoke `modifierType.apply`
|
||||
* @returns the list of all modifiers that matched `modifierType` and were applied.
|
||||
*/
|
||||
applyShuffledModifiers<T extends PersistentModifier>(scene: BattleScene, modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T[] {
|
||||
applyShuffledModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T[] {
|
||||
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args));
|
||||
scene.executeWithSeedOffset(() => {
|
||||
this.executeWithSeedOffset(() => {
|
||||
const shuffleModifiers = mods => {
|
||||
if (mods.length < 1) {
|
||||
return mods;
|
||||
|
@ -2946,7 +2965,7 @@ export default class BattleScene extends SceneBase {
|
|||
return [ mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand)) ];
|
||||
};
|
||||
modifiers = shuffleModifiers(modifiers);
|
||||
}, scene.currentBattle.turn << 4, scene.waveSeed);
|
||||
}, this.currentBattle.turn << 4, this.waveSeed);
|
||||
return this.applyModifiersInternal(modifiers, player, args);
|
||||
}
|
||||
|
||||
|
@ -3016,9 +3035,9 @@ export default class BattleScene extends SceneBase {
|
|||
if (matchingFormChange) {
|
||||
let phase: Phase;
|
||||
if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet) {
|
||||
phase = new FormChangePhase(this, pokemon, matchingFormChange, modal);
|
||||
phase = new FormChangePhase(pokemon, matchingFormChange, modal);
|
||||
} else {
|
||||
phase = new QuietFormChangePhase(this, pokemon, matchingFormChange);
|
||||
phase = new QuietFormChangePhase(pokemon, matchingFormChange);
|
||||
}
|
||||
if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet && modal) {
|
||||
this.overridePhase(phase);
|
||||
|
@ -3035,7 +3054,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
triggerPokemonBattleAnim(pokemon: Pokemon, battleAnimType: PokemonAnimType, fieldAssets?: Phaser.GameObjects.Sprite[], delayed: boolean = false): boolean {
|
||||
const phase: Phase = new PokemonAnimPhase(this, battleAnimType, pokemon, fieldAssets);
|
||||
const phase: Phase = new PokemonAnimPhase(battleAnimType, pokemon, fieldAssets);
|
||||
if (delayed) {
|
||||
this.pushPhase(phase);
|
||||
} else {
|
||||
|
@ -3053,7 +3072,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
validateAchv(achv: Achv, args?: unknown[]): boolean {
|
||||
if ((!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE)
|
||||
&& achv.validate(this, args)) {
|
||||
&& achv.validate(args)) {
|
||||
this.gameData.achvUnlocks[achv.id] = new Date().getTime();
|
||||
this.ui.achvBar.showAchv(achv);
|
||||
if (vouchers.hasOwnProperty(achv.id)) {
|
||||
|
@ -3066,7 +3085,7 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
validateVoucher(voucher: Voucher, args?: unknown[]): boolean {
|
||||
if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) {
|
||||
if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(args)) {
|
||||
this.gameData.voucherUnlocks[voucher.id] = new Date().getTime();
|
||||
this.ui.achvBar.showAchv(voucher);
|
||||
this.gameData.voucherCounts[voucher.voucherType]++;
|
||||
|
@ -3139,9 +3158,9 @@ export default class BattleScene extends SceneBase {
|
|||
this.currentBattle.double = true;
|
||||
const availablePartyMembers = this.getPlayerParty().filter((p) => p.isAllowedInBattle());
|
||||
if (availablePartyMembers.length > 1) {
|
||||
this.pushPhase(new ToggleDoublePositionPhase(this, true));
|
||||
this.pushPhase(new ToggleDoublePositionPhase(true));
|
||||
if (!availablePartyMembers[1].isOnField()) {
|
||||
this.pushPhase(new SummonPhase(this, 1));
|
||||
this.pushPhase(new SummonPhase(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3186,7 +3205,7 @@ export default class BattleScene extends SceneBase {
|
|||
if (participated && pokemonDefeated) {
|
||||
partyMember.addFriendship(FRIENDSHIP_GAIN_FROM_BATTLE);
|
||||
const machoBraceModifier = partyMember.getHeldItems().find(m => m instanceof PokemonIncrementingStatModifier);
|
||||
if (machoBraceModifier && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount(this)) {
|
||||
if (machoBraceModifier && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount()) {
|
||||
machoBraceModifier.stackCount++;
|
||||
this.updateModifiers(true, true);
|
||||
partyMember.updateInfo();
|
||||
|
@ -3248,7 +3267,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
if (exp) {
|
||||
const partyMemberIndex = party.indexOf(expPartyMembers[pm]);
|
||||
this.unshiftPhase(expPartyMembers[pm].isOnField() ? new ExpPhase(this, partyMemberIndex, exp) : new ShowPartyExpBarPhase(this, partyMemberIndex, exp));
|
||||
this.unshiftPhase(expPartyMembers[pm].isOnField() ? new ExpPhase(partyMemberIndex, exp) : new ShowPartyExpBarPhase(partyMemberIndex, exp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3340,7 +3359,7 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
if (encounter) {
|
||||
encounter = new MysteryEncounter(encounter);
|
||||
encounter.populateDialogueTokensFromRequirements(this);
|
||||
encounter.populateDialogueTokensFromRequirements();
|
||||
return encounter;
|
||||
}
|
||||
|
||||
|
@ -3368,9 +3387,11 @@ export default class BattleScene extends SceneBase {
|
|||
}
|
||||
|
||||
let availableEncounters: MysteryEncounter[] = [];
|
||||
// New encounter should never be the same as the most recent encounter
|
||||
const previousEncounter = this.mysteryEncounterSaveData.encounteredEvents.length > 0 ? this.mysteryEncounterSaveData.encounteredEvents[this.mysteryEncounterSaveData.encounteredEvents.length - 1].type : null;
|
||||
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType) ?? [];
|
||||
const previousEncounter = this.mysteryEncounterSaveData.encounteredEvents.length > 0 ?
|
||||
this.mysteryEncounterSaveData.encounteredEvents[this.mysteryEncounterSaveData.encounteredEvents.length - 1].type
|
||||
: null;
|
||||
const disabledEncounters = this.eventManager.getEventMysteryEncountersDisabled();
|
||||
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType)?.filter(enc => !disabledEncounters.includes(enc)) ?? [];
|
||||
// If no valid encounters exist at tier, checks next tier down, continuing until there are some encounters available
|
||||
while (availableEncounters.length === 0 && tier !== null) {
|
||||
availableEncounters = biomeMysteryEncounters
|
||||
|
@ -3379,27 +3400,27 @@ export default class BattleScene extends SceneBase {
|
|||
if (!encounterCandidate) {
|
||||
return false;
|
||||
}
|
||||
if (encounterCandidate.encounterTier !== tier) { // Encounter is in tier
|
||||
if (this.eventManager.getMysteryEncounterTierForEvent(encounterType, encounterCandidate.encounterTier) !== tier) {
|
||||
return false;
|
||||
}
|
||||
const disallowedGameModes = encounterCandidate.disallowedGameModes;
|
||||
if (disallowedGameModes && disallowedGameModes.length > 0
|
||||
&& disallowedGameModes.includes(this.gameMode.modeId)) { // Encounter is enabled for game mode
|
||||
&& disallowedGameModes.includes(this.gameMode.modeId)) {
|
||||
return false;
|
||||
}
|
||||
if (this.gameMode.modeId === GameModes.CHALLENGE) { // Encounter is enabled for challenges
|
||||
if (this.gameMode.modeId === GameModes.CHALLENGE) {
|
||||
const disallowedChallenges = encounterCandidate.disallowedChallenges;
|
||||
if (disallowedChallenges && disallowedChallenges.length > 0 && this.gameMode.challenges.some(challenge => disallowedChallenges.includes(challenge.id))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!encounterCandidate.meetsRequirements(this)) { // Meets encounter requirements
|
||||
if (!encounterCandidate.meetsRequirements()) {
|
||||
return false;
|
||||
}
|
||||
if (previousEncounter !== null && encounterType === previousEncounter) { // Previous encounter was not this one
|
||||
if (previousEncounter !== null && encounterType === previousEncounter) {
|
||||
return false;
|
||||
}
|
||||
if (this.mysteryEncounterSaveData.encounteredEvents.length > 0 && // Encounter has not exceeded max allowed encounters
|
||||
if (this.mysteryEncounterSaveData.encounteredEvents.length > 0 &&
|
||||
(encounterCandidate.maxAllowedEncounters && encounterCandidate.maxAllowedEncounters > 0)
|
||||
&& this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length >= encounterCandidate.maxAllowedEncounters) {
|
||||
return false;
|
||||
|
@ -3427,7 +3448,7 @@ export default class BattleScene extends SceneBase {
|
|||
encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)];
|
||||
// New encounter object to not dirty flags
|
||||
encounter = new MysteryEncounter(encounter);
|
||||
encounter.populateDialogueTokensFromRequirements(this);
|
||||
encounter.populateDialogueTokensFromRequirements();
|
||||
return encounter;
|
||||
}
|
||||
}
|
||||
|
|
172
src/battle.ts
|
@ -1,31 +1,49 @@
|
|||
import BattleScene from "./battle-scene";
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { Command } from "./ui/command-ui-handler";
|
||||
import * as Utils from "./utils";
|
||||
import Trainer, { TrainerVariant } from "./field/trainer";
|
||||
import { GameMode } from "./game-mode";
|
||||
import type { GameMode } from "./game-mode";
|
||||
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import type { PokeballType } from "#enums/pokeball";
|
||||
import { trainerConfigs } from "#app/data/trainer-config";
|
||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon, QueuedMove } from "#app/field/pokemon";
|
||||
import type { EnemyPokemon, PlayerPokemon, TurnMove } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { BattleSpec } from "#enums/battle-spec";
|
||||
import { Moves } from "#enums/moves";
|
||||
import type { Moves } from "#enums/moves";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { MusicPreference } from "#app/system/settings/settings";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { CustomModifierSettings } from "#app/modifier/modifier-type";
|
||||
import type { CustomModifierSettings } from "#app/modifier/modifier-type";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
|
||||
export enum ClassicFixedBossWaves {
|
||||
// TODO: other fixed wave battles should be added here
|
||||
TOWN_YOUNGSTER = 5,
|
||||
RIVAL_1 = 8,
|
||||
RIVAL_2 = 25,
|
||||
EVIL_GRUNT_1 = 35,
|
||||
RIVAL_3 = 55,
|
||||
EVIL_GRUNT_2 = 62,
|
||||
EVIL_GRUNT_3 = 64,
|
||||
EVIL_ADMIN_1 = 66,
|
||||
RIVAL_4 = 95,
|
||||
EVIL_GRUNT_4 = 112,
|
||||
EVIL_ADMIN_2 = 114,
|
||||
EVIL_BOSS_1 = 115,
|
||||
RIVAL_5 = 145,
|
||||
EVIL_BOSS_2 = 165,
|
||||
ELITE_FOUR_1 = 182,
|
||||
ELITE_FOUR_2 = 184,
|
||||
ELITE_FOUR_3 = 186,
|
||||
ELITE_FOUR_4 = 188,
|
||||
CHAMPION = 190,
|
||||
RIVAL_6 = 195,
|
||||
}
|
||||
|
||||
export enum BattleType {
|
||||
|
@ -46,7 +64,7 @@ export enum BattlerIndex {
|
|||
export interface TurnCommand {
|
||||
command: Command;
|
||||
cursor?: number;
|
||||
move?: QueuedMove;
|
||||
move?: TurnMove;
|
||||
targets?: BattlerIndex[];
|
||||
skip?: boolean;
|
||||
args?: any[];
|
||||
|
@ -154,7 +172,7 @@ export default class Battle {
|
|||
return this.double ? 2 : 1;
|
||||
}
|
||||
|
||||
incrementTurn(scene: BattleScene): void {
|
||||
incrementTurn(): void {
|
||||
this.turn++;
|
||||
this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [ bt, null ]));
|
||||
this.battleSeedState = null;
|
||||
|
@ -169,7 +187,7 @@ export default class Battle {
|
|||
}
|
||||
|
||||
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
|
||||
this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable, false).map(i => {
|
||||
this.postBattleLoot.push(...globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable, false).map(i => {
|
||||
const ret = i as PokemonHeldItemModifier;
|
||||
//@ts-ignore - this is awful to fix/change
|
||||
ret.pokemonId = null;
|
||||
|
@ -177,43 +195,43 @@ export default class Battle {
|
|||
}));
|
||||
}
|
||||
|
||||
pickUpScatteredMoney(scene: BattleScene): void {
|
||||
const moneyAmount = new Utils.IntegerHolder(scene.currentBattle.moneyScattered);
|
||||
scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
||||
pickUpScatteredMoney(): void {
|
||||
const moneyAmount = new Utils.IntegerHolder(globalScene.currentBattle.moneyScattered);
|
||||
globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
||||
|
||||
if (scene.arena.getTag(ArenaTagType.HAPPY_HOUR)) {
|
||||
if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) {
|
||||
moneyAmount.value *= 2;
|
||||
}
|
||||
|
||||
scene.addMoney(moneyAmount.value);
|
||||
globalScene.addMoney(moneyAmount.value);
|
||||
|
||||
const userLocale = navigator.language || "en-US";
|
||||
const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale);
|
||||
const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount });
|
||||
scene.queueMessage(message, undefined, true);
|
||||
globalScene.queueMessage(message, undefined, true);
|
||||
|
||||
scene.currentBattle.moneyScattered = 0;
|
||||
globalScene.currentBattle.moneyScattered = 0;
|
||||
}
|
||||
|
||||
addBattleScore(scene: BattleScene): void {
|
||||
let partyMemberTurnMultiplier = scene.getEnemyParty().length / 2 + 0.5;
|
||||
addBattleScore(): void {
|
||||
let partyMemberTurnMultiplier = globalScene.getEnemyParty().length / 2 + 0.5;
|
||||
if (this.double) {
|
||||
partyMemberTurnMultiplier /= 1.5;
|
||||
}
|
||||
for (const p of scene.getEnemyParty()) {
|
||||
for (const p of globalScene.getEnemyParty()) {
|
||||
if (p.isBoss()) {
|
||||
partyMemberTurnMultiplier *= (p.bossSegments / 1.5) / scene.getEnemyParty().length;
|
||||
partyMemberTurnMultiplier *= (p.bossSegments / 1.5) / globalScene.getEnemyParty().length;
|
||||
}
|
||||
}
|
||||
const turnMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")(1 - Math.min(this.turn - 2, 10 * partyMemberTurnMultiplier) / (10 * partyMemberTurnMultiplier));
|
||||
const finalBattleScore = Math.ceil(this.battleScore * turnMultiplier);
|
||||
scene.score += finalBattleScore;
|
||||
globalScene.score += finalBattleScore;
|
||||
console.log(`Battle Score: ${finalBattleScore} (${this.turn - 1} Turns x${Math.floor(turnMultiplier * 100) / 100})`);
|
||||
console.log(`Total Score: ${scene.score}`);
|
||||
scene.updateScoreText();
|
||||
console.log(`Total Score: ${globalScene.score}`);
|
||||
globalScene.updateScoreText();
|
||||
}
|
||||
|
||||
getBgmOverride(scene: BattleScene): string | null {
|
||||
getBgmOverride(): string | null {
|
||||
if (this.isBattleMysteryEncounter() && this.mysteryEncounter?.encounterMode === MysteryEncounterMode.DEFAULT) {
|
||||
// Music is overridden for MEs during ME onInit()
|
||||
// Should not use any BGM overrides before swapping from DEFAULT mode
|
||||
|
@ -222,7 +240,7 @@ export default class Battle {
|
|||
if (!this.started && this.trainer?.config.encounterBgm && this.trainer?.getEncounterMessages()?.length) {
|
||||
return `encounter_${this.trainer?.getEncounterBgm()}`;
|
||||
}
|
||||
if (scene.musicPreference === MusicPreference.GENFIVE) {
|
||||
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
|
||||
return this.trainer?.getBattleBgm() ?? null;
|
||||
} else {
|
||||
return this.trainer?.getMixedBattleBgm() ?? null;
|
||||
|
@ -230,7 +248,7 @@ export default class Battle {
|
|||
} else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) {
|
||||
return "end_summit";
|
||||
}
|
||||
const wildOpponents = scene.getEnemyParty();
|
||||
const wildOpponents = globalScene.getEnemyParty();
|
||||
for (const pokemon of wildOpponents) {
|
||||
if (this.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||
if (pokemon.species.getFormSpriteKey(pokemon.formIndex) === SpeciesFormKey.ETERNAMAX) {
|
||||
|
@ -239,7 +257,7 @@ export default class Battle {
|
|||
return "battle_final_encounter";
|
||||
}
|
||||
if (pokemon.species.legendary || pokemon.species.subLegendary || pokemon.species.mythical) {
|
||||
if (scene.musicPreference === MusicPreference.GENFIVE) {
|
||||
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
|
||||
switch (pokemon.species.speciesId) {
|
||||
case Species.REGIROCK:
|
||||
case Species.REGICE:
|
||||
|
@ -256,7 +274,7 @@ export default class Battle {
|
|||
}
|
||||
return "battle_legendary_unova";
|
||||
}
|
||||
} else if (scene.musicPreference === MusicPreference.ALLGENS) {
|
||||
} else if (globalScene.musicPreference === MusicPreference.ALLGENS) {
|
||||
switch (pokemon.species.speciesId) {
|
||||
case Species.ARTICUNO:
|
||||
case Species.ZAPDOS:
|
||||
|
@ -396,7 +414,7 @@ export default class Battle {
|
|||
}
|
||||
}
|
||||
|
||||
if (scene.gameMode.isClassic && this.waveIndex <= 4) {
|
||||
if (globalScene.gameMode.isClassic && this.waveIndex <= 4) {
|
||||
return "battle_wild";
|
||||
}
|
||||
|
||||
|
@ -409,12 +427,12 @@ export default class Battle {
|
|||
* @param min The minimum integer to pick, default `0`
|
||||
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||
*/
|
||||
randSeedInt(scene: BattleScene, range: number, min: number = 0): number {
|
||||
randSeedInt(range: number, min: number = 0): number {
|
||||
if (range <= 1) {
|
||||
return min;
|
||||
}
|
||||
const tempRngCounter = scene.rngCounter;
|
||||
const tempSeedOverride = scene.rngSeedOverride;
|
||||
const tempRngCounter = globalScene.rngCounter;
|
||||
const tempSeedOverride = globalScene.rngSeedOverride;
|
||||
const state = Phaser.Math.RND.state();
|
||||
if (this.battleSeedState) {
|
||||
Phaser.Math.RND.state(this.battleSeedState);
|
||||
|
@ -422,13 +440,13 @@ export default class Battle {
|
|||
Phaser.Math.RND.sow([ Utils.shiftCharCodes(this.battleSeed, this.turn << 6) ]);
|
||||
console.log("Battle Seed:", this.battleSeed);
|
||||
}
|
||||
scene.rngCounter = this.rngCounter++;
|
||||
scene.rngSeedOverride = this.battleSeed;
|
||||
globalScene.rngCounter = this.rngCounter++;
|
||||
globalScene.rngSeedOverride = this.battleSeed;
|
||||
const ret = Utils.randSeedInt(range, min);
|
||||
this.battleSeedState = Phaser.Math.RND.state();
|
||||
Phaser.Math.RND.state(state);
|
||||
scene.rngCounter = tempRngCounter;
|
||||
scene.rngSeedOverride = tempSeedOverride;
|
||||
globalScene.rngCounter = tempRngCounter;
|
||||
globalScene.rngSeedOverride = tempSeedOverride;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -441,16 +459,16 @@ export default class Battle {
|
|||
}
|
||||
|
||||
export class FixedBattle extends Battle {
|
||||
constructor(scene: BattleScene, waveIndex: number, config: FixedBattleConfig) {
|
||||
super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : undefined, config.double);
|
||||
constructor(waveIndex: number, config: FixedBattleConfig) {
|
||||
super(globalScene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer() : undefined, config.double);
|
||||
if (config.getEnemyParty) {
|
||||
this.enemyParty = config.getEnemyParty(scene);
|
||||
this.enemyParty = config.getEnemyParty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type GetTrainerFunc = (scene: BattleScene) => Trainer;
|
||||
type GetEnemyPartyFunc = (scene: BattleScene) => EnemyPokemon[];
|
||||
type GetTrainerFunc = () => Trainer;
|
||||
type GetEnemyPartyFunc = () => EnemyPokemon[];
|
||||
|
||||
export class FixedBattleConfig {
|
||||
public battleType: BattleType;
|
||||
|
@ -499,12 +517,12 @@ export class FixedBattleConfig {
|
|||
* @param seedOffset the seed offset to use for the random generation of the trainer
|
||||
* @returns the generated trainer
|
||||
*/
|
||||
function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc {
|
||||
return (scene: BattleScene) => {
|
||||
export function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc {
|
||||
return () => {
|
||||
const rand = Utils.randSeedInt(trainerPool.length);
|
||||
const trainerTypes: TrainerType[] = [];
|
||||
|
||||
scene.executeWithSeedOffset(() => {
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
for (const trainerPoolEntry of trainerPool) {
|
||||
const trainerType = Array.isArray(trainerPoolEntry)
|
||||
? Utils.randSeedItem(trainerPoolEntry)
|
||||
|
@ -523,10 +541,10 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
|||
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
|
||||
|
||||
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
|
||||
return new Trainer(scene, trainerTypes[rand], (Utils.randInt(3) === 0) ? TrainerVariant.DOUBLE : trainerGender);
|
||||
return new Trainer(trainerTypes[rand], (Utils.randInt(3) === 0) ? TrainerVariant.DOUBLE : trainerGender);
|
||||
}
|
||||
|
||||
return new Trainer(scene, trainerTypes[rand], trainerGender);
|
||||
return new Trainer(trainerTypes[rand], trainerGender);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -543,51 +561,51 @@ export interface FixedBattleConfigs {
|
|||
* Champion on 190
|
||||
*/
|
||||
export const classicFixedBattles: FixedBattleConfigs = {
|
||||
[5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[8]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[ClassicFixedBossWaves.RIVAL_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_2, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
|
||||
[35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_1]: 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, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
|
||||
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
[ClassicFixedBossWaves.RIVAL_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_3, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
|
||||
[62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
|
||||
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
|
||||
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]], true)),
|
||||
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
[ClassicFixedBossWaves.RIVAL_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_4, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
|
||||
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT, TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT, TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT ], true)),
|
||||
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]], true, 1)),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE, TrainerType.LUSAMINE, TrainerType.GUZMA, TrainerType.ROSE, TrainerType.PENNY ]))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
|
||||
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
[ClassicFixedBossWaves.RIVAL_5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_5, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2, TrainerType.LUSAMINE_2, TrainerType.GUZMA_2, TrainerType.ROSE_2, TrainerType.PENNY_2 ]))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
|
||||
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_1]: 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 ])),
|
||||
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY, TrainerType.AMARYS ])),
|
||||
[186]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_3]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, [ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ], TrainerType.LARRY_ELITE, TrainerType.LACEY ])),
|
||||
[188]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_4]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL, TrainerType.DRAYTON ])),
|
||||
[190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
|
||||
[ClassicFixedBossWaves.CHAMPION]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])),
|
||||
[195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
[ClassicFixedBossWaves.RIVAL_6]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(() => new Trainer(TrainerType.RIVAL_6, globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false })
|
||||
};
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { Arena } from "#app/field/arena";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { Arena } from "#app/field/arena";
|
||||
import { Type } from "#enums/type";
|
||||
import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils";
|
||||
import { MoveCategory, allMoves, MoveTarget } from "#app/data/move";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import Pokemon, { HitResult, PokemonMove } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { HitResult, PokemonMove } from "#app/field/pokemon";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import type { BattlerIndex } from "#app/battle";
|
||||
import { BlockNonDirectDamageAbAttr, InfiltratorAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims";
|
||||
|
@ -44,7 +45,7 @@ export abstract class ArenaTag {
|
|||
|
||||
onRemove(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:arenaOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`, { moveName: this.getMoveName() }));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:arenaOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`, { moveName: this.getMoveName() }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,27 +75,25 @@ export abstract class ArenaTag {
|
|||
|
||||
/**
|
||||
* Helper function that retrieves the source Pokemon
|
||||
* @param scene medium to retrieve the source Pokemon
|
||||
* @returns The source {@linkcode Pokemon} or `null` if none is found
|
||||
*/
|
||||
public getSourcePokemon(scene: BattleScene): Pokemon | null {
|
||||
return this.sourceId ? scene.getPokemonById(this.sourceId) : null;
|
||||
public getSourcePokemon(): Pokemon | null {
|
||||
return this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that retrieves the Pokemon affected
|
||||
* @param scene - medium to retrieve the involved Pokemon
|
||||
* @returns list of PlayerPokemon or EnemyPokemon on the field
|
||||
*/
|
||||
public getAffectedPokemon(scene: BattleScene): Pokemon[] {
|
||||
public getAffectedPokemon(): Pokemon[] {
|
||||
switch (this.side) {
|
||||
case ArenaTagSide.PLAYER:
|
||||
return scene.getPlayerField() ?? [];
|
||||
return globalScene.getPlayerField() ?? [];
|
||||
case ArenaTagSide.ENEMY:
|
||||
return scene.getEnemyField() ?? [];
|
||||
return globalScene.getEnemyField() ?? [];
|
||||
case ArenaTagSide.BOTH:
|
||||
default:
|
||||
return scene.getField(true) ?? [];
|
||||
return globalScene.getField(true) ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,10 +111,10 @@ export class MistTag extends ArenaTag {
|
|||
super.onAdd(arena);
|
||||
|
||||
if (this.sourceId) {
|
||||
const source = arena.scene.getPokemonById(this.sourceId);
|
||||
const source = globalScene.getPokemonById(this.sourceId);
|
||||
|
||||
if (!quiet && source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
} else if (!quiet) {
|
||||
console.warn("Failed to get source for MistTag onAdd");
|
||||
}
|
||||
|
@ -146,7 +145,7 @@ export class MistTag extends ArenaTag {
|
|||
cancelled.value = true;
|
||||
|
||||
if (!simulated) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:mistApply"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:mistApply"));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -193,7 +192,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
|
|||
if (bypassed.value) {
|
||||
return false;
|
||||
}
|
||||
damageMultiplier.value = arena.scene.currentBattle.double ? 2732 / 4096 : 0.5;
|
||||
damageMultiplier.value = globalScene.currentBattle.double ? 2732 / 4096 : 0.5;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -211,7 +210,7 @@ class ReflectTag extends WeakenMoveScreenTag {
|
|||
|
||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:reflectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:reflectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +226,7 @@ class LightScreenTag extends WeakenMoveScreenTag {
|
|||
|
||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:lightScreenOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:lightScreenOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +242,7 @@ class AuroraVeilTag extends WeakenMoveScreenTag {
|
|||
|
||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:auroraVeilOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:auroraVeilOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +267,7 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:conditionalProtectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`, { moveName: super.getMoveName() }));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:conditionalProtectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`, { moveName: super.getMoveName() }));
|
||||
}
|
||||
|
||||
// Removes default message for effect removal
|
||||
|
@ -296,8 +295,8 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||
if (!simulated) {
|
||||
attacker.stopMultiHit(defender);
|
||||
|
||||
new CommonBattleAnim(CommonAnim.PROTECT, defender).play(arena.scene);
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:conditionalProtectApply", { moveName: super.getMoveName(), pokemonNameWithAffix: getPokemonNameWithAffix(defender) }));
|
||||
new CommonBattleAnim(CommonAnim.PROTECT, defender).play();
|
||||
globalScene.queueMessage(i18next.t("arenaTag:conditionalProtectApply", { moveName: super.getMoveName(), pokemonNameWithAffix: getPokemonNameWithAffix(defender) }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +317,7 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||
*/
|
||||
const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
|
||||
const move = allMoves[moveId];
|
||||
const effectPhase = arena.scene.getCurrentPhase();
|
||||
const effectPhase = globalScene.getCurrentPhase();
|
||||
|
||||
if (effectPhase instanceof MoveEffectPhase) {
|
||||
const attacker = effectPhase.getUserPokemon();
|
||||
|
@ -393,9 +392,9 @@ class MatBlockTag extends ConditionalProtectTag {
|
|||
|
||||
onAdd(arena: Arena) {
|
||||
if (this.sourceId) {
|
||||
const source = arena.scene.getPokemonById(this.sourceId);
|
||||
const source = globalScene.getPokemonById(this.sourceId);
|
||||
if (source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
} else {
|
||||
console.warn("Failed to get source for MatBlockTag onAdd");
|
||||
}
|
||||
|
@ -448,15 +447,15 @@ export class NoCritTag extends ArenaTag {
|
|||
|
||||
/** Queues a message upon adding this effect to the field */
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:noCritOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : "Enemy"}`, {
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:noCritOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : "Enemy"}`, {
|
||||
moveName: this.getMoveName()
|
||||
}));
|
||||
}
|
||||
|
||||
/** Queues a message upon removing this effect from the field */
|
||||
onRemove(arena: Arena): void {
|
||||
const source = arena.scene.getPokemonById(this.sourceId!); // TODO: is this bang correct?
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:noCritOnRemove", {
|
||||
const source = globalScene.getPokemonById(this.sourceId!); // TODO: is this bang correct?
|
||||
globalScene.queueMessage(i18next.t("arenaTag:noCritOnRemove", {
|
||||
pokemonNameWithAffix: getPokemonNameWithAffix(source ?? undefined),
|
||||
moveName: this.getMoveName()
|
||||
}));
|
||||
|
@ -478,7 +477,7 @@ class WishTag extends ArenaTag {
|
|||
|
||||
onAdd(arena: Arena): void {
|
||||
if (this.sourceId) {
|
||||
const user = arena.scene.getPokemonById(this.sourceId);
|
||||
const user = globalScene.getPokemonById(this.sourceId);
|
||||
if (user) {
|
||||
this.battlerIndex = user.getBattlerIndex();
|
||||
this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) });
|
||||
|
@ -490,10 +489,10 @@ class WishTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
const target = arena.scene.getField()[this.battlerIndex];
|
||||
const target = globalScene.getField()[this.battlerIndex];
|
||||
if (target?.isActive(true)) {
|
||||
arena.scene.queueMessage(this.triggerMessage);
|
||||
arena.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), this.healHp, null, true, false));
|
||||
globalScene.queueMessage(this.triggerMessage);
|
||||
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), this.healHp, null, true, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -546,11 +545,11 @@ class MudSportTag extends WeakenMoveTypeTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:mudSportOnAdd"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:mudSportOnAdd"));
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:mudSportOnRemove"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:mudSportOnRemove"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,11 +563,11 @@ class WaterSportTag extends WeakenMoveTypeTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:waterSportOnAdd"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:waterSportOnAdd"));
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:waterSportOnRemove"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:waterSportOnRemove"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,7 +583,7 @@ export class IonDelugeTag extends ArenaTag {
|
|||
|
||||
/** Queues an on-add message */
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void { } // Removes default on-remove message
|
||||
|
@ -679,9 +678,9 @@ class SpikesTag extends ArenaTrapTag {
|
|||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
super.onAdd(arena);
|
||||
|
||||
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
if (!quiet && source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:spikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:spikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -698,7 +697,7 @@ class SpikesTag extends ArenaTrapTag {
|
|||
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
||||
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
|
||||
|
||||
pokemon.scene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
||||
if (pokemon.turnData) {
|
||||
pokemon.turnData.damageTaken += damage;
|
||||
|
@ -728,9 +727,9 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
|||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
super.onAdd(arena);
|
||||
|
||||
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
if (!quiet && source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:toxicSpikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:toxicSpikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -747,8 +746,8 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
|||
}
|
||||
if (pokemon.isOfType(Type.POISON)) {
|
||||
this.neutralized = true;
|
||||
if (pokemon.scene.arena.removeTag(this.tagType)) {
|
||||
pokemon.scene.queueMessage(i18next.t("arenaTag:toxicSpikesActivateTrapPoison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: this.getMoveName() }));
|
||||
if (globalScene.arena.removeTag(this.tagType)) {
|
||||
globalScene.queueMessage(i18next.t("arenaTag:toxicSpikesActivateTrapPoison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: this.getMoveName() }));
|
||||
return true;
|
||||
}
|
||||
} else if (!pokemon.status) {
|
||||
|
@ -792,7 +791,7 @@ export class DelayedAttackTag extends ArenaTag {
|
|||
const ret = super.lapse(arena);
|
||||
|
||||
if (!ret) {
|
||||
arena.scene.unshiftPhase(new MoveEffectPhase(arena.scene, this.sourceId!, [ this.targetIndex ], new PokemonMove(this.sourceMove!, 0, 0, true))); // TODO: are those bangs correct?
|
||||
globalScene.unshiftPhase(new MoveEffectPhase(this.sourceId!, [ this.targetIndex ], new PokemonMove(this.sourceMove!, 0, 0, true))); // TODO: are those bangs correct?
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -814,9 +813,9 @@ class StealthRockTag extends ArenaTrapTag {
|
|||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
super.onAdd(arena);
|
||||
|
||||
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
if (!quiet && source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:stealthRockOnAdd", { opponentDesc: source.getOpponentDescriptor() }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:stealthRockOnAdd", { opponentDesc: source.getOpponentDescriptor() }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -864,7 +863,7 @@ class StealthRockTag extends ArenaTrapTag {
|
|||
return true;
|
||||
}
|
||||
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
|
||||
pokemon.scene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
||||
if (pokemon.turnData) {
|
||||
pokemon.turnData.damageTaken += damage;
|
||||
|
@ -893,9 +892,9 @@ class StickyWebTag extends ArenaTrapTag {
|
|||
|
||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
super.onAdd(arena);
|
||||
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
if (!quiet && source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:stickyWebOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:stickyWebOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -909,9 +908,9 @@ class StickyWebTag extends ArenaTrapTag {
|
|||
}
|
||||
|
||||
if (!cancelled.value) {
|
||||
pokemon.scene.queueMessage(i18next.t("arenaTag:stickyWebActivateTrap", { pokemonName: pokemon.getNameToRender() }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:stickyWebActivateTrap", { pokemonName: pokemon.getNameToRender() }));
|
||||
const stages = new NumberHolder(-1);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [ Stat.SPD ], stages.value));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, [ Stat.SPD ], stages.value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -945,14 +944,14 @@ export class TrickRoomTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
|
||||
if (source) {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
}
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnRemove"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:trickRoomOnRemove"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,8 +966,8 @@ export class GravityTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:gravityOnAdd"));
|
||||
arena.scene.getField(true).forEach((pokemon) => {
|
||||
globalScene.queueMessage(i18next.t("arenaTag:gravityOnAdd"));
|
||||
globalScene.getField(true).forEach((pokemon) => {
|
||||
if (pokemon !== null) {
|
||||
pokemon.removeTag(BattlerTagType.FLOATING);
|
||||
pokemon.removeTag(BattlerTagType.TELEKINESIS);
|
||||
|
@ -980,7 +979,7 @@ export class GravityTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:gravityOnRemove"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:gravityOnRemove"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -996,29 +995,29 @@ class TailwindTag extends ArenaTag {
|
|||
|
||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
|
||||
const source = arena.scene.getPokemonById(this.sourceId!); //TODO: this bang is questionable!
|
||||
const party = (source?.isPlayer() ? source.scene.getPlayerField() : source?.scene.getEnemyField()) ?? [];
|
||||
const source = globalScene.getPokemonById(this.sourceId!); //TODO: this bang is questionable!
|
||||
const party = (source?.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField()) ?? [];
|
||||
|
||||
for (const pokemon of party) {
|
||||
// Apply the CHARGED tag to party members with the WIND_POWER ability
|
||||
if (pokemon.hasAbility(Abilities.WIND_POWER) && !pokemon.getTag(BattlerTagType.CHARGED)) {
|
||||
pokemon.addTag(BattlerTagType.CHARGED);
|
||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: this.getMoveName() }));
|
||||
globalScene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: this.getMoveName() }));
|
||||
}
|
||||
// Raise attack by one stage if party member has WIND_RIDER ability
|
||||
if (pokemon.hasAbility(Abilities.WIND_RIDER)) {
|
||||
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.getBattlerIndex()));
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK ], 1, true));
|
||||
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.getBattlerIndex()));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.ATK ], 1, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRemove(arena: Arena, quiet: boolean = false): void {
|
||||
if (!quiet) {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:tailwindOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:tailwindOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1033,11 +1032,11 @@ class HappyHourTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:happyHourOnAdd"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:happyHourOnAdd"));
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:happyHourOnRemove"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:happyHourOnRemove"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1047,11 +1046,11 @@ class SafeguardTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:safeguardOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:safeguardOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,16 +1073,16 @@ class ImprisonTag extends ArenaTrapTag {
|
|||
* This function applies the effects of Imprison to the opposing Pokemon already present on the field.
|
||||
* @param arena
|
||||
*/
|
||||
override onAdd({ scene }: Arena) {
|
||||
const source = this.getSourcePokemon(scene);
|
||||
override onAdd() {
|
||||
const source = this.getSourcePokemon();
|
||||
if (source) {
|
||||
const party = this.getAffectedPokemon(scene);
|
||||
const party = this.getAffectedPokemon();
|
||||
party?.forEach((p: Pokemon ) => {
|
||||
if (p.isAllowedInBattle()) {
|
||||
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
||||
}
|
||||
});
|
||||
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
globalScene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1092,8 +1091,8 @@ class ImprisonTag extends ArenaTrapTag {
|
|||
* @param _arena
|
||||
* @returns `true` if the source of the tag is still active on the field | `false` if not
|
||||
*/
|
||||
override lapse({ scene }: Arena): boolean {
|
||||
const source = this.getSourcePokemon(scene);
|
||||
override lapse(): boolean {
|
||||
const source = this.getSourcePokemon();
|
||||
return source ? source.isActive(true) : false;
|
||||
}
|
||||
|
||||
|
@ -1103,7 +1102,7 @@ class ImprisonTag extends ArenaTrapTag {
|
|||
* @returns `true`
|
||||
*/
|
||||
override activateTrap(pokemon: Pokemon): boolean {
|
||||
const source = this.getSourcePokemon(pokemon.scene);
|
||||
const source = this.getSourcePokemon();
|
||||
if (source && source.isActive(true) && pokemon.isAllowedInBattle()) {
|
||||
pokemon.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
|
||||
}
|
||||
|
@ -1114,8 +1113,8 @@ class ImprisonTag extends ArenaTrapTag {
|
|||
* When the arena tag is removed, it also attempts to remove any related Battler Tags if they haven't already been removed from the affected Pokemon
|
||||
* @param arena
|
||||
*/
|
||||
override onRemove({ scene }: Arena): void {
|
||||
const party = this.getAffectedPokemon(scene);
|
||||
override onRemove(): void {
|
||||
const party = this.getAffectedPokemon();
|
||||
party?.forEach((p: Pokemon) => {
|
||||
p.removeTag(BattlerTagType.IMPRISON);
|
||||
});
|
||||
|
@ -1136,19 +1135,19 @@ class FireGrassPledgeTag extends ArenaTag {
|
|||
|
||||
override onAdd(arena: Arena): void {
|
||||
// "A sea of fire enveloped your/the opposing team!"
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:fireGrassPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:fireGrassPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
|
||||
override lapse(arena: Arena): boolean {
|
||||
const field: Pokemon[] = (this.side === ArenaTagSide.PLAYER)
|
||||
? arena.scene.getPlayerField()
|
||||
: arena.scene.getEnemyField();
|
||||
? globalScene.getPlayerField()
|
||||
: globalScene.getEnemyField();
|
||||
|
||||
field.filter(pokemon => !pokemon.isOfType(Type.FIRE) && !pokemon.switchOutStatus).forEach(pokemon => {
|
||||
// "{pokemonNameWithAffix} was hurt by the sea of fire!"
|
||||
pokemon.scene.queueMessage(i18next.t("arenaTag:fireGrassPledgeLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:fireGrassPledgeLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||
// TODO: Replace this with a proper animation
|
||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM));
|
||||
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM));
|
||||
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8));
|
||||
});
|
||||
|
||||
|
@ -1170,7 +1169,7 @@ class WaterFirePledgeTag extends ArenaTag {
|
|||
|
||||
override onAdd(arena: Arena): void {
|
||||
// "A rainbow appeared in the sky on your/the opposing team's side!"
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:waterFirePledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:waterFirePledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1200,7 +1199,7 @@ class GrassWaterPledgeTag extends ArenaTag {
|
|||
|
||||
override onAdd(arena: Arena): void {
|
||||
// "A swamp enveloped your/the opposing team!"
|
||||
arena.scene.queueMessage(i18next.t(`arenaTag:grassWaterPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
globalScene.queueMessage(i18next.t(`arenaTag:grassWaterPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1217,7 +1216,7 @@ export class FairyLockTag extends ArenaTag {
|
|||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(i18next.t("arenaTag:fairyLockOnAdd"));
|
||||
globalScene.queueMessage(i18next.t("arenaTag:fairyLockOnAdd"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Type } from "#enums/type";
|
||||
import * as Utils from "#app/utils";
|
||||
import { pokemonEvolutions, SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
||||
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import i18next from "i18next";
|
||||
import { Biome } from "#enums/biome";
|
||||
import { Species } from "#enums/species";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { globalScene } from "#app/global-scene";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import Pokemon from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { Type } from "#enums/type";
|
||||
import * as Utils from "#app/utils";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
|
@ -11,6 +12,8 @@ import { Species } from "#enums/species";
|
|||
import { TimeOfDay } from "#enums/time-of-day";
|
||||
import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier, TempExtraModifierModifier } from "#app/modifier/modifier";
|
||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||
import { speciesStarterCosts } from "./starters";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
||||
export enum SpeciesWildEvolutionDelay {
|
||||
|
@ -119,17 +122,214 @@ export class FusionSpeciesFormEvolution extends SpeciesFormEvolution {
|
|||
|
||||
export class SpeciesEvolutionCondition {
|
||||
public predicate: EvolutionConditionPredicate;
|
||||
public enforceFunc: EvolutionConditionEnforceFunc | undefined;
|
||||
public enforceFunc?: EvolutionConditionEnforceFunc;
|
||||
public description: string;
|
||||
|
||||
constructor(predicate: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
|
||||
this.predicate = predicate;
|
||||
this.enforceFunc = enforceFunc;
|
||||
this.description = "";
|
||||
}
|
||||
}
|
||||
|
||||
export class SpeciesFriendshipEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor(friendshipAmount: integer, predicate?: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
|
||||
super(p => p.friendship >= friendshipAmount && (!predicate || predicate(p)), enforceFunc);
|
||||
class GenderEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public gender: Gender;
|
||||
constructor(gender: Gender) {
|
||||
super(p => p.gender === gender, p => p.gender = gender);
|
||||
this.gender = gender;
|
||||
this.description = i18next.t("pokemonEvolutions:gender", { gender: i18next.t(`pokemonEvolutions:${Gender[gender]}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class TimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public timesOfDay: TimeOfDay[];
|
||||
constructor(tod: "day" | "night") {
|
||||
if (tod === "day") {
|
||||
super(() => globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY);
|
||||
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
|
||||
} else if (tod === "night") {
|
||||
super(() => globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT);
|
||||
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
|
||||
} else {
|
||||
super(() => false);
|
||||
this.timesOfDay = [];
|
||||
}
|
||||
this.description = i18next.t("pokemonEvolutions:timeOfDay", { tod: i18next.t(`pokemonEvolutions:${tod}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class MoveEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
constructor(move: Moves) {
|
||||
super(p => p.moveset.filter(m => m?.moveId === move).length > 0);
|
||||
this.move = move;
|
||||
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
|
||||
}
|
||||
}
|
||||
|
||||
class FriendshipEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public amount: integer;
|
||||
constructor(amount: number) {
|
||||
super(p => p.friendship >= amount);
|
||||
this.amount = amount;
|
||||
this.description = i18next.t("pokemonEvolutions:friendship");
|
||||
}
|
||||
}
|
||||
|
||||
class FriendshipTimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public amount: integer;
|
||||
public timesOfDay: TimeOfDay[];
|
||||
constructor(amount: number, tod: "day" | "night") {
|
||||
if (tod === "day") {
|
||||
super(p => p.friendship >= amount && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
|
||||
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
|
||||
} else if (tod === "night") {
|
||||
super(p => p.friendship >= amount && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
|
||||
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
|
||||
} else {
|
||||
super(p => false);
|
||||
this.timesOfDay = [];
|
||||
}
|
||||
this.amount = amount;
|
||||
this.description = i18next.t("pokemonEvolutions:friendshipTimeOfDay", { tod: i18next.t(`pokemonEvolutions:${tod}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class FriendshipMoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public amount: integer;
|
||||
public type: Type;
|
||||
constructor(amount: number, type: Type) {
|
||||
super(p => p.friendship >= amount && !!p.getMoveset().find(m => m?.getMove().type === type));
|
||||
this.amount = amount;
|
||||
this.type = type;
|
||||
this.description = i18next.t("pokemonEvolutions:friendshipMoveType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class ShedinjaEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor() {
|
||||
super(() => globalScene.getPlayerParty().length < 6 && globalScene.pokeballCounts[PokeballType.POKEBALL] > 0);
|
||||
this.description = i18next.t("pokemonEvolutions:shedinja");
|
||||
}
|
||||
}
|
||||
|
||||
class PartyTypeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public type: Type;
|
||||
constructor(type: Type) {
|
||||
super(() => !!globalScene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(type) > -1));
|
||||
this.type = type;
|
||||
this.description = i18next.t("pokemonEvolutions:partyType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class CaughtEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public species: Species;
|
||||
constructor(species: Species) {
|
||||
super(() => !!globalScene.gameData.dexData[species].caughtAttr);
|
||||
this.species = species;
|
||||
this.description = i18next.t("pokemonEvolutions:caught", { species: i18next.t(`pokemon:${Species[this.species].toLowerCase()}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class WeatherEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public weatherTypes: WeatherType[];
|
||||
constructor(weatherTypes: WeatherType[]) {
|
||||
super(() => weatherTypes.indexOf(globalScene.arena.weather?.weatherType || WeatherType.NONE) > -1);
|
||||
this.weatherTypes = weatherTypes;
|
||||
}
|
||||
}
|
||||
|
||||
class MoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public type: Type;
|
||||
constructor(type: Type) {
|
||||
super(p => p.moveset.filter(m => m?.getMove().type === type).length > 0);
|
||||
this.type = type;
|
||||
this.description = i18next.t("pokemonEvolutions:moveType", { type: i18next.t(`pokemonInfo:Type.${Type[this.type]}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class TreasureEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor() {
|
||||
super(p => p.evoCounter
|
||||
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||
+ globalScene.findModifiers(m => m instanceof MoneyMultiplierModifier
|
||||
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9);
|
||||
this.description = i18next.t("pokemonEvolutions:treasure");
|
||||
}
|
||||
}
|
||||
|
||||
class TyrogueEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
constructor(move: Moves) {
|
||||
super(p =>
|
||||
p.getMoveset(true).find(m => m && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(m?.moveId))?.moveId === move);
|
||||
this.move = move;
|
||||
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
|
||||
}
|
||||
}
|
||||
|
||||
class NatureEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public natures: Nature[];
|
||||
constructor(natures: Nature[]) {
|
||||
super(p => natures.indexOf(p.getNature()) > -1);
|
||||
this.natures = natures;
|
||||
this.description = i18next.t("pokemonEvolutions:nature");
|
||||
}
|
||||
}
|
||||
|
||||
class MoveTimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
public timesOfDay: TimeOfDay[];
|
||||
constructor(move: Moves, tod: "day" | "night") {
|
||||
if (tod === "day") {
|
||||
super(p => p.moveset.filter(m => m?.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
|
||||
this.move = move;
|
||||
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
|
||||
} else if (tod === "night") {
|
||||
super(p => p.moveset.filter(m => m?.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
|
||||
this.move = move;
|
||||
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
|
||||
} else {
|
||||
super(() => false);
|
||||
this.timesOfDay = [];
|
||||
}
|
||||
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
this.description = i18next.t("pokemonEvolutions:moveTimeOfDay", { move: i18next.t(`move:${moveKey}.name`), tod: i18next.t(`pokemonEvolutions:${tod}`) });
|
||||
}
|
||||
}
|
||||
|
||||
class BiomeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public biomes: Biome[];
|
||||
constructor(biomes: Biome[]) {
|
||||
super(() => biomes.filter(b => b === globalScene.arena.biomeType).length > 0);
|
||||
this.biomes = biomes;
|
||||
this.description = i18next.t("pokemonEvolutions:biome");
|
||||
}
|
||||
}
|
||||
|
||||
class DunsparceEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor() {
|
||||
super(p => {
|
||||
let ret = false;
|
||||
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
|
||||
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
const moveKey = Moves[Moves.HYPER_DRILL].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
|
||||
}
|
||||
}
|
||||
|
||||
class TandemausEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor() {
|
||||
super(p => {
|
||||
let ret = false;
|
||||
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,8 +466,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.ELECTRODE, 30, null, null)
|
||||
],
|
||||
[Species.CUBONE]: [
|
||||
new SpeciesEvolution(Species.ALOLA_MAROWAK, 28, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.MAROWAK, 28, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.ALOLA_MAROWAK, 28, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.MAROWAK, 28, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.TYROGUE]: [
|
||||
/**
|
||||
|
@ -276,19 +476,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
* If Tyrogue knows multiple of these moves, its evolution is based on
|
||||
* the first qualifying move in its moveset.
|
||||
*/
|
||||
new SpeciesEvolution(Species.HITMONLEE, 20, null, new SpeciesEvolutionCondition(p =>
|
||||
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.LOW_SWEEP
|
||||
)),
|
||||
new SpeciesEvolution(Species.HITMONCHAN, 20, null, new SpeciesEvolutionCondition(p =>
|
||||
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.MACH_PUNCH
|
||||
)),
|
||||
new SpeciesEvolution(Species.HITMONTOP, 20, null, new SpeciesEvolutionCondition(p =>
|
||||
p.getMoveset(true).find(move => move && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(move?.moveId))?.moveId === Moves.RAPID_SPIN
|
||||
)),
|
||||
new SpeciesEvolution(Species.HITMONLEE, 20, null, new TyrogueEvolutionCondition(Moves.LOW_SWEEP)),
|
||||
new SpeciesEvolution(Species.HITMONCHAN, 20, null, new TyrogueEvolutionCondition(Moves.MACH_PUNCH)),
|
||||
new SpeciesEvolution(Species.HITMONTOP, 20, null, new TyrogueEvolutionCondition(Moves.RAPID_SPIN)),
|
||||
],
|
||||
[Species.KOFFING]: [
|
||||
new SpeciesEvolution(Species.GALAR_WEEZING, 35, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.WEEZING, 35, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.GALAR_WEEZING, 35, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.WEEZING, 35, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.RHYHORN]: [
|
||||
new SpeciesEvolution(Species.RHYDON, 42, null, null)
|
||||
|
@ -333,8 +527,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.QUILAVA, 14, null, null)
|
||||
],
|
||||
[Species.QUILAVA]: [
|
||||
new SpeciesEvolution(Species.HISUI_TYPHLOSION, 36, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.TYPHLOSION, 36, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_TYPHLOSION, 36, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.TYPHLOSION, 36, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.TOTODILE]: [
|
||||
new SpeciesEvolution(Species.CROCONAW, 18, null, null)
|
||||
|
@ -436,8 +630,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.LINOONE, 20, null, null)
|
||||
],
|
||||
[Species.WURMPLE]: [
|
||||
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)),
|
||||
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||
new SpeciesEvolution(Species.SILCOON, 7, null, new TimeOfDayEvolutionCondition("day")),
|
||||
new SpeciesEvolution(Species.CASCOON, 7, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.SILCOON]: [
|
||||
new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null)
|
||||
|
@ -461,8 +655,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.KIRLIA, 20, null, null)
|
||||
],
|
||||
[Species.KIRLIA]: [
|
||||
new SpeciesEvolution(Species.GARDEVOIR, 30, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
|
||||
new SpeciesEvolution(Species.GALLADE, 30, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
|
||||
new SpeciesEvolution(Species.GARDEVOIR, 30, null, new GenderEvolutionCondition(Gender.FEMALE)),
|
||||
new SpeciesEvolution(Species.GALLADE, 30, null, new GenderEvolutionCondition(Gender.MALE))
|
||||
],
|
||||
[Species.SURSKIT]: [
|
||||
new SpeciesEvolution(Species.MASQUERAIN, 22, null, null)
|
||||
|
@ -478,7 +672,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
],
|
||||
[Species.NINCADA]: [
|
||||
new SpeciesEvolution(Species.NINJASK, 20, null, null),
|
||||
new SpeciesEvolution(Species.SHEDINJA, 20, null, new SpeciesEvolutionCondition(p => p.scene.getPlayerParty().length < 6 && p.scene.pokeballCounts[PokeballType.POKEBALL] > 0))
|
||||
new SpeciesEvolution(Species.SHEDINJA, 20, null, new ShedinjaEvolutionCondition())
|
||||
],
|
||||
[Species.WHISMUR]: [
|
||||
new SpeciesEvolution(Species.LOUDRED, 20, null, null)
|
||||
|
@ -550,8 +744,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.DUSCLOPS, 37, null, null)
|
||||
],
|
||||
[Species.SNORUNT]: [
|
||||
new SpeciesEvolution(Species.GLALIE, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE)),
|
||||
new SpeciesEvolution(Species.FROSLASS, 42, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
|
||||
new SpeciesEvolution(Species.GLALIE, 42, null, new GenderEvolutionCondition(Gender.MALE)),
|
||||
new SpeciesEvolution(Species.FROSLASS, 42, null, new GenderEvolutionCondition(Gender.FEMALE))
|
||||
],
|
||||
[Species.SPHEAL]: [
|
||||
new SpeciesEvolution(Species.SEALEO, 32, null, null)
|
||||
|
@ -614,11 +808,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.BASTIODON, 30, null, null)
|
||||
],
|
||||
[Species.BURMY]: [
|
||||
new SpeciesEvolution(Species.MOTHIM, 20, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE)),
|
||||
new SpeciesEvolution(Species.WORMADAM, 20, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
|
||||
new SpeciesEvolution(Species.MOTHIM, 20, null, new GenderEvolutionCondition(Gender.MALE)),
|
||||
new SpeciesEvolution(Species.WORMADAM, 20, null, new GenderEvolutionCondition(Gender.FEMALE))
|
||||
],
|
||||
[Species.COMBEE]: [
|
||||
new SpeciesEvolution(Species.VESPIQUEN, 21, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
|
||||
new SpeciesEvolution(Species.VESPIQUEN, 21, null, new GenderEvolutionCondition(Gender.FEMALE))
|
||||
],
|
||||
[Species.BUIZEL]: [
|
||||
new SpeciesEvolution(Species.FLOATZEL, 26, null, null)
|
||||
|
@ -660,7 +854,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.LUMINEON, 31, null, null)
|
||||
],
|
||||
[Species.MANTYKE]: [
|
||||
new SpeciesEvolution(Species.MANTINE, 32, null, new SpeciesEvolutionCondition(p => !!p.scene.gameData.dexData[Species.REMORAID].caughtAttr), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.MANTINE, 32, null, new CaughtEvolutionCondition(Species.REMORAID), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.SNOVER]: [
|
||||
new SpeciesEvolution(Species.ABOMASNOW, 40, null, null)
|
||||
|
@ -681,8 +875,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.DEWOTT, 17, null, null)
|
||||
],
|
||||
[Species.DEWOTT]: [
|
||||
new SpeciesEvolution(Species.HISUI_SAMUROTT, 36, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.SAMUROTT, 36, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_SAMUROTT, 36, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.SAMUROTT, 36, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.PATRAT]: [
|
||||
new SpeciesEvolution(Species.WATCHOG, 20, null, null)
|
||||
|
@ -832,8 +1026,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.KINGAMBIT, 1, EvolutionItem.LEADERS_CREST, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.RUFFLET]: [
|
||||
new SpeciesEvolution(Species.HISUI_BRAVIARY, 54, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.BRAVIARY, 54, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_BRAVIARY, 54, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.BRAVIARY, 54, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.VULLABY]: [
|
||||
new SpeciesEvolution(Species.MANDIBUZZ, 54, null, null)
|
||||
|
@ -890,11 +1084,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.GOGOAT, 32, null, null)
|
||||
],
|
||||
[Species.PANCHAM]: [
|
||||
new SpeciesEvolution(Species.PANGORO, 32, null, new SpeciesEvolutionCondition(p => !!p.scene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(Type.DARK) > -1)), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.PANGORO, 32, null, new PartyTypeEvolutionCondition(Type.DARK), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.ESPURR]: [
|
||||
new SpeciesFormEvolution(Species.MEOWSTIC, "", "female", 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
|
||||
new SpeciesFormEvolution(Species.MEOWSTIC, "", "", 25, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
|
||||
new SpeciesFormEvolution(Species.MEOWSTIC, "", "female", 25, null, new GenderEvolutionCondition(Gender.FEMALE)),
|
||||
new SpeciesFormEvolution(Species.MEOWSTIC, "", "", 25, null, new GenderEvolutionCondition(Gender.MALE))
|
||||
],
|
||||
[Species.HONEDGE]: [
|
||||
new SpeciesEvolution(Species.DOUBLADE, 35, null, null)
|
||||
|
@ -912,21 +1106,21 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.CLAWITZER, 37, null, null)
|
||||
],
|
||||
[Species.TYRUNT]: [
|
||||
new SpeciesEvolution(Species.TYRANTRUM, 39, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.TYRANTRUM, 39, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.AMAURA]: [
|
||||
new SpeciesEvolution(Species.AURORUS, 39, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||
new SpeciesEvolution(Species.AURORUS, 39, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.GOOMY]: [
|
||||
new SpeciesEvolution(Species.HISUI_SLIGGOO, 40, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.SLIGGOO, 40, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_SLIGGOO, 40, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.SLIGGOO, 40, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.SLIGGOO]: [
|
||||
new SpeciesEvolution(Species.GOODRA, 50, null, new SpeciesEvolutionCondition(p => [ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ].indexOf(p.scene.arena.weather?.weatherType || WeatherType.NONE) > -1), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.GOODRA, 50, null, new WeatherEvolutionCondition([ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ]), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.BERGMITE]: [
|
||||
new SpeciesEvolution(Species.HISUI_AVALUGG, 37, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.AVALUGG, 37, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_AVALUGG, 37, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.AVALUGG, 37, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.NOIBAT]: [
|
||||
new SpeciesEvolution(Species.NOIVERN, 48, null, null)
|
||||
|
@ -935,8 +1129,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.DARTRIX, 17, null, null)
|
||||
],
|
||||
[Species.DARTRIX]: [
|
||||
new SpeciesEvolution(Species.HISUI_DECIDUEYE, 36, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)),
|
||||
new SpeciesEvolution(Species.DECIDUEYE, 34, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.HISUI_DECIDUEYE, 36, null, new TimeOfDayEvolutionCondition("night")),
|
||||
new SpeciesEvolution(Species.DECIDUEYE, 34, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.LITTEN]: [
|
||||
new SpeciesEvolution(Species.TORRACAT, 17, null, null)
|
||||
|
@ -957,7 +1151,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.TOUCANNON, 28, null, null)
|
||||
],
|
||||
[Species.YUNGOOS]: [
|
||||
new SpeciesEvolution(Species.GUMSHOOS, 20, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.GUMSHOOS, 20, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.GRUBBIN]: [
|
||||
new SpeciesEvolution(Species.CHARJABUG, 20, null, null)
|
||||
|
@ -975,13 +1169,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.ARAQUANID, 22, null, null)
|
||||
],
|
||||
[Species.FOMANTIS]: [
|
||||
new SpeciesEvolution(Species.LURANTIS, 34, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY))
|
||||
new SpeciesEvolution(Species.LURANTIS, 34, null, new TimeOfDayEvolutionCondition("day"))
|
||||
],
|
||||
[Species.MORELULL]: [
|
||||
new SpeciesEvolution(Species.SHIINOTIC, 24, null, null)
|
||||
],
|
||||
[Species.SALANDIT]: [
|
||||
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
|
||||
new SpeciesEvolution(Species.SALAZZLE, 33, null, new GenderEvolutionCondition(Gender.FEMALE))
|
||||
],
|
||||
[Species.STUFFUL]: [
|
||||
new SpeciesEvolution(Species.BEWEAR, 27, null, null)
|
||||
|
@ -1012,7 +1206,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.MELMETAL, 48, null, null)
|
||||
],
|
||||
[Species.ALOLA_RATTATA]: [
|
||||
new SpeciesEvolution(Species.ALOLA_RATICATE, 20, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||
new SpeciesEvolution(Species.ALOLA_RATICATE, 20, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.ALOLA_DIGLETT]: [
|
||||
new SpeciesEvolution(Species.ALOLA_DUGTRIO, 26, null, null)
|
||||
|
@ -1085,7 +1279,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
],
|
||||
[Species.TOXEL]: [
|
||||
new SpeciesFormEvolution(Species.TOXTRICITY, "", "lowkey", 30, null,
|
||||
new SpeciesEvolutionCondition(p => [ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ].indexOf(p.getNature()) > -1)),
|
||||
new NatureEvolutionCondition([ Nature.LONELY, Nature.BOLD, Nature.RELAXED, Nature.TIMID, Nature.SERIOUS, Nature.MODEST, Nature.MILD, Nature.QUIET, Nature.BASHFUL, Nature.CALM, Nature.GENTLE, Nature.CAREFUL ])
|
||||
),
|
||||
new SpeciesFormEvolution(Species.TOXTRICITY, "", "amped", 30, null, null)
|
||||
],
|
||||
[Species.SIZZLIPEDE]: [
|
||||
|
@ -1135,7 +1330,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.GALAR_LINOONE, 20, null, null)
|
||||
],
|
||||
[Species.GALAR_LINOONE]: [
|
||||
new SpeciesEvolution(Species.OBSTAGOON, 35, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||
new SpeciesEvolution(Species.OBSTAGOON, 35, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.GALAR_YAMASK]: [
|
||||
new SpeciesEvolution(Species.RUNERIGUS, 34, null, null)
|
||||
|
@ -1144,7 +1339,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.HISUI_ZOROARK, 30, null, null)
|
||||
],
|
||||
[Species.HISUI_SLIGGOO]: [
|
||||
new SpeciesEvolution(Species.HISUI_GOODRA, 50, null, new SpeciesEvolutionCondition(p => [ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ].indexOf(p.scene.arena.weather?.weatherType || WeatherType.NONE) > -1), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.HISUI_GOODRA, 50, null, new WeatherEvolutionCondition([ WeatherType.RAIN, WeatherType.FOG, WeatherType.HEAVY_RAIN ]), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.SPRIGATITO]: [
|
||||
new SpeciesEvolution(Species.FLORAGATO, 16, null, null)
|
||||
|
@ -1165,8 +1360,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.QUAQUAVAL, 36, null, null)
|
||||
],
|
||||
[Species.LECHONK]: [
|
||||
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "female", 18, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)),
|
||||
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "", 18, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE))
|
||||
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "female", 18, null, new GenderEvolutionCondition(Gender.FEMALE)),
|
||||
new SpeciesFormEvolution(Species.OINKOLOGNE, "", "", 18, null, new GenderEvolutionCondition(Gender.MALE))
|
||||
],
|
||||
[Species.TAROUNTULA]: [
|
||||
new SpeciesEvolution(Species.SPIDOPS, 15, null, null)
|
||||
|
@ -1181,11 +1376,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.PAWMOT, 32, null, null)
|
||||
],
|
||||
[Species.TANDEMAUS]: [
|
||||
new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new SpeciesEvolutionCondition(p => {
|
||||
let ret = false;
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
return ret;
|
||||
})),
|
||||
new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new TandemausEvolutionCondition()),
|
||||
new SpeciesEvolution(Species.MAUSHOLD, 25, null, null)
|
||||
],
|
||||
[Species.FIDOUGH]: [
|
||||
|
@ -1243,7 +1434,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.GLIMMORA, 35, null, null)
|
||||
],
|
||||
[Species.GREAVARD]: [
|
||||
new SpeciesEvolution(Species.HOUNDSTONE, 30, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||
new SpeciesEvolution(Species.HOUNDSTONE, 30, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.FRIGIBAX]: [
|
||||
new SpeciesEvolution(Species.ARCTIBAX, 35, null, null)
|
||||
|
@ -1300,21 +1491,21 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.EXEGGUTOR, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.TANGELA]: [
|
||||
new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.TANGROWTH, 34, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.LICKITUNG]: [
|
||||
new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.LICKILICKY, 32, null, new MoveEvolutionCondition(Moves.ROLLOUT), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.STARYU]: [
|
||||
new SpeciesEvolution(Species.STARMIE, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.EEVEE]: [
|
||||
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.UMBREON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(120, p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new FriendshipMoveTypeEvolutionCondition(120, Type.FAIRY), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new FriendshipMoveTypeEvolutionCondition(120, Type.FAIRY), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "night"), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.UMBREON, "partner", "", 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "night"), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.VAPOREON, "", "", 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.VAPOREON, "partner", "", 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.JOLTEON, "", "", 1, EvolutionItem.THUNDER_STONE, null, SpeciesWildEvolutionDelay.LONG),
|
||||
|
@ -1330,13 +1521,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.TOGEKISS, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.AIPOM]: [
|
||||
new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.AMBIPOM, 32, null, new MoveEvolutionCondition(Moves.DOUBLE_HIT), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.SUNKERN]: [
|
||||
new SpeciesEvolution(Species.SUNFLORA, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.YANMA]: [
|
||||
new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.YANMEGA, 33, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.MURKROW]: [
|
||||
new SpeciesEvolution(Species.HONCHKROW, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1345,32 +1536,26 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.MISMAGIUS, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.GIRAFARIG]: [
|
||||
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new MoveEvolutionCondition(Moves.TWIN_BEAM), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.DUNSPARCE]: [
|
||||
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => {
|
||||
let ret = false;
|
||||
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
}
|
||||
return ret;
|
||||
}), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new DunsparceEvolutionCondition(), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new MoveEvolutionCondition(Moves.HYPER_DRILL), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.GLIGAR]: [
|
||||
new SpeciesEvolution(Species.GLISCOR, 1, EvolutionItem.RAZOR_FANG, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor fang at night*/), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.GLISCOR, 1, EvolutionItem.RAZOR_FANG, new TimeOfDayEvolutionCondition("night") /* Razor fang at night*/, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.SNEASEL]: [
|
||||
new SpeciesEvolution(Species.WEAVILE, 1, EvolutionItem.RAZOR_CLAW, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor claw at night*/), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.WEAVILE, 1, EvolutionItem.RAZOR_CLAW, new TimeOfDayEvolutionCondition("night") /* Razor claw at night*/, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.URSARING]: [
|
||||
new SpeciesEvolution(Species.URSALUNA, 1, EvolutionItem.PEAT_BLOCK, null, SpeciesWildEvolutionDelay.VERY_LONG) //Ursaring does not evolve into Bloodmoon Ursaluna
|
||||
],
|
||||
[Species.PILOSWINE]: [
|
||||
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new MoveEvolutionCondition(Moves.ANCIENT_POWER), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.STANTLER]: [
|
||||
new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.WYRDEER, 25, null, new MoveEvolutionCondition(Moves.PSYSHIELD_BASH), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.LOMBRE]: [
|
||||
new SpeciesEvolution(Species.LUDICOLO, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -1388,11 +1573,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.ROSERADE, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.BONSLY]: [
|
||||
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new MoveEvolutionCondition(Moves.MIMIC), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.MIME_JR]: [
|
||||
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)), SpeciesWildEvolutionDelay.MEDIUM),
|
||||
new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new MoveTimeOfDayEvolutionCondition(Moves.MIMIC, "night"), SpeciesWildEvolutionDelay.MEDIUM),
|
||||
new SpeciesEvolution(Species.MR_MIME, 1, null, new MoveTimeOfDayEvolutionCondition(Moves.MIMIC, "day"), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.PANSAGE]: [
|
||||
new SpeciesEvolution(Species.SIMISAGE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -1414,8 +1599,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.LILLIGANT, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.BASCULIN]: [
|
||||
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "female", 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "male", 40, null, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "female", 40, null, new GenderEvolutionCondition(Gender.FEMALE), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesFormEvolution(Species.BASCULEGION, "white-striped", "male", 40, null, new GenderEvolutionCondition(Gender.MALE), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.MINCCINO]: [
|
||||
new SpeciesEvolution(Species.CINCCINO, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -1442,15 +1627,15 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.ROCKRUFF]: [
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "dusk", 25, null, null),
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new TimeOfDayEvolutionCondition("day")),
|
||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new TimeOfDayEvolutionCondition("night"))
|
||||
],
|
||||
[Species.STEENEE]: [
|
||||
new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.TSAREENA, 28, null, new MoveEvolutionCondition(Moves.STOMP), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.POIPOLE]: [
|
||||
new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.NAGANADEL, 1, null, new MoveEvolutionCondition(Moves.DRAGON_PULSE), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.ALOLA_SANDSHREW]: [
|
||||
new SpeciesEvolution(Species.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -1464,22 +1649,40 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.APPLETUN, 1, EvolutionItem.SWEET_APPLE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.CLOBBOPUS]: [
|
||||
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TAUNT).length > 0)/*Once Taunt is implemented, change evo level to 1 and delay to LONG*/)
|
||||
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new MoveEvolutionCondition(Moves.TAUNT)/*Once Taunt is implemented, change evo level to 1 and delay to LONG*/)
|
||||
],
|
||||
[Species.SINISTEA]: [
|
||||
new SpeciesFormEvolution(Species.POLTEAGEIST, "phony", "phony", 1, EvolutionItem.CRACKED_POT, null, SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.POLTEAGEIST, "antique", "antique", 1, EvolutionItem.CHIPPED_POT, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.MILCERY]: [
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "vanilla-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.TOWN || p.scene.arena.biomeType === Biome.PLAINS || p.scene.arena.biomeType === Biome.GRASS || p.scene.arena.biomeType === Biome.TALL_GRASS || p.scene.arena.biomeType === Biome.METROPOLIS), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.BADLANDS || p.scene.arena.biomeType === Biome.VOLCANO || p.scene.arena.biomeType === Biome.GRAVEYARD || p.scene.arena.biomeType === Biome.FACTORY || p.scene.arena.biomeType === Biome.SLUM), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "matcha-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.FOREST || p.scene.arena.biomeType === Biome.SWAMP || p.scene.arena.biomeType === Biome.MEADOW || p.scene.arena.biomeType === Biome.JUNGLE), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "mint-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.SEA || p.scene.arena.biomeType === Biome.BEACH || p.scene.arena.biomeType === Biome.LAKE || p.scene.arena.biomeType === Biome.SEABED), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "lemon-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.DESERT || p.scene.arena.biomeType === Biome.POWER_PLANT || p.scene.arena.biomeType === Biome.DOJO || p.scene.arena.biomeType === Biome.RUINS || p.scene.arena.biomeType === Biome.CONSTRUCTION_SITE), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "salted-cream", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.MOUNTAIN || p.scene.arena.biomeType === Biome.CAVE || p.scene.arena.biomeType === Biome.ICE_CAVE || p.scene.arena.biomeType === Biome.FAIRY_CAVE || p.scene.arena.biomeType === Biome.SNOWY_FOREST), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.WASTELAND || p.scene.arena.biomeType === Biome.LABORATORY), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "caramel-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.TEMPLE || p.scene.arena.biomeType === Biome.ISLAND), SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "rainbow-swirl", 1, EvolutionItem.STRAWBERRY_SWEET, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType === Biome.ABYSS || p.scene.arena.biomeType === Biome.SPACE || p.scene.arena.biomeType === Biome.END), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "vanilla-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.TOWN, Biome.PLAINS, Biome.GRASS, Biome.TALL_GRASS, Biome.METROPOLIS ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.BADLANDS, Biome.VOLCANO, Biome.GRAVEYARD, Biome.FACTORY, Biome.SLUM ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "matcha-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.FOREST, Biome.SWAMP, Biome.MEADOW, Biome.JUNGLE ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "mint-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.SEA, Biome.BEACH, Biome.LAKE, Biome.SEABED ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "lemon-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.DESERT, Biome.POWER_PLANT, Biome.DOJO, Biome.RUINS, Biome.CONSTRUCTION_SITE ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "salted-cream", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.MOUNTAIN, Biome.CAVE, Biome.ICE_CAVE, Biome.FAIRY_CAVE, Biome.SNOWY_FOREST ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "ruby-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.WASTELAND, Biome.LABORATORY ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "caramel-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.TEMPLE, Biome.ISLAND ]),
|
||||
SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesFormEvolution(Species.ALCREMIE, "", "rainbow-swirl", 1, EvolutionItem.STRAWBERRY_SWEET,
|
||||
new BiomeEvolutionCondition([ Biome.ABYSS, Biome.SPACE, Biome.END ]),
|
||||
SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.DURALUDON]: [
|
||||
new SpeciesFormEvolution(Species.ARCHALUDON, "", "", 1, EvolutionItem.METAL_ALLOY, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1498,10 +1701,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.HISUI_ELECTRODE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.HISUI_QWILFISH]: [
|
||||
new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.OVERQWIL, 28, null, new MoveEvolutionCondition(Moves.BARB_BARRAGE), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.HISUI_SNEASEL]: [
|
||||
new SpeciesEvolution(Species.SNEASLER, 1, EvolutionItem.RAZOR_CLAW, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY /* Razor claw at day*/), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.SNEASLER, 1, EvolutionItem.RAZOR_CLAW, new TimeOfDayEvolutionCondition("day") /* Razor claw at day*/, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.CHARCADET]: [
|
||||
new SpeciesEvolution(Species.ARMAROUGE, 1, EvolutionItem.AUSPICIOUS_ARMOR, null, SpeciesWildEvolutionDelay.LONG),
|
||||
|
@ -1521,7 +1724,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesFormEvolution(Species.SINISTCHA, "artisan", "masterpiece", 1, EvolutionItem.MASTERPIECE_TEACUP, null, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.DIPPLIN]: [
|
||||
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new MoveEvolutionCondition(Moves.DRAGON_CHEER), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.KADABRA]: [
|
||||
new SpeciesEvolution(Species.ALAKAZAM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1536,9 +1739,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.GENGAR, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.ONIX]: [
|
||||
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
||||
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
|
||||
SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new MoveTypeEvolutionCondition(Type.STEEL), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.RHYDON]: [
|
||||
new SpeciesEvolution(Species.RHYPERIOR, 1, EvolutionItem.PROTECTOR, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1547,9 +1748,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.KINGDRA, 1, EvolutionItem.DRAGON_SCALE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.SCYTHER]: [
|
||||
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
||||
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
|
||||
SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new MoveTypeEvolutionCondition(Type.STEEL), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesEvolution(Species.KLEAVOR, 1, EvolutionItem.BLACK_AUGURITE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.ELECTABUZZ]: [
|
||||
|
@ -1571,8 +1770,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.DUSKNOIR, 1, EvolutionItem.REAPER_CLOTH, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.CLAMPERL]: [
|
||||
new SpeciesEvolution(Species.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.gender === Gender.MALE, p => p.gender = Gender.MALE /* Deep Sea Tooth */), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesEvolution(Species.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE /* Deep Sea Scale */), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new GenderEvolutionCondition(Gender.MALE /* Deep Sea Tooth */), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesEvolution(Species.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new GenderEvolutionCondition(Gender.FEMALE /* Deep Sea Scale */), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.BOLDORE]: [
|
||||
new SpeciesEvolution(Species.GIGALITH, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1581,10 +1780,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.CONKELDURR, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.KARRABLAST]: [
|
||||
new SpeciesEvolution(Species.ESCAVALIER, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.gameData.dexData[Species.SHELMET].caughtAttr), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.ESCAVALIER, 1, EvolutionItem.LINKING_CORD, new CaughtEvolutionCondition(Species.SHELMET), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.SHELMET]: [
|
||||
new SpeciesEvolution(Species.ACCELGOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.gameData.dexData[Species.KARRABLAST].caughtAttr), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.ACCELGOR, 1, EvolutionItem.LINKING_CORD, new CaughtEvolutionCondition(Species.KARRABLAST), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.SPRITZEE]: [
|
||||
new SpeciesEvolution(Species.AROMATISSE, 1, EvolutionItem.SACHET, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
|
@ -1602,72 +1801,66 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||
new SpeciesEvolution(Species.ALOLA_GOLEM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.PRIMEAPE]: [
|
||||
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new MoveEvolutionCondition(Moves.RAGE_FIST), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.GOLBAT]: [
|
||||
new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.CROBAT, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.CHANSEY]: [
|
||||
new SpeciesEvolution(Species.BLISSEY, 1, null, new SpeciesFriendshipEvolutionCondition(200), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.BLISSEY, 1, null, new FriendshipEvolutionCondition(200), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.PICHU]: [
|
||||
new SpeciesFormEvolution(Species.PIKACHU, "spiky", "partner", 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
|
||||
new SpeciesFormEvolution(Species.PIKACHU, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
|
||||
new SpeciesFormEvolution(Species.PIKACHU, "spiky", "partner", 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
|
||||
new SpeciesFormEvolution(Species.PIKACHU, "", "", 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.SHORT),
|
||||
],
|
||||
[Species.CLEFFA]: [
|
||||
new SpeciesEvolution(Species.CLEFAIRY, 1, null, new SpeciesFriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.CLEFAIRY, 1, null, new FriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.IGGLYBUFF]: [
|
||||
new SpeciesEvolution(Species.JIGGLYPUFF, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.JIGGLYPUFF, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.TOGEPI]: [
|
||||
new SpeciesEvolution(Species.TOGETIC, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.TOGETIC, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.AZURILL]: [
|
||||
new SpeciesEvolution(Species.MARILL, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.MARILL, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.BUDEW]: [
|
||||
new SpeciesEvolution(Species.ROSELIA, 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.ROSELIA, 1, null, new FriendshipTimeOfDayEvolutionCondition(70, "day"), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.BUNEARY]: [
|
||||
new SpeciesEvolution(Species.LOPUNNY, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.LOPUNNY, 1, null, new FriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.CHINGLING]: [
|
||||
new SpeciesEvolution(Species.CHIMECHO, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.CHIMECHO, 1, null, new FriendshipTimeOfDayEvolutionCondition(90, "night"), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.HAPPINY]: [
|
||||
new SpeciesEvolution(Species.CHANSEY, 1, null, new SpeciesFriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
|
||||
new SpeciesEvolution(Species.CHANSEY, 1, null, new FriendshipEvolutionCondition(160), SpeciesWildEvolutionDelay.SHORT)
|
||||
],
|
||||
[Species.MUNCHLAX]: [
|
||||
new SpeciesEvolution(Species.SNORLAX, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.SNORLAX, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.RIOLU]: [
|
||||
new SpeciesEvolution(Species.LUCARIO, 1, null, new SpeciesFriendshipEvolutionCondition(120, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.LUCARIO, 1, null, new FriendshipTimeOfDayEvolutionCondition(120, "day"), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.WOOBAT]: [
|
||||
new SpeciesEvolution(Species.SWOOBAT, 1, null, new SpeciesFriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.SWOOBAT, 1, null, new FriendshipEvolutionCondition(90), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.SWADLOON]: [
|
||||
new SpeciesEvolution(Species.LEAVANNY, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.LEAVANNY, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.TYPE_NULL]: [
|
||||
new SpeciesEvolution(Species.SILVALLY, 1, null, new SpeciesFriendshipEvolutionCondition(100), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.SILVALLY, 1, null, new FriendshipEvolutionCondition(100), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.ALOLA_MEOWTH]: [
|
||||
new SpeciesEvolution(Species.ALOLA_PERSIAN, 1, null, new SpeciesFriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(Species.ALOLA_PERSIAN, 1, null, new FriendshipEvolutionCondition(120), SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[Species.SNOM]: [
|
||||
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
new SpeciesEvolution(Species.FROSMOTH, 1, null, new FriendshipTimeOfDayEvolutionCondition(90, "night"), SpeciesWildEvolutionDelay.MEDIUM)
|
||||
],
|
||||
[Species.GIMMIGHOUL]: [
|
||||
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
|
||||
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|
||||
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter
|
||||
+ p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length
|
||||
+ p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier
|
||||
|| m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new TreasureEvolutionCondition(), SpeciesWildEvolutionDelay.VERY_LONG),
|
||||
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new TreasureEvolutionCondition(), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -1690,3 +1883,19 @@ export function initPokemonPrevolutions(): void {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// TODO: This may cause funny business for double starters such as Pichu/Pikachu
|
||||
export const pokemonStarters: PokemonPrevolutions = {};
|
||||
|
||||
export function initPokemonStarters(): void {
|
||||
const starterKeys = Object.keys(pokemonPrevolutions);
|
||||
starterKeys.forEach(pk => {
|
||||
const prevolution = pokemonPrevolutions[pk];
|
||||
if (speciesStarterCosts.hasOwnProperty(prevolution)) {
|
||||
pokemonStarters[pk] = prevolution;
|
||||
} else {
|
||||
pokemonStarters[pk] = pokemonPrevolutions[prevolution];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19718,6 +19718,44 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||
[ 48, Moves.CLOSE_COMBAT ],
|
||||
[ 52, Moves.FOCUS_PUNCH ],
|
||||
],
|
||||
2: [
|
||||
[ EVOLVE_MOVE, Moves.WICKED_BLOW ],
|
||||
[ 1, Moves.LEER ],
|
||||
[ 1, Moves.FOCUS_ENERGY ],
|
||||
[ 1, Moves.ENDURE ],
|
||||
[ 1, Moves.ROCK_SMASH ],
|
||||
[ 1, Moves.SUCKER_PUNCH ],
|
||||
[ 12, Moves.AERIAL_ACE ],
|
||||
[ 16, Moves.SCARY_FACE ],
|
||||
[ 20, Moves.HEADBUTT ],
|
||||
[ 24, Moves.BRICK_BREAK ],
|
||||
[ 28, Moves.DETECT ],
|
||||
[ 32, Moves.BULK_UP ],
|
||||
[ 36, Moves.IRON_HEAD ],
|
||||
[ 40, Moves.DYNAMIC_PUNCH ],
|
||||
[ 44, Moves.COUNTER ],
|
||||
[ 48, Moves.CLOSE_COMBAT ],
|
||||
[ 52, Moves.FOCUS_PUNCH ],
|
||||
],
|
||||
3: [
|
||||
[ EVOLVE_MOVE, Moves.SURGING_STRIKES ],
|
||||
[ 1, Moves.LEER ],
|
||||
[ 1, Moves.FOCUS_ENERGY ],
|
||||
[ 1, Moves.ENDURE ],
|
||||
[ 1, Moves.ROCK_SMASH ],
|
||||
[ 1, Moves.AQUA_JET ],
|
||||
[ 12, Moves.AERIAL_ACE ],
|
||||
[ 16, Moves.SCARY_FACE ],
|
||||
[ 20, Moves.HEADBUTT ],
|
||||
[ 24, Moves.BRICK_BREAK ],
|
||||
[ 28, Moves.DETECT ],
|
||||
[ 32, Moves.BULK_UP ],
|
||||
[ 36, Moves.IRON_HEAD ],
|
||||
[ 40, Moves.DYNAMIC_PUNCH ],
|
||||
[ 44, Moves.COUNTER ],
|
||||
[ 48, Moves.CLOSE_COMBAT ],
|
||||
[ 52, Moves.FOCUS_PUNCH ],
|
||||
],
|
||||
},
|
||||
[Species.CALYREX]: {
|
||||
1: [
|
||||
|
|
|
@ -51,9 +51,7 @@ export const speciesStarterCosts = {
|
|||
[Species.SANDSHREW]: 2,
|
||||
[Species.NIDORAN_F]: 3,
|
||||
[Species.NIDORAN_M]: 3,
|
||||
[Species.CLEFAIRY]: 3,
|
||||
[Species.VULPIX]: 3,
|
||||
[Species.JIGGLYPUFF]: 2,
|
||||
[Species.ZUBAT]: 3,
|
||||
[Species.ODDISH]: 3,
|
||||
[Species.PARAS]: 2,
|
||||
|
@ -84,22 +82,15 @@ export const speciesStarterCosts = {
|
|||
[Species.VOLTORB]: 2,
|
||||
[Species.EXEGGCUTE]: 3,
|
||||
[Species.CUBONE]: 3,
|
||||
[Species.HITMONLEE]: 4,
|
||||
[Species.HITMONCHAN]: 4,
|
||||
[Species.LICKITUNG]: 3,
|
||||
[Species.KOFFING]: 2,
|
||||
[Species.RHYHORN]: 4,
|
||||
[Species.CHANSEY]: 3,
|
||||
[Species.TANGELA]: 3,
|
||||
[Species.KANGASKHAN]: 4,
|
||||
[Species.HORSEA]: 3,
|
||||
[Species.GOLDEEN]: 2,
|
||||
[Species.STARYU]: 3,
|
||||
[Species.MR_MIME]: 3,
|
||||
[Species.SCYTHER]: 5,
|
||||
[Species.JYNX]: 4,
|
||||
[Species.ELECTABUZZ]: 4,
|
||||
[Species.MAGMAR]: 4,
|
||||
[Species.PINSIR]: 4,
|
||||
[Species.TAUROS]: 4,
|
||||
[Species.MAGIKARP]: 4,
|
||||
|
@ -110,7 +101,6 @@ export const speciesStarterCosts = {
|
|||
[Species.OMANYTE]: 3,
|
||||
[Species.KABUTO]: 3,
|
||||
[Species.AERODACTYL]: 5,
|
||||
[Species.SNORLAX]: 5,
|
||||
[Species.ARTICUNO]: 5,
|
||||
[Species.ZAPDOS]: 6,
|
||||
[Species.MOLTRES]: 6,
|
||||
|
@ -132,8 +122,6 @@ export const speciesStarterCosts = {
|
|||
[Species.TOGEPI]: 3,
|
||||
[Species.NATU]: 2,
|
||||
[Species.MAREEP]: 2,
|
||||
[Species.MARILL]: 4,
|
||||
[Species.SUDOWOODO]: 3,
|
||||
[Species.HOPPIP]: 2,
|
||||
[Species.AIPOM]: 2,
|
||||
[Species.SUNKERN]: 1,
|
||||
|
@ -142,7 +130,6 @@ export const speciesStarterCosts = {
|
|||
[Species.MURKROW]: 3,
|
||||
[Species.MISDREAVUS]: 2,
|
||||
[Species.UNOWN]: 1,
|
||||
[Species.WOBBUFFET]: 2,
|
||||
[Species.GIRAFARIG]: 3,
|
||||
[Species.PINECO]: 2,
|
||||
[Species.DUNSPARCE]: 3,
|
||||
|
@ -158,7 +145,6 @@ export const speciesStarterCosts = {
|
|||
[Species.CORSOLA]: 2,
|
||||
[Species.REMORAID]: 2,
|
||||
[Species.DELIBIRD]: 2,
|
||||
[Species.MANTINE]: 3,
|
||||
[Species.SKARMORY]: 4,
|
||||
[Species.HOUNDOUR]: 3,
|
||||
[Species.PHANPY]: 3,
|
||||
|
@ -206,7 +192,6 @@ export const speciesStarterCosts = {
|
|||
[Species.MINUN]: 2,
|
||||
[Species.VOLBEAT]: 2,
|
||||
[Species.ILLUMISE]: 2,
|
||||
[Species.ROSELIA]: 3,
|
||||
[Species.GULPIN]: 1,
|
||||
[Species.CARVANHA]: 3,
|
||||
[Species.WAILMER]: 2,
|
||||
|
@ -232,7 +217,6 @@ export const speciesStarterCosts = {
|
|||
[Species.SHUPPET]: 2,
|
||||
[Species.DUSKULL]: 3,
|
||||
[Species.TROPIUS]: 3,
|
||||
[Species.CHIMECHO]: 3,
|
||||
[Species.ABSOL]: 4,
|
||||
[Species.WYNAUT]: 2,
|
||||
[Species.SNORUNT]: 2,
|
||||
|
@ -543,7 +527,6 @@ export const speciesStarterCosts = {
|
|||
[Species.GALAR_PONYTA]: 2,
|
||||
[Species.GALAR_SLOWPOKE]: 3,
|
||||
[Species.GALAR_FARFETCHD]: 3,
|
||||
[Species.GALAR_MR_MIME]: 3,
|
||||
[Species.GALAR_ARTICUNO]: 6,
|
||||
[Species.GALAR_ZAPDOS]: 6,
|
||||
[Species.GALAR_MOLTRES]: 6,
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
//import { battleAnimRawData } from "./battle-anim-raw-data";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
|
||||
import Pokemon from "../field/pokemon";
|
||||
import type Pokemon from "../field/pokemon";
|
||||
import * as Utils from "../utils";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { Element } from "json-stable-stringify";
|
||||
import type { BattlerIndex } from "../battle";
|
||||
import type { Element } from "json-stable-stringify";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { SubstituteTag } from "./battler-tags";
|
||||
import { isNullOrUndefined } from "../utils";
|
||||
import Phaser from "phaser";
|
||||
import { EncounterAnim } from "#enums/encounter-anims";
|
||||
//import fs from 'vite-plugin-fs/browser';
|
||||
|
||||
export enum AnimFrameTarget {
|
||||
USER,
|
||||
|
@ -308,7 +306,7 @@ abstract class AnimTimedEvent {
|
|||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
abstract execute(scene: BattleScene, battleAnim: BattleAnim, priority?: number): integer;
|
||||
abstract execute(battleAnim: BattleAnim, priority?: number): integer;
|
||||
|
||||
abstract getEventType(): string;
|
||||
}
|
||||
|
@ -326,15 +324,15 @@ class AnimTimedSoundEvent extends AnimTimedEvent {
|
|||
}
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, battleAnim: BattleAnim, priority?: number): integer {
|
||||
execute(battleAnim: BattleAnim, priority?: number): integer {
|
||||
const soundConfig = { rate: (this.pitch * 0.01), volume: (this.volume * 0.01) };
|
||||
if (this.resourceName) {
|
||||
try {
|
||||
scene.playSound(`battle_anims/${this.resourceName}`, soundConfig);
|
||||
globalScene.playSound(`battle_anims/${this.resourceName}`, soundConfig);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return Math.ceil((scene.sound.get(`battle_anims/${this.resourceName}`).totalDuration * 1000) / 33.33);
|
||||
return Math.ceil((globalScene.sound.get(`battle_anims/${this.resourceName}`).totalDuration * 1000) / 33.33);
|
||||
} else {
|
||||
return Math.ceil((battleAnim.user!.cry(soundConfig).totalDuration * 1000) / 33.33); // TODO: is the bang behind user correct?
|
||||
}
|
||||
|
@ -388,7 +386,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
|||
super(frameIndex, resourceName, source);
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, moveAnim: MoveAnim, priority?: number): integer {
|
||||
execute(moveAnim: MoveAnim, priority?: number): integer {
|
||||
const tweenProps = {};
|
||||
if (this.bgX !== undefined) {
|
||||
tweenProps["x"] = (this.bgX * 0.5) - 320;
|
||||
|
@ -400,7 +398,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
|||
tweenProps["alpha"] = (this.opacity || 0) / 255;
|
||||
}
|
||||
if (Object.keys(tweenProps).length) {
|
||||
scene.tweens.add(Object.assign({
|
||||
globalScene.tweens.add(Object.assign({
|
||||
targets: moveAnim.bgSprite,
|
||||
duration: Utils.getFrameMs(this.duration * 3)
|
||||
}, tweenProps));
|
||||
|
@ -418,25 +416,25 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
|||
super(frameIndex, resourceName, source);
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, moveAnim: MoveAnim, priority?: number): integer {
|
||||
execute(moveAnim: MoveAnim, priority?: number): integer {
|
||||
if (moveAnim.bgSprite) {
|
||||
moveAnim.bgSprite.destroy();
|
||||
}
|
||||
moveAnim.bgSprite = this.resourceName
|
||||
? scene.add.tileSprite(this.bgX - 320, this.bgY - 284, 896, 576, this.resourceName)
|
||||
: scene.add.rectangle(this.bgX - 320, this.bgY - 284, 896, 576, 0);
|
||||
? globalScene.add.tileSprite(this.bgX - 320, this.bgY - 284, 896, 576, this.resourceName)
|
||||
: globalScene.add.rectangle(this.bgX - 320, this.bgY - 284, 896, 576, 0);
|
||||
moveAnim.bgSprite.setOrigin(0, 0);
|
||||
moveAnim.bgSprite.setScale(1.25);
|
||||
moveAnim.bgSprite.setAlpha(this.opacity / 255);
|
||||
scene.field.add(moveAnim.bgSprite);
|
||||
const fieldPokemon = scene.getEnemyPokemon(false) ?? scene.getPlayerPokemon(false);
|
||||
globalScene.field.add(moveAnim.bgSprite);
|
||||
const fieldPokemon = globalScene.getEnemyPokemon(false) ?? globalScene.getPlayerPokemon(false);
|
||||
if (!isNullOrUndefined(priority)) {
|
||||
scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority);
|
||||
globalScene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority);
|
||||
} else if (fieldPokemon?.isOnField()) {
|
||||
scene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon);
|
||||
globalScene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon);
|
||||
}
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: moveAnim.bgSprite,
|
||||
duration: Utils.getFrameMs(this.duration * 3)
|
||||
});
|
||||
|
@ -454,14 +452,14 @@ export const chargeAnims = new Map<ChargeAnim, AnimConfig | [AnimConfig, AnimCon
|
|||
export const commonAnims = new Map<CommonAnim, AnimConfig>();
|
||||
export const encounterAnims = new Map<EncounterAnim, AnimConfig>();
|
||||
|
||||
export function initCommonAnims(scene: BattleScene): Promise<void> {
|
||||
export function initCommonAnims(): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
|
||||
const commonAnimIds = Utils.getEnumValues(CommonAnim);
|
||||
const commonAnimFetches: Promise<Map<CommonAnim, AnimConfig>>[] = [];
|
||||
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
||||
const commonAnimId = commonAnimIds[ca];
|
||||
commonAnimFetches.push(scene.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
commonAnimFetches.push(globalScene.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
.then(response => response.json())
|
||||
.then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))));
|
||||
}
|
||||
|
@ -469,7 +467,7 @@ export function initCommonAnims(scene: BattleScene): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
||||
export function initMoveAnim(move: Moves): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (moveAnims.has(move)) {
|
||||
if (moveAnims.get(move) !== null) {
|
||||
|
@ -494,7 +492,7 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
|||
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
||||
|
||||
const fetchAnimAndResolve = (move: Moves) => {
|
||||
scene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
|
||||
globalScene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
|
||||
.then(response => {
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
||||
|
@ -516,7 +514,7 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
|||
: (allMoves[move].getAttrs(DelayedAttackAttr)[0]
|
||||
?? allMoves[move].getAttrs(BeakBlastHeaderAttr)[0]);
|
||||
if (chargeAnimSource) {
|
||||
initMoveChargeAnim(scene, chargeAnimSource.chargeAnim).then(() => resolve());
|
||||
initMoveChargeAnim(chargeAnimSource.chargeAnim).then(() => resolve());
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
|
@ -557,10 +555,9 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
|||
|
||||
/**
|
||||
* Fetches animation configs to be used in a Mystery Encounter
|
||||
* @param scene
|
||||
* @param encounterAnim one or more animations to fetch
|
||||
*/
|
||||
export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||
export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||
const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
|
||||
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
||||
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
|
||||
|
@ -568,14 +565,14 @@ export async function initEncounterAnims(scene: BattleScene, encounterAnim: Enco
|
|||
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
||||
continue;
|
||||
}
|
||||
encounterAnimFetches.push(scene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
encounterAnimFetches.push(globalScene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
.then(response => response.json())
|
||||
.then(cas => encounterAnims.set(anim, new AnimConfig(cas))));
|
||||
}
|
||||
await Promise.allSettled(encounterAnimFetches);
|
||||
}
|
||||
|
||||
export function initMoveChargeAnim(scene: BattleScene, chargeAnim: ChargeAnim): Promise<void> {
|
||||
export function initMoveChargeAnim(chargeAnim: ChargeAnim): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (chargeAnims.has(chargeAnim)) {
|
||||
if (chargeAnims.get(chargeAnim) !== null) {
|
||||
|
@ -590,7 +587,7 @@ export function initMoveChargeAnim(scene: BattleScene, chargeAnim: ChargeAnim):
|
|||
}
|
||||
} else {
|
||||
chargeAnims.set(chargeAnim, null);
|
||||
scene.cachedFetch(`./battle-anims/${ChargeAnim[chargeAnim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
globalScene.cachedFetch(`./battle-anims/${ChargeAnim[chargeAnim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||
.then(response => response.json())
|
||||
.then(ca => {
|
||||
if (Array.isArray(ca)) {
|
||||
|
@ -623,23 +620,22 @@ function populateMoveChargeAnim(chargeAnim: ChargeAnim, animSource: any) {
|
|||
chargeAnims.set(chargeAnim, [ chargeAnims.get(chargeAnim) as AnimConfig, moveChargeAnim ]);
|
||||
}
|
||||
|
||||
export function loadCommonAnimAssets(scene: BattleScene, startLoad?: boolean): Promise<void> {
|
||||
export function loadCommonAnimAssets(startLoad?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
loadAnimAssets(scene, Array.from(commonAnims.values()), startLoad).then(() => resolve());
|
||||
loadAnimAssets(Array.from(commonAnims.values()), startLoad).then(() => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads encounter animation assets to scene
|
||||
* MUST be called after {@linkcode initEncounterAnims()} to load all required animations properly
|
||||
* @param scene
|
||||
* @param startLoad
|
||||
*/
|
||||
export async function loadEncounterAnimAssets(scene: BattleScene, startLoad?: boolean): Promise<void> {
|
||||
await loadAnimAssets(scene, Array.from(encounterAnims.values()), startLoad);
|
||||
export async function loadEncounterAnimAssets(startLoad?: boolean): Promise<void> {
|
||||
await loadAnimAssets(Array.from(encounterAnims.values()), startLoad);
|
||||
}
|
||||
|
||||
export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLoad?: boolean): Promise<void> {
|
||||
export function loadMoveAnimAssets(moveIds: Moves[], startLoad?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
|
||||
for (const moveId of moveIds) {
|
||||
|
@ -655,11 +651,11 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo
|
|||
}
|
||||
}
|
||||
}
|
||||
loadAnimAssets(scene, moveAnimations, startLoad).then(() => resolve());
|
||||
loadAnimAssets(moveAnimations, startLoad).then(() => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
function loadAnimAssets(scene: BattleScene, anims: AnimConfig[], startLoad?: boolean): Promise<void> {
|
||||
function loadAnimAssets(anims: AnimConfig[], startLoad?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const backgrounds = new Set<string>();
|
||||
const sounds = new Set<string>();
|
||||
|
@ -676,19 +672,19 @@ function loadAnimAssets(scene: BattleScene, anims: AnimConfig[], startLoad?: boo
|
|||
backgrounds.add(abg);
|
||||
}
|
||||
if (a.graphic) {
|
||||
scene.loadSpritesheet(a.graphic, "battle_anims", 96);
|
||||
globalScene.loadSpritesheet(a.graphic, "battle_anims", 96);
|
||||
}
|
||||
}
|
||||
for (const bg of backgrounds) {
|
||||
scene.loadImage(bg, "battle_anims");
|
||||
globalScene.loadImage(bg, "battle_anims");
|
||||
}
|
||||
for (const s of sounds) {
|
||||
scene.loadSe(s, "battle_anims", s);
|
||||
globalScene.loadSe(s, "battle_anims", s);
|
||||
}
|
||||
if (startLoad) {
|
||||
scene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
|
||||
if (!scene.load.isLoading()) {
|
||||
scene.load.start();
|
||||
globalScene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
|
||||
if (!globalScene.load.isLoading()) {
|
||||
globalScene.load.start();
|
||||
}
|
||||
} else {
|
||||
resolve();
|
||||
|
@ -778,7 +774,7 @@ export abstract class BattleAnim {
|
|||
return false;
|
||||
}
|
||||
|
||||
private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
|
||||
private getGraphicFrameData(frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
|
||||
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
|
||||
[ AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
||||
[ AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
||||
|
@ -835,7 +831,7 @@ export abstract class BattleAnim {
|
|||
return ret;
|
||||
}
|
||||
|
||||
play(scene: BattleScene, onSubstitute?: boolean, callback?: Function) {
|
||||
play(onSubstitute?: boolean, callback?: Function) {
|
||||
const isOppAnim = this.isOppAnim();
|
||||
const user = !isOppAnim ? this.user! : this.target!; // TODO: are those bangs correct?
|
||||
const target = !isOppAnim ? this.target! : this.user!;
|
||||
|
@ -907,7 +903,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
};
|
||||
|
||||
if (!scene.moveAnimations && !this.playRegardlessOfIssues) {
|
||||
if (!globalScene.moveAnimations && !this.playRegardlessOfIssues) {
|
||||
return cleanUpAndComplete();
|
||||
}
|
||||
|
||||
|
@ -924,7 +920,7 @@ export abstract class BattleAnim {
|
|||
let r = anim?.frames.length ?? 0;
|
||||
let f = 0;
|
||||
|
||||
scene.tweens.addCounter({
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(3),
|
||||
repeat: anim?.frames.length ?? 0,
|
||||
onRepeat: () => {
|
||||
|
@ -934,7 +930,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
|
||||
const spriteFrames = anim!.frames[f]; // TODO: is the bang correcT?
|
||||
const frameData = this.getGraphicFrameData(scene, anim!.frames[f], onSubstitute); // TODO: is the bang correct?
|
||||
const frameData = this.getGraphicFrameData(anim!.frames[f], onSubstitute); // TODO: is the bang correct?
|
||||
let u = 0;
|
||||
let t = 0;
|
||||
let g = 0;
|
||||
|
@ -950,19 +946,19 @@ export abstract class BattleAnim {
|
|||
const spriteSource = isUser ? userSprite : targetSprite;
|
||||
if ((isUser ? u : t) === sprites.length) {
|
||||
if (isUser || !targetSubstitute) {
|
||||
const sprite = scene.addPokemonSprite(isUser ? user! : target, 0, 0, spriteSource!.texture, spriteSource!.frame.name, true); // TODO: are those bangs correct?
|
||||
const sprite = globalScene.addPokemonSprite(isUser ? user! : target, 0, 0, spriteSource!.texture, spriteSource!.frame.name, true); // TODO: are those bangs correct?
|
||||
[ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = (isUser ? user! : target).getSprite().pipelineData[k]); // TODO: are those bangs correct?
|
||||
sprite.setPipelineData("spriteKey", (isUser ? user! : target).getBattleSpriteKey());
|
||||
sprite.setPipelineData("shiny", (isUser ? user : target).shiny);
|
||||
sprite.setPipelineData("variant", (isUser ? user : target).variant);
|
||||
sprite.setPipelineData("ignoreFieldPos", true);
|
||||
spriteSource.on("animationupdate", (_anim, frame) => sprite.setFrame(frame.textureFrame));
|
||||
scene.field.add(sprite);
|
||||
globalScene.field.add(sprite);
|
||||
sprites.push(sprite);
|
||||
} else {
|
||||
const sprite = scene.addFieldSprite(spriteSource.x, spriteSource.y, spriteSource.texture);
|
||||
const sprite = globalScene.addFieldSprite(spriteSource.x, spriteSource.y, spriteSource.texture);
|
||||
spriteSource.on("animationupdate", (_anim, frame) => sprite.setFrame(frame.textureFrame));
|
||||
scene.field.add(sprite);
|
||||
globalScene.field.add(sprite);
|
||||
sprites.push(sprite);
|
||||
}
|
||||
}
|
||||
|
@ -987,9 +983,9 @@ export abstract class BattleAnim {
|
|||
} else {
|
||||
const sprites = spriteCache[AnimFrameTarget.GRAPHIC];
|
||||
if (g === sprites.length) {
|
||||
const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim!.graphic, 1); // TODO: is the bang correct?
|
||||
const newSprite: Phaser.GameObjects.Sprite = globalScene.addFieldSprite(0, 0, anim!.graphic, 1); // TODO: is the bang correct?
|
||||
sprites.push(newSprite);
|
||||
scene.field.add(newSprite);
|
||||
globalScene.field.add(newSprite);
|
||||
spritePriorities.push(1);
|
||||
}
|
||||
|
||||
|
@ -1000,22 +996,22 @@ export abstract class BattleAnim {
|
|||
const setSpritePriority = (priority: integer) => {
|
||||
switch (priority) {
|
||||
case 0:
|
||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, scene.getEnemyPokemon(false) ?? scene.getPlayerPokemon(false)!); // TODO: is this bang correct?
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, globalScene.getEnemyPokemon(false) ?? globalScene.getPlayerPokemon(false)!); // TODO: is this bang correct?
|
||||
break;
|
||||
case 1:
|
||||
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
||||
globalScene.field.moveTo(moveSprite, globalScene.field.getAll().length - 1);
|
||||
break;
|
||||
case 2:
|
||||
switch (frame.focus) {
|
||||
case AnimFocus.USER:
|
||||
if (this.bgSprite) {
|
||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
||||
} else {
|
||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
}
|
||||
break;
|
||||
case AnimFocus.TARGET:
|
||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
break;
|
||||
default:
|
||||
setSpritePriority(1);
|
||||
|
@ -1025,10 +1021,10 @@ export abstract class BattleAnim {
|
|||
case 3:
|
||||
switch (frame.focus) {
|
||||
case AnimFocus.USER:
|
||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||
break;
|
||||
case AnimFocus.TARGET:
|
||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||
break;
|
||||
default:
|
||||
setSpritePriority(1);
|
||||
|
@ -1056,7 +1052,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
if (anim?.frameTimedEvents.has(f)) {
|
||||
for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct?
|
||||
r = Math.max((anim.frames.length - f) + event.execute(scene, this), r);
|
||||
r = Math.max((anim.frames.length - f) + event.execute(this), r);
|
||||
}
|
||||
}
|
||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
||||
|
@ -1086,7 +1082,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
}
|
||||
if (r) {
|
||||
scene.tweens.addCounter({
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(r),
|
||||
onComplete: () => cleanUpAndComplete()
|
||||
});
|
||||
|
@ -1123,8 +1119,6 @@ export abstract class BattleAnim {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scene
|
||||
* @param targetInitialX
|
||||
* @param targetInitialY
|
||||
* @param frameTimeMult
|
||||
|
@ -1135,7 +1129,7 @@ export abstract class BattleAnim {
|
|||
* - 5 is on top of player sprite
|
||||
* @param callback
|
||||
*/
|
||||
playWithoutTargets(scene: BattleScene, targetInitialX: number, targetInitialY: number, frameTimeMult: number, frameTimedEventPriority?: 0 | 1 | 3 | 5, callback?: Function) {
|
||||
playWithoutTargets(targetInitialX: number, targetInitialY: number, frameTimeMult: number, frameTimedEventPriority?: 0 | 1 | 3 | 5, callback?: Function) {
|
||||
const spriteCache: SpriteCache = {
|
||||
[AnimFrameTarget.GRAPHIC]: [],
|
||||
[AnimFrameTarget.USER]: [],
|
||||
|
@ -1156,7 +1150,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
};
|
||||
|
||||
if (!scene.moveAnimations && !this.playRegardlessOfIssues) {
|
||||
if (!globalScene.moveAnimations && !this.playRegardlessOfIssues) {
|
||||
return cleanUpAndComplete();
|
||||
}
|
||||
|
||||
|
@ -1168,13 +1162,13 @@ export abstract class BattleAnim {
|
|||
let totalFrames = anim!.frames.length;
|
||||
let frameCount = 0;
|
||||
|
||||
let existingFieldSprites = scene.field.getAll().slice(0);
|
||||
let existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||
|
||||
scene.tweens.addCounter({
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(3) * frameTimeMult,
|
||||
repeat: anim!.frames.length,
|
||||
onRepeat: () => {
|
||||
existingFieldSprites = scene.field.getAll().slice(0);
|
||||
existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||
const spriteFrames = anim!.frames[frameCount];
|
||||
const frameData = this.getGraphicFrameDataWithoutTarget(anim!.frames[frameCount], targetInitialX, targetInitialY);
|
||||
let graphicFrameCount = 0;
|
||||
|
@ -1186,9 +1180,9 @@ export abstract class BattleAnim {
|
|||
|
||||
const sprites = spriteCache[AnimFrameTarget.GRAPHIC];
|
||||
if (graphicFrameCount === sprites.length) {
|
||||
const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim!.graphic, 1);
|
||||
const newSprite: Phaser.GameObjects.Sprite = globalScene.addFieldSprite(0, 0, anim!.graphic, 1);
|
||||
sprites.push(newSprite);
|
||||
scene.field.add(newSprite);
|
||||
globalScene.field.add(newSprite);
|
||||
}
|
||||
|
||||
const graphicIndex = graphicFrameCount++;
|
||||
|
@ -1197,11 +1191,11 @@ export abstract class BattleAnim {
|
|||
const setSpritePriority = (priority: integer) => {
|
||||
if (existingFieldSprites.length > priority) {
|
||||
// Move to specified priority index
|
||||
const index = scene.field.getIndex(existingFieldSprites[priority]);
|
||||
scene.field.moveTo(moveSprite, index);
|
||||
const index = globalScene.field.getIndex(existingFieldSprites[priority]);
|
||||
globalScene.field.moveTo(moveSprite, index);
|
||||
} else {
|
||||
// Move to top of scene
|
||||
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
||||
globalScene.field.moveTo(moveSprite, globalScene.field.getAll().length - 1);
|
||||
}
|
||||
};
|
||||
setSpritePriority(frame.priority);
|
||||
|
@ -1221,7 +1215,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
if (anim?.frameTimedEvents.get(frameCount)) {
|
||||
for (const event of anim.frameTimedEvents.get(frameCount)!) {
|
||||
totalFrames = Math.max((anim.frames.length - frameCount) + event.execute(scene, this, frameTimedEventPriority), totalFrames);
|
||||
totalFrames = Math.max((anim.frames.length - frameCount) + event.execute(this, frameTimedEventPriority), totalFrames);
|
||||
}
|
||||
}
|
||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
||||
|
@ -1248,7 +1242,7 @@ export abstract class BattleAnim {
|
|||
}
|
||||
}
|
||||
if (totalFrames) {
|
||||
scene.tweens.addCounter({
|
||||
globalScene.tweens.addCounter({
|
||||
duration: Utils.getFrameMs(totalFrames),
|
||||
onComplete: () => cleanUpAndComplete()
|
||||
});
|
||||
|
@ -1282,7 +1276,7 @@ export class MoveAnim extends BattleAnim {
|
|||
public move: Moves;
|
||||
|
||||
constructor(move: Moves, user: Pokemon, target: BattlerIndex, playOnEmptyField: boolean = false) {
|
||||
super(user, user.scene.getField()[target], playOnEmptyField);
|
||||
super(user, globalScene.getField()[target], playOnEmptyField);
|
||||
|
||||
this.move = move;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { getPokemonNameWithAffix } from "../messages";
|
||||
import Pokemon, { HitResult } from "../field/pokemon";
|
||||
import type Pokemon from "../field/pokemon";
|
||||
import { HitResult } from "../field/pokemon";
|
||||
import { getStatusEffectHealText } from "./status-effect";
|
||||
import * as Utils from "../utils";
|
||||
import { DoubleBerryEffectAbAttr, PostItemLostAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs, applyPostItemLostAbAttrs } from "./ability";
|
||||
|
@ -9,6 +10,7 @@ import { BerryType } from "#enums/berry-type";
|
|||
import { Stat, type BattleStat } from "#app/enums/stat";
|
||||
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
|
||||
export function getBerryName(berryType: BerryType): string {
|
||||
return i18next.t(`berry:${BerryType[berryType]}.name`);
|
||||
|
@ -73,7 +75,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
}
|
||||
const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4));
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed);
|
||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
|
||||
globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
|
||||
hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true));
|
||||
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
|
||||
};
|
||||
|
@ -83,7 +85,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
pokemon.battleData.berriesEaten.push(berryType);
|
||||
}
|
||||
if (pokemon.status) {
|
||||
pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
||||
globalScene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
||||
}
|
||||
pokemon.resetStatus(true, true);
|
||||
pokemon.updateInfo();
|
||||
|
@ -102,7 +104,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
const stat: BattleStat = berryType - BerryType.ENIGMA;
|
||||
const statStages = new Utils.NumberHolder(1);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], statStages.value));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ stat ], statStages.value));
|
||||
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
|
||||
};
|
||||
case BerryType.LANSAT:
|
||||
|
@ -121,7 +123,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK);
|
||||
const stages = new Utils.NumberHolder(2);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randStat ], stages.value));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ randStat ], stages.value));
|
||||
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
|
||||
};
|
||||
case BerryType.LEPPA:
|
||||
|
@ -132,7 +134,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||
const ppRestoreMove = pokemon.getMoveset().find(m => !m?.getPpRatio()) ? pokemon.getMoveset().find(m => !m?.getPpRatio()) : pokemon.getMoveset().find(m => m!.getPpRatio() < 1); // TODO: is this bang correct?
|
||||
if (ppRestoreMove !== undefined) {
|
||||
ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0);
|
||||
pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) }));
|
||||
globalScene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) }));
|
||||
applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
import * as Utils from "#app/utils";
|
||||
import i18next from "i18next";
|
||||
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data";
|
||||
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import type { DexAttrProps, GameData } from "#app/system/game-data";
|
||||
import { defaultStarterSpecies } from "#app/system/game-data";
|
||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||
import Pokemon, { PokemonMove } from "#app/field/pokemon";
|
||||
import { BattleType, FixedBattleConfig } from "#app/battle";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import type { FixedBattleConfig } from "#app/battle";
|
||||
import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle";
|
||||
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||
import { GameMode } from "#app/game-mode";
|
||||
import type { GameMode } from "#app/game-mode";
|
||||
import { Type } from "#enums/type";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { Moves } from "#enums/moves";
|
||||
import type { Moves } from "#enums/moves";
|
||||
import { TypeColor, TypeShadow } from "#enums/color";
|
||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
|
||||
/** A constant for the default max cost of the starting party before a run */
|
||||
const DEFAULT_PARTY_MAX_COST = 10;
|
||||
|
@ -84,6 +89,11 @@ export enum ChallengeType {
|
|||
* Modifies what weight AI pokemon have when generating movesets. UNIMPLEMENTED.
|
||||
*/
|
||||
MOVE_WEIGHT,
|
||||
/**
|
||||
* Modifies what the pokemon stats for Flip Stat Mode.
|
||||
*/
|
||||
FLIP_STAT,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -401,6 +411,16 @@ export abstract class Challenge {
|
|||
applyMoveWeight(pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, level: Utils.IntegerHolder): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for FlipStats. Derived classes should alter this.
|
||||
* @param pokemon {@link Pokemon} What pokemon would learn the move.
|
||||
* @param baseStats What are the stats to flip.
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyFlipStat(pokemon: Pokemon, baseStats: number[]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
type ChallengeCondition = (data: GameData) => boolean;
|
||||
|
@ -445,30 +465,64 @@ export class SingleGenerationChallenge extends Challenge {
|
|||
return false;
|
||||
}
|
||||
|
||||
applyFixedBattle(waveIndex: Number, battleConfig: FixedBattleConfig): boolean {
|
||||
let trainerTypes: TrainerType[] = [];
|
||||
applyFixedBattle(waveIndex: number, battleConfig: FixedBattleConfig): boolean {
|
||||
let trainerTypes: (TrainerType | TrainerType[])[] = [];
|
||||
const evilTeamWaves: number[] = [ ClassicFixedBossWaves.EVIL_GRUNT_1, ClassicFixedBossWaves.EVIL_GRUNT_2, ClassicFixedBossWaves.EVIL_GRUNT_3, ClassicFixedBossWaves.EVIL_ADMIN_1, ClassicFixedBossWaves.EVIL_GRUNT_4, ClassicFixedBossWaves.EVIL_ADMIN_2, ClassicFixedBossWaves.EVIL_BOSS_1, ClassicFixedBossWaves.EVIL_BOSS_2 ];
|
||||
const evilTeamGrunts = [[ TrainerType.ROCKET_GRUNT ], [ TrainerType.ROCKET_GRUNT ], [ TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT ], [ TrainerType.GALACTIC_GRUNT ], [ TrainerType.PLASMA_GRUNT ], [ TrainerType.FLARE_GRUNT ], [ TrainerType.AETHER_GRUNT, TrainerType.SKULL_GRUNT ], [ TrainerType.MACRO_GRUNT ], [ TrainerType.STAR_GRUNT ]];
|
||||
const evilTeamAdmins = [[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [[ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ]], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], [ TrainerType.FABA, TrainerType.PLUMERIA ], [ TrainerType.OLEANA ], [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]];
|
||||
const evilTeamBosses = [[ TrainerType.ROCKET_BOSS_GIOVANNI_1 ], [ TrainerType.ROCKET_BOSS_GIOVANNI_1 ], [ TrainerType.MAXIE, TrainerType.ARCHIE ], [ TrainerType.CYRUS ], [ TrainerType.GHETSIS ], [ TrainerType.LYSANDRE ], [ TrainerType.LUSAMINE, TrainerType.GUZMA ], [ TrainerType.ROSE ], [ TrainerType.PENNY ]];
|
||||
const evilTeamBossRematches = [[ TrainerType.ROCKET_BOSS_GIOVANNI_2 ], [ TrainerType.ROCKET_BOSS_GIOVANNI_2 ], [ TrainerType.MAXIE_2, TrainerType.ARCHIE_2 ], [ TrainerType.CYRUS_2 ], [ TrainerType.GHETSIS_2 ], [ TrainerType.LYSANDRE_2 ], [ TrainerType.LUSAMINE_2, TrainerType.GUZMA_2 ], [ TrainerType.ROSE_2 ], [ TrainerType.PENNY_2 ]];
|
||||
switch (waveIndex) {
|
||||
case 182:
|
||||
case ClassicFixedBossWaves.EVIL_GRUNT_1:
|
||||
trainerTypes = evilTeamGrunts[this.value - 1];
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true));
|
||||
return true;
|
||||
case ClassicFixedBossWaves.EVIL_GRUNT_2:
|
||||
case ClassicFixedBossWaves.EVIL_GRUNT_3:
|
||||
case ClassicFixedBossWaves.EVIL_GRUNT_4:
|
||||
trainerTypes = evilTeamGrunts[this.value - 1];
|
||||
break;
|
||||
case ClassicFixedBossWaves.EVIL_ADMIN_1:
|
||||
case ClassicFixedBossWaves.EVIL_ADMIN_2:
|
||||
trainerTypes = evilTeamAdmins[this.value - 1];
|
||||
break;
|
||||
case ClassicFixedBossWaves.EVIL_BOSS_1:
|
||||
trainerTypes = evilTeamBosses[this.value - 1];
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false });
|
||||
return true;
|
||||
case ClassicFixedBossWaves.EVIL_BOSS_2:
|
||||
trainerTypes = evilTeamBossRematches[this.value - 1];
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
||||
.setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false });
|
||||
return true;
|
||||
case ClassicFixedBossWaves.ELITE_FOUR_1:
|
||||
trainerTypes = [ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, Utils.randSeedItem([ TrainerType.HALA, TrainerType.MOLAYNE ]), TrainerType.MARNIE_ELITE, TrainerType.RIKA ];
|
||||
break;
|
||||
case 184:
|
||||
case ClassicFixedBossWaves.ELITE_FOUR_2:
|
||||
trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ];
|
||||
break;
|
||||
case 186:
|
||||
case ClassicFixedBossWaves.ELITE_FOUR_3:
|
||||
trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ]), TrainerType.LARRY_ELITE ];
|
||||
break;
|
||||
case 188:
|
||||
case ClassicFixedBossWaves.ELITE_FOUR_4:
|
||||
trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ];
|
||||
break;
|
||||
case 190:
|
||||
case ClassicFixedBossWaves.CHAMPION:
|
||||
trainerTypes = [ TrainerType.BLUE, Utils.randSeedItem([ TrainerType.RED, TrainerType.LANCE_CHAMPION ]), Utils.randSeedItem([ TrainerType.STEVEN, TrainerType.WALLACE ]), TrainerType.CYNTHIA, Utils.randSeedItem([ TrainerType.ALDER, TrainerType.IRIS ]), TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, Utils.randSeedItem([ TrainerType.GEETA, TrainerType.NEMONA ]) ];
|
||||
break;
|
||||
}
|
||||
if (trainerTypes.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(scene => new Trainer(scene, trainerTypes[this.value - 1], TrainerVariant.DEFAULT));
|
||||
} else if (evilTeamWaves.includes(waveIndex)) {
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1).setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true));
|
||||
return true;
|
||||
} else if (waveIndex >= ClassicFixedBossWaves.ELITE_FOUR_1 && waveIndex <= ClassicFixedBossWaves.CHAMPION) {
|
||||
const ttypes = trainerTypes as TrainerType[];
|
||||
battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(() => new Trainer(ttypes[this.value - 1], TrainerVariant.DEFAULT));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,6 +755,33 @@ export class InverseBattleChallenge extends Challenge {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a flip stat challenge.
|
||||
*/
|
||||
export class FlipStatChallenge extends Challenge {
|
||||
constructor() {
|
||||
super(Challenges.FLIP_STAT, 1);
|
||||
}
|
||||
|
||||
override applyFlipStat(pokemon: Pokemon, baseStats: number[]) {
|
||||
const origStats = Utils.deepCopy(baseStats);
|
||||
baseStats[0] = origStats[5];
|
||||
baseStats[1] = origStats[4];
|
||||
baseStats[2] = origStats[3];
|
||||
baseStats[3] = origStats[2];
|
||||
baseStats[4] = origStats[1];
|
||||
baseStats[5] = origStats[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
static loadChallenge(source: FlipStatChallenge | any): FlipStatChallenge {
|
||||
const newChallenge = new FlipStatChallenge();
|
||||
newChallenge.value = source.value;
|
||||
newChallenge.severity = source.severity;
|
||||
return newChallenge;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowers the amount of starter points available.
|
||||
*/
|
||||
|
@ -886,6 +967,9 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.MOVE_WEIGHT, pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, weight: Utils.IntegerHolder): boolean;
|
||||
|
||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
|
||||
|
||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType, ...args: any[]): boolean {
|
||||
let ret = false;
|
||||
gameMode.challenges.forEach(c => {
|
||||
|
@ -930,6 +1014,9 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||
case ChallengeType.MOVE_WEIGHT:
|
||||
ret ||= c.applyMoveWeight(args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
case ChallengeType.FLIP_STAT:
|
||||
ret ||= c.applyFlipStat(args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -955,6 +1042,8 @@ export function copyChallenge(source: Challenge | any): Challenge {
|
|||
return FreshStartChallenge.loadChallenge(source);
|
||||
case Challenges.INVERSE_BATTLE:
|
||||
return InverseBattleChallenge.loadChallenge(source);
|
||||
case Challenges.FLIP_STAT:
|
||||
return FlipStatChallenge.loadChallenge(source);
|
||||
}
|
||||
throw new Error("Unknown challenge copied");
|
||||
}
|
||||
|
@ -967,5 +1056,6 @@ export function initChallenges() {
|
|||
new SingleTypeChallenge(),
|
||||
new FreshStartChallenge(),
|
||||
new InverseBattleChallenge(),
|
||||
new FlipStatChallenge()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Abilities } from "#enums/abilities";
|
||||
import { Type } from "#enums/type";
|
||||
import type { Abilities } from "#enums/abilities";
|
||||
import type { Type } from "#enums/type";
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { Nature } from "#enums/nature";
|
||||
import type { Nature } from "#enums/nature";
|
||||
|
||||
/**
|
||||
* Data that can customize a Pokemon in non-standard ways from its Species
|
||||
* Currently only used by Mystery Encounters and Mints.
|
||||
* Used by Mystery Encounters and Mints
|
||||
* Also used as a counter how often a Pokemon got hit until new arena encounter
|
||||
*/
|
||||
export class CustomPokemonData {
|
||||
public spriteScale: number;
|
||||
|
@ -13,6 +14,8 @@ export class CustomPokemonData {
|
|||
public passive: Abilities | -1;
|
||||
public nature: Nature | -1;
|
||||
public types: Type[];
|
||||
/** `hitsReceivedCount` aka `hitsRecCount` saves how often the pokemon got hit until a new arena encounter (used for Rage Fist) */
|
||||
public hitsRecCount: number;
|
||||
|
||||
constructor(data?: CustomPokemonData | Partial<CustomPokemonData>) {
|
||||
if (!isNullOrUndefined(data)) {
|
||||
|
@ -24,5 +27,10 @@ export class CustomPokemonData {
|
|||
this.passive = this.passive ?? -1;
|
||||
this.nature = this.nature ?? -1;
|
||||
this.types = this.types ?? [];
|
||||
this.hitsRecCount = this.hitsRecCount ?? 0;
|
||||
}
|
||||
|
||||
resetHitReceivedCount(): void {
|
||||
this.hitsRecCount = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import type { Species } from "#enums/species";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { Starter } from "#app/ui/starter-select-ui-handler";
|
||||
import type { Starter } from "#app/ui/starter-select-ui-handler";
|
||||
import * as Utils from "#app/utils";
|
||||
import PokemonSpecies, { PokemonSpeciesForm, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||
import { Biome } from "#app/enums/biome";
|
||||
|
||||
export interface DailyRunConfig {
|
||||
seed: integer;
|
||||
|
@ -21,17 +23,17 @@ export function fetchDailyRunSeed(): Promise<string | null> {
|
|||
});
|
||||
}
|
||||
|
||||
export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[] {
|
||||
export function getDailyRunStarters(seed: string): Starter[] {
|
||||
const starters: Starter[] = [];
|
||||
|
||||
scene.executeWithSeedOffset(() => {
|
||||
const startingLevel = scene.gameMode.getStartingLevel();
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
const startingLevel = globalScene.gameMode.getStartingLevel();
|
||||
|
||||
if (/\d{18}$/.test(seed)) {
|
||||
for (let s = 0; s < 3; s++) {
|
||||
const offset = 6 + s * 6;
|
||||
const starterSpeciesForm = getPokemonSpeciesForm(parseInt(seed.slice(offset, offset + 4)) as Species, parseInt(seed.slice(offset + 4, offset + 6)));
|
||||
starters.push(getDailyRunStarter(scene, starterSpeciesForm, startingLevel));
|
||||
starters.push(getDailyRunStarter(starterSpeciesForm, startingLevel));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -48,17 +50,17 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[]
|
|||
.filter(s => speciesStarterCosts[s] === cost);
|
||||
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies));
|
||||
const starterSpecies = getPokemonSpecies(randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER));
|
||||
starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel));
|
||||
starters.push(getDailyRunStarter(starterSpecies, startingLevel));
|
||||
}
|
||||
}, 0, seed);
|
||||
|
||||
return starters;
|
||||
}
|
||||
|
||||
function getDailyRunStarter(scene: BattleScene, starterSpeciesForm: PokemonSpeciesForm, startingLevel: integer): Starter {
|
||||
function getDailyRunStarter(starterSpeciesForm: PokemonSpeciesForm, startingLevel: integer): Starter {
|
||||
const starterSpecies = starterSpeciesForm instanceof PokemonSpecies ? starterSpeciesForm : getPokemonSpecies(starterSpeciesForm.speciesId);
|
||||
const formIndex = starterSpeciesForm instanceof PokemonSpecies ? undefined : starterSpeciesForm.formIndex;
|
||||
const pokemon = new PlayerPokemon(scene, starterSpecies, startingLevel, undefined, formIndex, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||
const pokemon = new PlayerPokemon(starterSpecies, startingLevel, undefined, formIndex, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||
const starter: Starter = {
|
||||
species: starterSpecies,
|
||||
dexAttr: pokemon.getDexAttr(),
|
||||
|
@ -70,3 +72,76 @@ function getDailyRunStarter(scene: BattleScene, starterSpeciesForm: PokemonSpeci
|
|||
pokemon.destroy();
|
||||
return starter;
|
||||
}
|
||||
|
||||
interface BiomeWeights {
|
||||
[key: integer]: integer
|
||||
}
|
||||
|
||||
// Initially weighted by amount of exits each biome has
|
||||
// Town and End are set to 0 however
|
||||
// And some other biomes were balanced +1/-1 based on average size of the total daily.
|
||||
const dailyBiomeWeights: BiomeWeights = {
|
||||
[Biome.CAVE]: 3,
|
||||
[Biome.LAKE]: 3,
|
||||
[Biome.PLAINS]: 3,
|
||||
[Biome.SNOWY_FOREST]: 3,
|
||||
[Biome.SWAMP]: 3, // 2 -> 3
|
||||
[Biome.TALL_GRASS]: 3, // 2 -> 3
|
||||
|
||||
[Biome.ABYSS]: 2, // 3 -> 2
|
||||
[Biome.RUINS]: 2,
|
||||
[Biome.BADLANDS]: 2,
|
||||
[Biome.BEACH]: 2,
|
||||
[Biome.CONSTRUCTION_SITE]: 2,
|
||||
[Biome.DESERT]: 2,
|
||||
[Biome.DOJO]: 2, // 3 -> 2
|
||||
[Biome.FACTORY]: 2,
|
||||
[Biome.FAIRY_CAVE]: 2,
|
||||
[Biome.FOREST]: 2,
|
||||
[Biome.GRASS]: 2, // 1 -> 2
|
||||
[Biome.MEADOW]: 2,
|
||||
[Biome.MOUNTAIN]: 2, // 3 -> 2
|
||||
[Biome.SEA]: 2,
|
||||
[Biome.SEABED]: 2,
|
||||
[Biome.SLUM]: 2,
|
||||
[Biome.TEMPLE]: 2, // 3 -> 2
|
||||
[Biome.VOLCANO]: 2,
|
||||
|
||||
[Biome.GRAVEYARD]: 1,
|
||||
[Biome.ICE_CAVE]: 1,
|
||||
[Biome.ISLAND]: 1,
|
||||
[Biome.JUNGLE]: 1,
|
||||
[Biome.LABORATORY]: 1,
|
||||
[Biome.METROPOLIS]: 1,
|
||||
[Biome.POWER_PLANT]: 1,
|
||||
[Biome.SPACE]: 1,
|
||||
[Biome.WASTELAND]: 1,
|
||||
|
||||
[Biome.TOWN]: 0,
|
||||
[Biome.END]: 0,
|
||||
};
|
||||
|
||||
export function getDailyStartingBiome(): Biome {
|
||||
const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END);
|
||||
|
||||
let totalWeight = 0;
|
||||
const biomeThresholds: integer[] = [];
|
||||
for (const biome of biomes) {
|
||||
// Keep track of the total weight
|
||||
totalWeight += dailyBiomeWeights[biome];
|
||||
|
||||
// Keep track of each biomes cumulative weight
|
||||
biomeThresholds.push(totalWeight);
|
||||
}
|
||||
|
||||
const randInt = Utils.randSeedInt(totalWeight);
|
||||
|
||||
for (let i = 0; i < biomes.length; i++) {
|
||||
if (randInt < biomeThresholds[i]) {
|
||||
return biomes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback in case something went wrong
|
||||
return biomes[Utils.randSeedInt(biomes.length)];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import BattleScene from "#app/battle-scene";
|
||||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { DexEntry, StarterDataEntry } from "#app/system/game-data";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { DexEntry, StarterDataEntry } from "#app/system/game-data";
|
||||
|
||||
/**
|
||||
* Stores data associated with a specific egg and the hatched pokemon
|
||||
|
@ -17,11 +17,8 @@ export class EggHatchData {
|
|||
public dexEntryBeforeUpdate: DexEntry;
|
||||
/** stored copy of the hatched pokemon's starter entry before it was updated due to hatch */
|
||||
public starterDataEntryBeforeUpdate: StarterDataEntry;
|
||||
/** reference to the battle scene to get gamedata and update dex */
|
||||
private scene: BattleScene;
|
||||
|
||||
constructor(scene: BattleScene, pokemon: PlayerPokemon, eggMoveIndex: number) {
|
||||
this.scene = scene;
|
||||
constructor(pokemon: PlayerPokemon, eggMoveIndex: number) {
|
||||
this.pokemon = pokemon;
|
||||
this.eggMoveIndex = eggMoveIndex;
|
||||
}
|
||||
|
@ -39,8 +36,8 @@ export class EggHatchData {
|
|||
* Used before updating the dex, so comparing the pokemon to these entries will show the new attributes
|
||||
*/
|
||||
setDex() {
|
||||
const currDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId];
|
||||
const currStarterDataEntry = this.scene.gameData.starterData[this.pokemon.species.getRootSpeciesId()];
|
||||
const currDexEntry = globalScene.gameData.dexData[this.pokemon.species.speciesId];
|
||||
const currStarterDataEntry = globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId()];
|
||||
this.dexEntryBeforeUpdate = {
|
||||
seenAttr: currDexEntry.seenAttr,
|
||||
caughtAttr: currDexEntry.caughtAttr,
|
||||
|
@ -86,9 +83,9 @@ export class EggHatchData {
|
|||
*/
|
||||
updatePokemon(showMessage : boolean = false) {
|
||||
return new Promise<void>(resolve => {
|
||||
this.scene.gameData.setPokemonCaught(this.pokemon, true, true, showMessage).then(() => {
|
||||
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
||||
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex, showMessage).then((value) => {
|
||||
globalScene.gameData.setPokemonCaught(this.pokemon, true, true, showMessage).then(() => {
|
||||
globalScene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
||||
globalScene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex, showMessage).then((value) => {
|
||||
this.setEggMoveUnlocked(value);
|
||||
resolve();
|
||||
});
|
||||
|
|
106
src/data/egg.ts
|
@ -1,11 +1,13 @@
|
|||
import BattleScene from "#app/battle-scene";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import type BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||
import { VariantTier } from "#enums/variant-tier";
|
||||
import * as Utils from "#app/utils";
|
||||
import Overrides from "#app/overrides";
|
||||
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import i18next from "i18next";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { Species } from "#enums/species";
|
||||
|
@ -22,9 +24,8 @@ export interface IEggOptions {
|
|||
/** 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.
|
||||
* Defines if the egg got pulled from a gacha or not. If true, egg pity and pull statistics will be applied.
|
||||
* Egg will be automaticly added to the game data.
|
||||
* NEEDS `scene` `eggOption` to work.
|
||||
*/
|
||||
pulled?: boolean;
|
||||
/**
|
||||
|
@ -32,7 +33,7 @@ export interface IEggOptions {
|
|||
* 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 defined since this will be needed to generate them. */
|
||||
/** Legacy field, kept for backwards-compatibility */
|
||||
scene?: BattleScene;
|
||||
/**
|
||||
* Sets the tier of the egg. Only species of this tier can be hatched from this egg.
|
||||
|
@ -41,10 +42,7 @@ export interface IEggOptions {
|
|||
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.
|
||||
*/
|
||||
/** Sets the exact species that will hatch from this egg. */
|
||||
species?: Species;
|
||||
/** Defines if the hatched pokemon will be a shiny. */
|
||||
isShiny?: boolean;
|
||||
|
@ -56,8 +54,7 @@ export interface IEggOptions {
|
|||
* 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,
|
||||
|
||||
overrideHiddenAbility?: boolean;
|
||||
/** Can customize the message displayed for where the egg was obtained */
|
||||
eggDescriptor?: string;
|
||||
}
|
||||
|
@ -148,7 +145,7 @@ export class Egg {
|
|||
// 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!); // TODO: is this bang correct?
|
||||
this.checkForPityTierOverrides();
|
||||
}
|
||||
|
||||
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
||||
|
@ -160,7 +157,7 @@ export class Egg {
|
|||
// 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!)!; // TODO: Are those bangs correct?
|
||||
this._species = eggOptions?.species ?? this.rollSpecies()!; // TODO: Is this bang correct?
|
||||
|
||||
this._overrideHiddenAbility = eggOptions?.overrideHiddenAbility ?? false;
|
||||
|
||||
|
@ -178,19 +175,15 @@ export class Egg {
|
|||
// 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!); // TODO: is this bang correct?
|
||||
this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct?
|
||||
this.increasePullStatistic();
|
||||
this.addEggToGameData();
|
||||
}
|
||||
};
|
||||
|
||||
if (eggOptions?.scene) {
|
||||
const seedOverride = Utils.randomString(24);
|
||||
eggOptions?.scene.executeWithSeedOffset(() => {
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
generateEggProperties(eggOptions);
|
||||
}, 0, seedOverride);
|
||||
} else { // For legacy eggs without scene
|
||||
generateEggProperties(eggOptions);
|
||||
}
|
||||
|
||||
this._eggDescriptor = eggOptions?.eggDescriptor;
|
||||
}
|
||||
|
@ -212,14 +205,14 @@ export class Egg {
|
|||
}
|
||||
|
||||
// Generates a PlayerPokemon from an egg
|
||||
public generatePlayerPokemon(scene: BattleScene): PlayerPokemon {
|
||||
public generatePlayerPokemon(): PlayerPokemon {
|
||||
let ret: PlayerPokemon;
|
||||
|
||||
const generatePlayerPokemonHelper = (scene: BattleScene) => {
|
||||
const generatePlayerPokemonHelper = () => {
|
||||
// Legacy egg wants to hatch. Generate missing properties
|
||||
if (!this._species) {
|
||||
this._isShiny = this.rollShiny();
|
||||
this._species = this.rollSpecies(scene!)!; // TODO: are these bangs correct?
|
||||
this._species = this.rollSpecies()!; // TODO: is this bang correct?
|
||||
}
|
||||
|
||||
let pokemonSpecies = getPokemonSpecies(this._species);
|
||||
|
@ -238,7 +231,7 @@ export class Egg {
|
|||
}
|
||||
|
||||
// This function has way to many optional parameters
|
||||
ret = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
|
||||
ret = globalScene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
|
||||
ret.shiny = this._isShiny;
|
||||
ret.variant = this._variantTier;
|
||||
|
||||
|
@ -250,16 +243,16 @@ export class Egg {
|
|||
};
|
||||
|
||||
ret = ret!; // Tell TS compiler it's defined now
|
||||
scene.executeWithSeedOffset(() => {
|
||||
generatePlayerPokemonHelper(scene);
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
generatePlayerPokemonHelper();
|
||||
}, this._id, EGG_SEED.toString());
|
||||
|
||||
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 addEggToGameData(): void {
|
||||
globalScene.gameData.eggs.push(this);
|
||||
}
|
||||
|
||||
public getEggDescriptor(): string {
|
||||
|
@ -291,12 +284,12 @@ export class Egg {
|
|||
return i18next.t("egg:hatchWavesMessageLongTime");
|
||||
}
|
||||
|
||||
public getEggTypeDescriptor(scene: BattleScene): string {
|
||||
public getEggTypeDescriptor(): string {
|
||||
switch (this.sourceType) {
|
||||
case EggSourceType.SAME_SPECIES_EGG:
|
||||
return this._eggDescriptor ?? i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName() });
|
||||
case EggSourceType.GACHA_LEGENDARY:
|
||||
return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`;
|
||||
return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.timestamp)).getName()})`;
|
||||
case EggSourceType.GACHA_SHINY:
|
||||
return this._eggDescriptor ?? i18next.t("egg:gachaTypeShiny");
|
||||
case EggSourceType.GACHA_MOVE:
|
||||
|
@ -356,8 +349,8 @@ export class Egg {
|
|||
return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset ? EggTier.COMMON : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset ? EggTier.RARE : tierValue >= GACHA_DEFAULT_EPIC_EGG_THRESHOLD + tierValueOffset ? EggTier.EPIC : EggTier.LEGENDARY;
|
||||
}
|
||||
|
||||
private rollSpecies(scene: BattleScene): Species | null {
|
||||
if (!scene) {
|
||||
private rollSpecies(): Species | null {
|
||||
if (!globalScene) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
|
@ -376,7 +369,7 @@ export class Egg {
|
|||
} else if (this.tier === EggTier.LEGENDARY
|
||||
&& this._sourceType === EggSourceType.GACHA_LEGENDARY) {
|
||||
if (!Utils.randSeedInt(2)) {
|
||||
return getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp);
|
||||
return getLegendaryGachaSpeciesForTimestamp(this.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,8 +403,8 @@ export class Egg {
|
|||
.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 (globalScene.gameData.unlockPity[this.tier] >= 9) {
|
||||
const lockedPool = speciesPool.filter(s => !globalScene.gameData.dexData[s].caughtAttr && !globalScene.gameData.eggs.some(e => e.species === s));
|
||||
if (lockedPool.length) { // Skip this if everything is unlocked
|
||||
speciesPool = lockedPool;
|
||||
}
|
||||
|
@ -454,10 +447,10 @@ export class Egg {
|
|||
}
|
||||
species = species!; // tell TS compiled it's defined now!
|
||||
|
||||
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);
|
||||
if (globalScene.gameData.dexData[species].caughtAttr || globalScene.gameData.eggs.some(e => e.species === species)) {
|
||||
globalScene.gameData.unlockPity[this.tier] = Math.min(globalScene.gameData.unlockPity[this.tier] + 1, 10);
|
||||
} else {
|
||||
scene.gameData.unlockPity[this.tier] = 0;
|
||||
globalScene.gameData.unlockPity[this.tier] = 0;
|
||||
}
|
||||
|
||||
return species;
|
||||
|
@ -465,7 +458,7 @@ export class Egg {
|
|||
|
||||
/**
|
||||
* Rolls whether the egg is shiny or not.
|
||||
* @returns True if the egg is shiny
|
||||
* @returns `true` if the egg is shiny
|
||||
**/
|
||||
private rollShiny(): boolean {
|
||||
let shinyChance = GACHA_DEFAULT_SHINY_RATE;
|
||||
|
@ -485,6 +478,7 @@ export class Egg {
|
|||
|
||||
// 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.
|
||||
// TODO: Remove this or replace the one in the Pokemon class.
|
||||
private rollVariant(): VariantTier {
|
||||
if (!this.isShiny) {
|
||||
return VariantTier.STANDARD;
|
||||
|
@ -500,38 +494,38 @@ export class Egg {
|
|||
}
|
||||
}
|
||||
|
||||
private checkForPityTierOverrides(scene: BattleScene): void {
|
||||
private checkForPityTierOverrides(): void {
|
||||
const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0;
|
||||
scene.gameData.eggPity[EggTier.RARE] += 1;
|
||||
scene.gameData.eggPity[EggTier.EPIC] += 1;
|
||||
scene.gameData.eggPity[EggTier.LEGENDARY] += 1 + tierValueOffset;
|
||||
globalScene.gameData.eggPity[EggTier.RARE] += 1;
|
||||
globalScene.gameData.eggPity[EggTier.EPIC] += 1;
|
||||
globalScene.gameData.eggPity[EggTier.LEGENDARY] += 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.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
if (globalScene.gameData.eggPity[EggTier.LEGENDARY] >= EGG_PITY_LEGENDARY_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
this._tier = EggTier.LEGENDARY;
|
||||
} else if (scene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
} else if (globalScene.gameData.eggPity[EggTier.EPIC] >= EGG_PITY_EPIC_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
this._tier = EggTier.EPIC;
|
||||
} else if (scene.gameData.eggPity[EggTier.RARE] >= EGG_PITY_RARE_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
} else if (globalScene.gameData.eggPity[EggTier.RARE] >= EGG_PITY_RARE_THRESHOLD && this._tier === EggTier.COMMON) {
|
||||
this._tier = EggTier.RARE;
|
||||
}
|
||||
scene.gameData.eggPity[this._tier] = 0;
|
||||
globalScene.gameData.eggPity[this._tier] = 0;
|
||||
}
|
||||
|
||||
private increasePullStatistic(scene: BattleScene): void {
|
||||
scene.gameData.gameStats.eggsPulled++;
|
||||
private increasePullStatistic(): void {
|
||||
globalScene.gameData.gameStats.eggsPulled++;
|
||||
if (this.isManaphyEgg()) {
|
||||
scene.gameData.gameStats.manaphyEggsPulled++;
|
||||
globalScene.gameData.gameStats.manaphyEggsPulled++;
|
||||
this._hatchWaves = this.getEggTierDefaultHatchWaves(EggTier.EPIC);
|
||||
return;
|
||||
}
|
||||
switch (this.tier) {
|
||||
case EggTier.RARE:
|
||||
scene.gameData.gameStats.rareEggsPulled++;
|
||||
globalScene.gameData.gameStats.rareEggsPulled++;
|
||||
break;
|
||||
case EggTier.EPIC:
|
||||
scene.gameData.gameStats.epicEggsPulled++;
|
||||
globalScene.gameData.gameStats.epicEggsPulled++;
|
||||
break;
|
||||
case EggTier.LEGENDARY:
|
||||
scene.gameData.gameStats.legendaryEggsPulled++;
|
||||
globalScene.gameData.gameStats.legendaryEggsPulled++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -552,7 +546,7 @@ export function getValidLegendaryGachaSpecies() : Species[] {
|
|||
.filter(s => getPokemonSpecies(s).isObtainable() && s !== Species.ETERNATUS);
|
||||
}
|
||||
|
||||
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
|
||||
export function getLegendaryGachaSpeciesForTimestamp(timestamp: number): Species {
|
||||
const legendarySpecies = getValidLegendaryGachaSpecies();
|
||||
|
||||
let ret: Species;
|
||||
|
@ -563,7 +557,7 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta
|
|||
const offset = Math.floor(Math.floor(dayTimestamp / 86400000) / legendarySpecies.length); // Cycle number
|
||||
const index = Math.floor(dayTimestamp / 86400000) % legendarySpecies.length; // Index within cycle
|
||||
|
||||
scene.executeWithSeedOffset(() => {
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
ret = Phaser.Math.RND.shuffle(legendarySpecies)[index];
|
||||
}, offset, EGG_SEED.toString());
|
||||
ret = ret!; // tell TS compiler it's
|
||||
|
|
1503
src/data/move.ts
|
@ -1,15 +1,17 @@
|
|||
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { trainerConfigs, } from "#app/data/trainer-config";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Species } from "#enums/species";
|
||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { randSeedInt } from "#app/utils";
|
||||
import i18next from "i18next";
|
||||
import { IEggOptions } from "#app/data/egg";
|
||||
import type { IEggOptions } from "#app/data/egg";
|
||||
import { EggSourceType } from "#enums/egg-source-types";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
||||
|
@ -36,8 +38,8 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Randomly pick from 1 of the 5 stat trainers to spawn
|
||||
let trainerType: TrainerType;
|
||||
|
@ -138,23 +140,22 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.1.label`,
|
||||
buttonTooltip: `${namespace}:option.1.tooltip`
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Battle the stat trainer for an Egg and great rewards
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene);
|
||||
await transitionMysteryEncounterIntroVisuals();
|
||||
|
||||
const eggOptions: IEggOptions = {
|
||||
scene,
|
||||
pulled: false,
|
||||
sourceType: EggSourceType.EVENT,
|
||||
eggDescriptor: encounter.misc.trainerEggDescription,
|
||||
tier: EggTier.EPIC
|
||||
};
|
||||
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`));
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SACRED_ASH ], guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ULTRA ], fillRemaining: true }, [ eggOptions ]);
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.SACRED_ASH ], guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ULTRA ], fillRemaining: true }, [ eggOptions ]);
|
||||
await initBattleWithEnemyConfig(config);
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -162,21 +163,20 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.2.label`,
|
||||
buttonTooltip: `${namespace}:option.2.tooltip`
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Full heal party
|
||||
scene.unshiftPhase(new PartyHealPhase(scene, true));
|
||||
globalScene.unshiftPhase(new PartyHealPhase(true));
|
||||
|
||||
const eggOptions: IEggOptions = {
|
||||
scene,
|
||||
pulled: false,
|
||||
sourceType: EggSourceType.EVENT,
|
||||
eggDescriptor: encounter.misc.trainerEggDescription,
|
||||
tier: EggTier.RARE
|
||||
};
|
||||
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.rare`));
|
||||
setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [ eggOptions ]);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ fillRemaining: false, rerollMultiplier: -1 }, [ eggOptions ]);
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
)
|
||||
.withOutroDialogue([
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import Pokemon, { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { BerryModifierType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { BerryModifierType, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { PersistentModifierRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
|
@ -19,8 +23,8 @@ import { BattlerIndex } from "#app/battle";
|
|||
import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
import type { BerryType } from "#enums/berry-type";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
|
@ -170,18 +174,18 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
scene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
||||
scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
||||
globalScene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
||||
globalScene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
||||
|
||||
// Get all player berry items, remove from party, and store reference
|
||||
const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||
|
||||
// Sort berries by party member ID to more easily re-add later if necessary
|
||||
const berryItemsMap = new Map<number, BerryModifier[]>();
|
||||
scene.getPlayerParty().forEach(pokemon => {
|
||||
globalScene.getPlayerParty().forEach(pokemon => {
|
||||
const pokemonBerries = berryItems.filter(b => b.pokemonId === pokemon.id);
|
||||
if (pokemonBerries?.length > 0) {
|
||||
berryItemsMap.set(pokemon.id, pokemonBerries);
|
||||
|
@ -196,7 +200,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
// Can't define stack count on a ModifierType, have to just create separate instances for each stack
|
||||
// Overflow berries will be "lost" on the boss, but it's un-catchable anyway
|
||||
for (let i = 0; i < berryMod.stackCount; i++) {
|
||||
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [ berryMod.berryType ]) as PokemonHeldItemModifierType;
|
||||
const modifierType = generateModifierType(modifierTypes.BERRY, [ berryMod.berryType ]) as PokemonHeldItemModifierType;
|
||||
bossModifierConfigs.push({ modifier: modifierType });
|
||||
}
|
||||
});
|
||||
|
@ -204,7 +208,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
// Do NOT remove the real berries yet or else it will be persisted in the session data
|
||||
|
||||
// SpDef buff below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = globalScene.currentBattle.waveIndex < 50 ?
|
||||
[ Stat.SPDEF ] :
|
||||
[ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
|
||||
|
||||
|
@ -221,8 +225,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
modifierConfigs: bossModifierConfigs,
|
||||
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -233,18 +237,18 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
doGreedentSpriteSteal(scene);
|
||||
doBerrySpritePile(scene);
|
||||
.withOnVisualsStart(() => {
|
||||
doGreedentSpriteSteal();
|
||||
doBerrySpritePile();
|
||||
|
||||
// Remove the berries from the party
|
||||
// Session has been safely saved at this point, so data won't be lost
|
||||
const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||
berryItems.forEach(berryMod => {
|
||||
scene.removeModifier(berryMod);
|
||||
globalScene.removeModifier(berryMod);
|
||||
});
|
||||
|
||||
scene.updateModifiers(true);
|
||||
globalScene.updateModifiers(true);
|
||||
|
||||
return true;
|
||||
})
|
||||
|
@ -260,26 +264,26 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Provides 1x Reviver Seed to each party member at end of battle
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const revSeed = generateModifierType(modifierTypes.REVIVER_SEED);
|
||||
encounter.setDialogueToken("foodReward", revSeed?.name ?? i18next.t("modifierType:ModifierType.REVIVER_SEED.name"));
|
||||
const givePartyPokemonReviverSeeds = () => {
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
party.forEach(p => {
|
||||
const heldItems = p.getHeldItems();
|
||||
if (revSeed && !heldItems.some(item => item instanceof PokemonInstantReviveModifier)) {
|
||||
const seedModifier = revSeed.newModifier(p);
|
||||
scene.addModifier(seedModifier, false, false, false, true);
|
||||
globalScene.addModifier(seedModifier, false, false, false, true);
|
||||
}
|
||||
});
|
||||
queueEncounterMessage(scene, `${namespace}:option.1.food_stash`);
|
||||
queueEncounterMessage(`${namespace}:option.1.food_stash`);
|
||||
};
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds);
|
||||
setEncounterRewards({ fillRemaining: true }, undefined, givePartyPokemonReviverSeeds);
|
||||
encounter.startOfBattleEffects.push({
|
||||
sourceBattlerIndex: BattlerIndex.ENEMY,
|
||||
targets: [ BattlerIndex.ENEMY ],
|
||||
|
@ -287,8 +291,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
ignorePp: true
|
||||
});
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
|
||||
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 500);
|
||||
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -304,12 +308,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const berryMap = encounter.misc.berryItemsMap;
|
||||
|
||||
// Returns 2/5 of the berries stolen to each Pokemon
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
party.forEach(pokemon => {
|
||||
const stolenBerries: BerryModifier[] = berryMap.get(pokemon.id);
|
||||
const berryTypesAsArray: BerryType[] = [];
|
||||
|
@ -322,15 +326,15 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
Phaser.Math.RND.shuffle(berryTypesAsArray);
|
||||
const randBerryType = berryTypesAsArray.pop();
|
||||
|
||||
const berryModType = generateModifierType(scene, modifierTypes.BERRY, [ randBerryType ]) as BerryModifierType;
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType);
|
||||
const berryModType = generateModifierType(modifierTypes.BERRY, [ randBerryType ]) as BerryModifierType;
|
||||
applyModifierTypeToPlayerPokemon(pokemon, berryModType);
|
||||
}
|
||||
}
|
||||
});
|
||||
await scene.updateModifiers(true);
|
||||
await globalScene.updateModifiers(true);
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 500);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -346,36 +350,36 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Animate berries being eaten
|
||||
doGreedentEatBerries(scene);
|
||||
doBerrySpritePile(scene, true);
|
||||
doGreedentEatBerries();
|
||||
doBerrySpritePile(true);
|
||||
return true;
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Let it have the food
|
||||
// Greedent joins the team, level equal to 2 below highest party member (shiny locked)
|
||||
const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2;
|
||||
const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false, true);
|
||||
const level = getHighestLevelPlayerPokemon(false, true).level - 2;
|
||||
const greedent = new EnemyPokemon(getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false, true);
|
||||
greedent.moveset = [ new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF) ];
|
||||
greedent.passive = true;
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
|
||||
await catchPokemon(scene, greedent, null, PokeballType.POKEBALL, false);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 500);
|
||||
await catchPokemon(greedent, null, PokeballType.POKEBALL, false);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
function doGreedentSpriteSteal(scene: BattleScene) {
|
||||
function doGreedentSpriteSteal() {
|
||||
const shakeDelay = 50;
|
||||
const slideDelay = 500;
|
||||
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
const greedentSprites = globalScene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
|
||||
scene.playSound("battle_anims/Follow Me");
|
||||
scene.tweens.chain({
|
||||
globalScene.playSound("battle_anims/Follow Me");
|
||||
globalScene.tweens.chain({
|
||||
targets: greedentSprites,
|
||||
tweens: [
|
||||
{ // Slide Greedent diagonally
|
||||
|
@ -445,10 +449,10 @@ function doGreedentSpriteSteal(scene: BattleScene) {
|
|||
});
|
||||
}
|
||||
|
||||
function doGreedentEatBerries(scene: BattleScene) {
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
function doGreedentEatBerries() {
|
||||
const greedentSprites = globalScene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
let index = 1;
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: greedentSprites,
|
||||
duration: 150,
|
||||
ease: "Cubic.easeOut",
|
||||
|
@ -456,11 +460,11 @@ function doGreedentEatBerries(scene: BattleScene) {
|
|||
y: "-=8",
|
||||
loop: 5,
|
||||
onStart: () => {
|
||||
scene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||
globalScene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||
},
|
||||
onLoop: () => {
|
||||
if (index % 2 === 0) {
|
||||
scene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||
globalScene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
@ -468,17 +472,15 @@ function doGreedentEatBerries(scene: BattleScene) {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scene
|
||||
* @param isEat Default false. Will "create" pile when false, and remove pile when true.
|
||||
*/
|
||||
function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
|
||||
function doBerrySpritePile(isEat: boolean = false) {
|
||||
const berryAddDelay = 150;
|
||||
let animationOrder = [ "starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa" ];
|
||||
if (isEat) {
|
||||
animationOrder = animationOrder.reverse();
|
||||
}
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
animationOrder.forEach((berry, i) => {
|
||||
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry));
|
||||
let sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite;
|
||||
|
@ -487,7 +489,7 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
|
|||
sprite = sprites[0];
|
||||
tintSprite = sprites[1];
|
||||
}
|
||||
scene.time.delayedCall(berryAddDelay * i + 400, () => {
|
||||
globalScene.time.delayedCall(berryAddDelay * i + 400, () => {
|
||||
if (sprite) {
|
||||
sprite.setVisible(!isEat);
|
||||
}
|
||||
|
@ -497,20 +499,20 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
|
|||
|
||||
// Animate Petaya berry falling off the pile
|
||||
if (berry === "petaya" && sprite && tintSprite && !isEat) {
|
||||
scene.time.delayedCall(200, () => {
|
||||
doBerryBounce(scene, [ sprite, tintSprite ], 30, 500);
|
||||
globalScene.time.delayedCall(200, () => {
|
||||
doBerryBounce([ sprite, tintSprite ], 30, 500);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function doBerryBounce(scene: BattleScene, berrySprites: Phaser.GameObjects.Sprite[], yd: number, baseBounceDuration: number) {
|
||||
function doBerryBounce(berrySprites: Phaser.GameObjects.Sprite[], yd: number, baseBounceDuration: number) {
|
||||
let bouncePower = 1;
|
||||
let bounceYOffset = yd;
|
||||
|
||||
const doBounce = () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: berrySprites,
|
||||
y: "+=" + bounceYOffset,
|
||||
x: { value: "+=" + (bouncePower * bouncePower * 10), ease: "Linear" },
|
||||
|
@ -522,7 +524,7 @@ function doBerryBounce(scene: BattleScene, berrySprites: Phaser.GameObjects.Spri
|
|||
if (bouncePower) {
|
||||
bounceYOffset = bounceYOffset * bouncePower;
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: berrySprites,
|
||||
y: "-=" + bounceYOffset,
|
||||
x: { value: "+=" + (bouncePower * bouncePower * 10), ease: "Linear" },
|
||||
|
|
|
@ -2,8 +2,9 @@ import { generateModifierType, leaveEncounterWithoutBattle, setEncounterExp, upd
|
|||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
|
@ -69,14 +70,14 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true);
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = getHighestStatTotalPlayerPokemon(true, true);
|
||||
|
||||
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId();
|
||||
const starterValue: number = speciesStarterCosts[baseSpecies] ?? 1;
|
||||
const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER);
|
||||
const price = scene.getWaveMoneyAmount(multiplier);
|
||||
const price = globalScene.getWaveMoneyAmount(multiplier);
|
||||
|
||||
encounter.setDialogueToken("strongestPokemon", pokemon.getNameToRender());
|
||||
encounter.setDialogueToken("price", price.toString());
|
||||
|
@ -89,7 +90,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
|
||||
// If player meets the combo OR requirements for option 2, populate the token
|
||||
const opt2Req = encounter.options[1].primaryPokemonRequirements[0];
|
||||
if (opt2Req.meetsRequirement(scene)) {
|
||||
if (opt2Req.meetsRequirement()) {
|
||||
const abilityToken = encounter.dialogueTokens["option2PrimaryAbility"];
|
||||
const moveToken = encounter.dialogueTokens["option2PrimaryMove"];
|
||||
if (abilityToken) {
|
||||
|
@ -99,7 +100,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
}
|
||||
}
|
||||
|
||||
const shinyCharm = generateModifierType(scene, modifierTypes.SHINY_CHARM);
|
||||
const shinyCharm = generateModifierType(modifierTypes.SHINY_CHARM);
|
||||
encounter.setDialogueToken("itemName", shinyCharm?.name ?? i18next.t("modifierType:ModifierType.SHINY_CHARM.name"));
|
||||
encounter.setDialogueToken("liepardName", getPokemonSpecies(Species.LIEPARD).getName());
|
||||
|
||||
|
@ -118,17 +119,17 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Update money and remove pokemon from party
|
||||
updatePlayerMoney(scene, encounter.misc.price);
|
||||
scene.removePokemonFromPlayerParty(encounter.misc.pokemon);
|
||||
updatePlayerMoney(encounter.misc.price);
|
||||
globalScene.removePokemonFromPlayerParty(encounter.misc.pokemon);
|
||||
return true;
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Give the player a Shiny Charm
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.SHINY_CHARM));
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.SHINY_CHARM));
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -152,15 +153,15 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Extort the rich kid for money
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Update money and remove pokemon from party
|
||||
updatePlayerMoney(scene, encounter.misc.price);
|
||||
updatePlayerMoney(encounter.misc.price);
|
||||
|
||||
setEncounterExp(scene, encounter.options[1].primaryPokemon!.id, getPokemonSpecies(Species.LIEPARD).baseExp, true);
|
||||
setEncounterExp(encounter.options[1].primaryPokemon!.id, getPokemonSpecies(Species.LIEPARD).baseExp, true);
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -175,9 +176,9 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,28 +1,35 @@
|
|||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import type {
|
||||
EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import {
|
||||
EnemyPartyConfig, generateModifierType, generateModifierTypeOption,
|
||||
generateModifierType,
|
||||
generateModifierTypeOption,
|
||||
getRandomEncounterSpecies,
|
||||
initBattleWithEnemyConfig,
|
||||
leaveEncounterWithoutBattle, setEncounterExp,
|
||||
leaveEncounterWithoutBattle,
|
||||
setEncounterExp,
|
||||
setEncounterRewards
|
||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||
import {
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import type {
|
||||
BerryModifierType,
|
||||
getPartyLuckValue,
|
||||
ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||
import {
|
||||
ModifierPoolType,
|
||||
ModifierTypeOption, modifierTypes,
|
||||
modifierTypes,
|
||||
regenerateModifierPoolThresholds,
|
||||
} from "#app/modifier/modifier-type";
|
||||
import { randSeedInt, randSeedItem } from "#app/utils";
|
||||
import { randSeedInt } from "#app/utils";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { applyModifierTypeToPlayerPokemon, getEncounterPokemonLevelForWave, getHighestStatPlayerPokemon, getSpriteKeysFromPokemon, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import { BerryModifier } from "#app/modifier/modifier";
|
||||
|
@ -31,7 +38,6 @@ import { BerryType } from "#enums/berry-type";
|
|||
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/berriesAbound";
|
||||
|
@ -54,25 +60,17 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const level = getEncounterPokemonLevelForWave(scene, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
let bossSpecies: PokemonSpecies;
|
||||
if (scene.eventManager.isEventActive() && scene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
|
||||
const eventEncounter = randSeedItem(scene.eventManager.activeEvent()!.uncommonBreedEncounters!);
|
||||
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, scene.gameMode);
|
||||
bossSpecies = getPokemonSpecies( levelSpecies );
|
||||
} else {
|
||||
bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getPlayerParty()), true);
|
||||
}
|
||||
const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true);
|
||||
const level = getEncounterPokemonLevelForWave(STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
const bossPokemon = getRandomEncounterSpecies(level, true);
|
||||
encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon));
|
||||
const config: EnemyPartyConfig = {
|
||||
pokemonConfigs: [{
|
||||
level: level,
|
||||
species: bossSpecies,
|
||||
species: bossPokemon.species,
|
||||
dataSource: new PokemonData(bossPokemon),
|
||||
isBoss: true
|
||||
}],
|
||||
|
@ -82,10 +80,10 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
// Calculate the number of extra berries that player receives
|
||||
// 10-40: 2, 40-120: 4, 120-160: 5, 160-180: 7
|
||||
const numBerries =
|
||||
scene.currentBattle.waveIndex > 160 ? 7
|
||||
: scene.currentBattle.waveIndex > 120 ? 5
|
||||
: scene.currentBattle.waveIndex > 40 ? 4 : 2;
|
||||
regenerateModifierPoolThresholds(scene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
||||
globalScene.currentBattle.waveIndex > 160 ? 7
|
||||
: globalScene.currentBattle.waveIndex > 120 ? 5
|
||||
: globalScene.currentBattle.waveIndex > 40 ? 4 : 2;
|
||||
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
||||
encounter.misc = { numBerries };
|
||||
|
||||
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(bossPokemon);
|
||||
|
@ -113,7 +111,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
];
|
||||
|
||||
// Get fastest party pokemon for option 2
|
||||
const fastestPokemon = getHighestStatPlayerPokemon(scene, PERMANENT_STATS[Stat.SPD], true, false);
|
||||
const fastestPokemon = getHighestStatPlayerPokemon(PERMANENT_STATS[Stat.SPD], true, false);
|
||||
encounter.misc.fastestPokemon = fastestPokemon;
|
||||
encounter.misc.enemySpeed = bossPokemon.getStat(Stat.SPD);
|
||||
encounter.setDialogueToken("fastestPokemon", fastestPokemon.getNameToRender());
|
||||
|
@ -134,34 +132,34 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const numBerries = encounter.misc.numBerries;
|
||||
|
||||
const doBerryRewards = () => {
|
||||
const berryText = i18next.t(`${namespace}:berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
|
||||
globalScene.playSound("item_fanfare");
|
||||
queueEncounterMessage(i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it
|
||||
for (let i = 0; i < numBerries; i++) {
|
||||
tryGiveBerry(scene);
|
||||
tryGiveBerry();
|
||||
}
|
||||
};
|
||||
|
||||
const shopOptions: ModifierTypeOption[] = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
// Generate shop berries
|
||||
const mod = generateModifierTypeOption(scene, modifierTypes.BERRY);
|
||||
const mod = generateModifierTypeOption(modifierTypes.BERRY);
|
||||
if (mod) {
|
||||
shopOptions.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withOption(
|
||||
|
@ -171,9 +169,9 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.2.label`,
|
||||
buttonTooltip: `${namespace}:option.2.tooltip`
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick race for berries
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const fastestPokemon: PlayerPokemon = encounter.misc.fastestPokemon;
|
||||
const enemySpeed: number = encounter.misc.enemySpeed;
|
||||
const speedDiff = fastestPokemon.getStat(Stat.SPD) / (enemySpeed * 1.1);
|
||||
|
@ -182,7 +180,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
const shopOptions: ModifierTypeOption[] = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
// Generate shop berries
|
||||
const mod = generateModifierTypeOption(scene, modifierTypes.BERRY);
|
||||
const mod = generateModifierTypeOption(modifierTypes.BERRY);
|
||||
if (mod) {
|
||||
shopOptions.push(mod);
|
||||
}
|
||||
|
@ -193,29 +191,29 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
const doBerryRewards = () => {
|
||||
const berryText = i18next.t(`${namespace}:berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
|
||||
globalScene.playSound("item_fanfare");
|
||||
queueEncounterMessage(i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerries }));
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it
|
||||
for (let i = 0; i < numBerries; i++) {
|
||||
tryGiveBerry(scene);
|
||||
tryGiveBerry();
|
||||
}
|
||||
};
|
||||
|
||||
// Defense/Spd buffs below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = globalScene.currentBattle.waveIndex < 50 ?
|
||||
[ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
|
||||
[ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
|
||||
|
||||
const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const config = globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
config.pokemonConfigs![0].tags = [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ];
|
||||
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}:option.2.boss_enraged`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
queueEncounterMessage(`${namespace}:option.2.boss_enraged`);
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
};
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await showEncounterText(scene, `${namespace}:option.2.selected_bad`);
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await showEncounterText(`${namespace}:option.2.selected_bad`);
|
||||
await initBattleWithEnemyConfig(config);
|
||||
return;
|
||||
} else {
|
||||
// Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2
|
||||
|
@ -224,19 +222,19 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
const doFasterBerryRewards = () => {
|
||||
const berryText = i18next.t(`${namespace}:berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
queueEncounterMessage(scene, i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerriesGrabbed }));
|
||||
globalScene.playSound("item_fanfare");
|
||||
queueEncounterMessage(i18next.t("battle:rewardGainCount", { modifierName: berryText, count: numBerriesGrabbed }));
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it (trying to give to fastest first)
|
||||
for (let i = 0; i < numBerriesGrabbed; i++) {
|
||||
tryGiveBerry(scene, fastestPokemon);
|
||||
tryGiveBerry(fastestPokemon);
|
||||
}
|
||||
};
|
||||
|
||||
setEncounterExp(scene, fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doFasterBerryRewards);
|
||||
await showEncounterText(scene, `${namespace}:option.2.selected`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterExp(fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doFasterBerryRewards);
|
||||
await showEncounterText(`${namespace}:option.2.selected`);
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
})
|
||||
.build()
|
||||
|
@ -251,38 +249,38 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
|
||||
function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
||||
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType;
|
||||
const berry = generateModifierType(scene, modifierTypes.BERRY, [ berryType ]) as BerryModifierType;
|
||||
const berry = generateModifierType(modifierTypes.BERRY, [ berryType ]) as BerryModifierType;
|
||||
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
|
||||
// Will try to apply to prioritized pokemon first, then do normal application method if it fails
|
||||
if (prioritizedPokemon) {
|
||||
const heldBerriesOfType = scene.findModifier(m => m instanceof BerryModifier
|
||||
const heldBerriesOfType = globalScene.findModifier(m => m instanceof BerryModifier
|
||||
&& m.pokemonId === prioritizedPokemon.id && (m as BerryModifier).berryType === berryType, true) as BerryModifier;
|
||||
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount(scene)) {
|
||||
applyModifierTypeToPlayerPokemon(scene, prioritizedPokemon, berry);
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
|
||||
applyModifierTypeToPlayerPokemon(prioritizedPokemon, berry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the party until berry was successfully given
|
||||
for (const pokemon of party) {
|
||||
const heldBerriesOfType = scene.findModifier(m => m instanceof BerryModifier
|
||||
const heldBerriesOfType = globalScene.findModifier(m => m instanceof BerryModifier
|
||||
&& m.pokemonId === pokemon.id && (m as BerryModifier).berryType === berryType, true) as BerryModifier;
|
||||
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount(scene)) {
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, berry);
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
|
||||
applyModifierTypeToPlayerPokemon(pokemon, berry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import type {
|
||||
EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import {
|
||||
EnemyPartyConfig, generateModifierType,
|
||||
generateModifierType,
|
||||
generateModifierTypeOption,
|
||||
initBattleWithEnemyConfig,
|
||||
leaveEncounterWithoutBattle,
|
||||
|
@ -17,17 +19,20 @@ import {
|
|||
} from "#app/data/trainer-config";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Species } from "#enums/species";
|
||||
import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { getEncounterText, showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import {
|
||||
|
@ -37,14 +42,17 @@ import {
|
|||
TypeRequirement
|
||||
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { Type } from "#enums/type";
|
||||
import { AttackTypeBoosterModifierType, ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type";
|
||||
import type { AttackTypeBoosterModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import type {
|
||||
PokemonHeldItemModifier
|
||||
} from "#app/modifier/modifier";
|
||||
import {
|
||||
AttackTypeBoosterModifier,
|
||||
BypassSpeedChanceModifier,
|
||||
ContactHeldItemTransferChanceModifier,
|
||||
GigantamaxAccessModifier,
|
||||
MegaEvolutionAccessModifier,
|
||||
PokemonHeldItemModifier
|
||||
MegaEvolutionAccessModifier
|
||||
} from "#app/modifier/modifier";
|
||||
import i18next from "i18next";
|
||||
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
||||
|
@ -214,12 +222,12 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Calculates what trainers are available for battle in the encounter
|
||||
|
||||
// Bug type superfan trainer config
|
||||
const config = getTrainerConfigForWave(scene.currentBattle.waveIndex);
|
||||
const config = getTrainerConfigForWave(globalScene.currentBattle.waveIndex);
|
||||
const spriteKey = config.getSpriteKey();
|
||||
encounter.enemyPartyConfigs.push({
|
||||
trainerConfig: config,
|
||||
|
@ -227,7 +235,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
});
|
||||
|
||||
let beedrillKeys: { spriteKey: string, fileRoot: string }, butterfreeKeys: { spriteKey: string, fileRoot: string };
|
||||
if (scene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
|
||||
if (globalScene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
|
||||
beedrillKeys = getSpriteKeysFromSpecies(Species.BEEDRILL, false);
|
||||
butterfreeKeys = getSpriteKeysFromSpecies(Species.BUTTERFREE, false);
|
||||
} else {
|
||||
|
@ -270,9 +278,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
];
|
||||
|
||||
const requiredItems = [
|
||||
generateModifierType(scene, modifierTypes.QUICK_CLAW),
|
||||
generateModifierType(scene, modifierTypes.GRIP_CLAW),
|
||||
generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.BUG ]),
|
||||
generateModifierType(modifierTypes.QUICK_CLAW),
|
||||
generateModifierType(modifierTypes.GRIP_CLAW),
|
||||
generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.BUG ]),
|
||||
];
|
||||
|
||||
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
|
||||
|
@ -295,9 +303,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Select battle the bug trainer
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
// Init the moves available for tutor
|
||||
|
@ -313,9 +321,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
// Assigns callback that teaches move before continuing to rewards
|
||||
encounter.onRewards = doBugTypeMoveTutor;
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true);
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
await transitionMysteryEncounterIntroVisuals(true, true);
|
||||
await initBattleWithEnemyConfig(config);
|
||||
}
|
||||
)
|
||||
.withOption(MysteryEncounterOptionBuilder
|
||||
|
@ -326,17 +334,17 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.2.tooltip`,
|
||||
disabledButtonTooltip: `${namespace}:option.2.disabled_tooltip`
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Player shows off their bug types
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Player gets different rewards depending on the number of bug types they have
|
||||
const numBugTypes = scene.getPlayerParty().filter(p => p.isOfType(Type.BUG, true)).length;
|
||||
const numBugTypes = globalScene.getPlayerParty().filter(p => p.isOfType(Type.BUG, true)).length;
|
||||
const numBugTypesText = i18next.t(`${namespace}:numBugTypes`, { count: numBugTypes });
|
||||
encounter.setDialogueToken("numBugTypes", numBugTypesText);
|
||||
|
||||
if (numBugTypes < 2) {
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL ], fillRemaining: false });
|
||||
encounter.selectedOption!.dialogue!.selected = [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
|
@ -344,7 +352,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
},
|
||||
];
|
||||
} else if (numBugTypes < 4) {
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL ], fillRemaining: false });
|
||||
encounter.selectedOption!.dialogue!.selected = [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
|
@ -352,7 +360,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
},
|
||||
];
|
||||
} else if (numBugTypes < 6) {
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL ], fillRemaining: false });
|
||||
encounter.selectedOption!.dialogue!.selected = [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
|
@ -362,28 +370,28 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
} else {
|
||||
// If the player has any evolution/form change items that are valid for their party,
|
||||
// spawn one of those items in addition to Dynamax Band, Mega Band, and Master Ball
|
||||
const modifierOptions: ModifierTypeOption[] = [ generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)! ];
|
||||
const modifierOptions: ModifierTypeOption[] = [ generateModifierTypeOption(modifierTypes.MASTER_BALL)! ];
|
||||
const specialOptions: ModifierTypeOption[] = [];
|
||||
|
||||
if (!scene.findModifier(m => m instanceof MegaEvolutionAccessModifier)) {
|
||||
modifierOptions.push(generateModifierTypeOption(scene, modifierTypes.MEGA_BRACELET)!);
|
||||
if (!globalScene.findModifier(m => m instanceof MegaEvolutionAccessModifier)) {
|
||||
modifierOptions.push(generateModifierTypeOption(modifierTypes.MEGA_BRACELET)!);
|
||||
}
|
||||
if (!scene.findModifier(m => m instanceof GigantamaxAccessModifier)) {
|
||||
modifierOptions.push(generateModifierTypeOption(scene, modifierTypes.DYNAMAX_BAND)!);
|
||||
if (!globalScene.findModifier(m => m instanceof GigantamaxAccessModifier)) {
|
||||
modifierOptions.push(generateModifierTypeOption(modifierTypes.DYNAMAX_BAND)!);
|
||||
}
|
||||
const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM);
|
||||
const nonRareEvolutionModifier = generateModifierTypeOption(modifierTypes.EVOLUTION_ITEM);
|
||||
if (nonRareEvolutionModifier) {
|
||||
specialOptions.push(nonRareEvolutionModifier);
|
||||
}
|
||||
const rareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.RARE_EVOLUTION_ITEM);
|
||||
const rareEvolutionModifier = generateModifierTypeOption(modifierTypes.RARE_EVOLUTION_ITEM);
|
||||
if (rareEvolutionModifier) {
|
||||
specialOptions.push(rareEvolutionModifier);
|
||||
}
|
||||
const formChangeModifier = generateModifierTypeOption(scene, modifierTypes.FORM_CHANGE_ITEM);
|
||||
const formChangeModifier = generateModifierTypeOption(modifierTypes.FORM_CHANGE_ITEM);
|
||||
if (formChangeModifier) {
|
||||
specialOptions.push(formChangeModifier);
|
||||
}
|
||||
const rareFormChangeModifier = generateModifierTypeOption(scene, modifierTypes.RARE_FORM_CHANGE_ITEM);
|
||||
const rareFormChangeModifier = generateModifierTypeOption(modifierTypes.RARE_FORM_CHANGE_ITEM);
|
||||
if (rareFormChangeModifier) {
|
||||
specialOptions.push(rareFormChangeModifier);
|
||||
}
|
||||
|
@ -391,7 +399,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifierOptions, fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: modifierOptions, fillRemaining: false });
|
||||
encounter.selectedOption!.dialogue!.selected = [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
|
@ -400,9 +408,9 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
];
|
||||
}
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Player shows off their bug types
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build())
|
||||
.withOption(MysteryEncounterOptionBuilder
|
||||
|
@ -429,8 +437,8 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
],
|
||||
secondOptionPrompt: `${namespace}:option.3.select_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
|
@ -466,27 +474,27 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
(item instanceof AttackTypeBoosterModifier && (item.type as AttackTypeBoosterModifierType).moveType === Type.BUG);
|
||||
});
|
||||
if (!hasValidItem) {
|
||||
return getEncounterText(scene, `${namespace}:option.3.invalid_selection`) ?? null;
|
||||
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier;
|
||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
chosenPokemon.loseHeldItem(modifier, false);
|
||||
scene.updateModifiers(true, true);
|
||||
globalScene.updateModifiers(true, true);
|
||||
|
||||
const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
|
||||
const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
|
||||
bugNet.type.tier = ModifierTier.ROGUE;
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ bugNet ], guaranteedModifierTypeFuncs: [ modifierTypes.REVIVER_SEED ], fillRemaining: false });
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: [ bugNet ], guaranteedModifierTypeFuncs: [ modifierTypes.REVIVER_SEED ], fillRemaining: false });
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build())
|
||||
.withOutroDialogue([
|
||||
|
@ -642,22 +650,22 @@ function getTrainerConfigForWave(waveIndex: number) {
|
|||
return config;
|
||||
}
|
||||
|
||||
function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
|
||||
function doBugTypeMoveTutor(): Promise<void> {
|
||||
return new Promise<void>(async resolve => {
|
||||
const moveOptions = scene.currentBattle.mysteryEncounter!.misc.moveTutorOptions;
|
||||
await showEncounterDialogue(scene, `${namespace}:battle_won`, `${namespace}:speaker`);
|
||||
const moveOptions = globalScene.currentBattle.mysteryEncounter!.misc.moveTutorOptions;
|
||||
await showEncounterDialogue(`${namespace}:battle_won`, `${namespace}:speaker`);
|
||||
|
||||
const overlayScale = 1;
|
||||
const moveInfoOverlay = new MoveInfoOverlay(scene, {
|
||||
const moveInfoOverlay = new MoveInfoOverlay({
|
||||
delayVisibility: false,
|
||||
scale: overlayScale,
|
||||
onSide: true,
|
||||
right: true,
|
||||
x: 1,
|
||||
y: -MoveInfoOverlay.getHeight(overlayScale, true) - 1,
|
||||
width: (scene.game.canvas.width / 6) - 2,
|
||||
width: (globalScene.game.canvas.width / 6) - 2,
|
||||
});
|
||||
scene.ui.add(moveInfoOverlay);
|
||||
globalScene.ui.add(moveInfoOverlay);
|
||||
|
||||
const optionSelectItems = moveOptions.map((move: PokemonMove) => {
|
||||
const option: OptionSelectItem = {
|
||||
|
@ -680,7 +688,7 @@ function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
|
|||
moveInfoOverlay.setVisible(false);
|
||||
};
|
||||
|
||||
const result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}:teach_move_prompt`, undefined, onHoverOverCancel);
|
||||
const result = await selectOptionThenPokemon(optionSelectItems, `${namespace}:teach_move_prompt`, undefined, onHoverOverCancel);
|
||||
// let forceExit = !!result;
|
||||
if (!result) {
|
||||
moveInfoOverlay.active = false;
|
||||
|
@ -691,7 +699,7 @@ function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
|
|||
|
||||
// Option select complete, handle if they are learning a move
|
||||
if (result && result.selectedOptionIndex < moveOptions.length) {
|
||||
scene.unshiftPhase(new LearnMovePhase(scene, result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId));
|
||||
globalScene.unshiftPhase(new LearnMovePhase(result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId));
|
||||
}
|
||||
|
||||
// Complete battle and go to rewards
|
||||
|
|
|
@ -1,26 +1,30 @@
|
|||
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, } from "#app/data/trainer-config";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { ModifierPoolType, modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { applyAbilityOverrideToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { Type } from "#enums/type";
|
||||
import type { Type } from "#enums/type";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { randSeedInt, randSeedShuffle } from "#app/utils";
|
||||
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import i18next from "i18next";
|
||||
import { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { Ability } from "#app/data/ability";
|
||||
import { BerryModifier } from "#app/modifier/modifier";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
|
@ -105,8 +109,8 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
speaker: `${namespace}:speaker`
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const clownTrainerType = TrainerType.HARLEQUIN;
|
||||
const clownConfig = trainerConfigs[clownTrainerType].clone();
|
||||
|
@ -142,7 +146,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
});
|
||||
|
||||
// Load animations/sfx for start of fight moves
|
||||
loadCustomMovesForEncounter(scene, [ Moves.ROLE_PLAY, Moves.TAUNT ]);
|
||||
loadCustomMovesForEncounter([ Moves.ROLE_PLAY, Moves.TAUNT ]);
|
||||
|
||||
encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName());
|
||||
|
||||
|
@ -165,12 +169,12 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Spawn battle
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
|
||||
// TODO: when Magic Room and Wonder Room are implemented, add those to start of battle
|
||||
encounter.startOfBattleEffects.push(
|
||||
|
@ -193,28 +197,28 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
ignorePp: true
|
||||
});
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene);
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
await transitionMysteryEncounterIntroVisuals();
|
||||
await initBattleWithEnemyConfig(config);
|
||||
})
|
||||
.withPostOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
.withPostOptionPhase(async (): Promise<boolean> => {
|
||||
// After the battle, offer the player the opportunity to permanently swap ability
|
||||
const abilityWasSwapped = await handleSwapAbility(scene);
|
||||
const abilityWasSwapped = await handleSwapAbility();
|
||||
if (abilityWasSwapped) {
|
||||
await showEncounterText(scene, `${namespace}:option.1.ability_gained`);
|
||||
await showEncounterText(`${namespace}:option.1.ability_gained`);
|
||||
}
|
||||
|
||||
// Play animations once ability swap is complete
|
||||
// Trainer sprite that is shown at end of battle is not the same as mystery encounter intro visuals
|
||||
scene.tweens.add({
|
||||
targets: scene.currentBattle.trainer,
|
||||
globalScene.tweens.add({
|
||||
targets: globalScene.currentBattle.trainer,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
alpha: 0,
|
||||
ease: "Sine.easeInOut",
|
||||
duration: 250
|
||||
});
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon());
|
||||
background.playWithoutTargets(scene, 230, 40, 2);
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, globalScene.getPlayerPokemon()!, globalScene.getPlayerPokemon());
|
||||
background.playWithoutTargets(230, 40, 2);
|
||||
return true;
|
||||
})
|
||||
.build()
|
||||
|
@ -239,13 +243,13 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Swap player's items on pokemon with the most items
|
||||
// Item comparisons look at whichever Pokemon has the greatest number of TRANSFERABLE, non-berry items
|
||||
// So Vitamins, form change items, etc. are not included
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
let mostHeldItemsPokemon = party[0];
|
||||
let count = mostHeldItemsPokemon.getHeldItems()
|
||||
.filter(m => m.isTransferable && !(m instanceof BerryModifier))
|
||||
|
@ -270,10 +274,10 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
items.filter(m => m instanceof BerryModifier)
|
||||
.forEach(m => {
|
||||
numBerries += m.stackCount;
|
||||
scene.removeModifier(m);
|
||||
globalScene.removeModifier(m);
|
||||
});
|
||||
|
||||
generateItemsOfTier(scene, mostHeldItemsPokemon, numBerries, "Berries");
|
||||
generateItemsOfTier(mostHeldItemsPokemon, numBerries, "Berries");
|
||||
|
||||
// Shuffle Transferable held items in the same tier (only shuffles Ultra and Rogue atm)
|
||||
// For the purpose of this ME, Soothe Bells and Lucky Eggs are counted as Ultra tier
|
||||
|
@ -286,24 +290,24 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
const tier = type.tier ?? ModifierTier.ULTRA;
|
||||
if (type.id === "GOLDEN_EGG" || tier === ModifierTier.ROGUE) {
|
||||
numRogue += m.stackCount;
|
||||
scene.removeModifier(m);
|
||||
globalScene.removeModifier(m);
|
||||
} else if (type.id === "LUCKY_EGG" || type.id === "SOOTHE_BELL" || tier === ModifierTier.ULTRA) {
|
||||
numUltra += m.stackCount;
|
||||
scene.removeModifier(m);
|
||||
globalScene.removeModifier(m);
|
||||
}
|
||||
});
|
||||
|
||||
generateItemsOfTier(scene, mostHeldItemsPokemon, numUltra, ModifierTier.ULTRA);
|
||||
generateItemsOfTier(scene, mostHeldItemsPokemon, numRogue, ModifierTier.ROGUE);
|
||||
generateItemsOfTier(mostHeldItemsPokemon, numUltra, ModifierTier.ULTRA);
|
||||
generateItemsOfTier(mostHeldItemsPokemon, numRogue, ModifierTier.ROGUE);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
.withOptionPhase(async () => {
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||
.withPostOptionPhase(async () => {
|
||||
// Play animations
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon());
|
||||
background.playWithoutTargets(scene, 230, 40, 2);
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 200);
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, globalScene.getPlayerPokemon()!, globalScene.getPlayerPokemon());
|
||||
background.playWithoutTargets(230, 40, 2);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 200);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -327,10 +331,10 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Randomize the second type of all player's pokemon
|
||||
// If the pokemon does not normally have a second type, it will gain 1
|
||||
for (const pokemon of scene.getPlayerParty()) {
|
||||
for (const pokemon of globalScene.getPlayerParty()) {
|
||||
const originalTypes = pokemon.getTypes(false, false, true);
|
||||
|
||||
// If the Pokemon has non-status moves that don't match the Pokemon's type, prioritizes those as the new type
|
||||
|
@ -367,14 +371,14 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
}
|
||||
}
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
.withOptionPhase(async () => {
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||
.withPostOptionPhase(async () => {
|
||||
// Play animations
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon());
|
||||
background.playWithoutTargets(scene, 230, 40, 2);
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 200);
|
||||
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, globalScene.getPlayerPokemon()!, globalScene.getPlayerPokemon());
|
||||
background.playWithoutTargets(230, 40, 2);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 200);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -385,24 +389,24 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
])
|
||||
.build();
|
||||
|
||||
async function handleSwapAbility(scene: BattleScene) {
|
||||
async function handleSwapAbility() {
|
||||
return new Promise<boolean>(async resolve => {
|
||||
await showEncounterDialogue(scene, `${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
|
||||
await showEncounterText(scene, `${namespace}:option.1.apply_ability_message`);
|
||||
await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
|
||||
await showEncounterText(`${namespace}:option.1.apply_ability_message`);
|
||||
|
||||
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
displayYesNoOptions(scene, resolve);
|
||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
displayYesNoOptions(resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function displayYesNoOptions(scene: BattleScene, resolve) {
|
||||
showEncounterText(scene, `${namespace}:option.1.ability_prompt`, null, 500, false);
|
||||
function displayYesNoOptions(resolve) {
|
||||
showEncounterText(`${namespace}:option.1.ability_prompt`, null, 500, false);
|
||||
const fullOptions = [
|
||||
{
|
||||
label: i18next.t("menu:yes"),
|
||||
handler: () => {
|
||||
onYesAbilitySwap(scene, resolve);
|
||||
onYesAbilitySwap(resolve);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
@ -420,29 +424,29 @@ function displayYesNoOptions(scene: BattleScene, resolve) {
|
|||
maxOptions: 7,
|
||||
yOffset: 0
|
||||
};
|
||||
scene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
|
||||
globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
|
||||
}
|
||||
|
||||
function onYesAbilitySwap(scene: BattleScene, resolve) {
|
||||
function onYesAbilitySwap(resolve) {
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Do ability swap
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability);
|
||||
encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
||||
scene.ui.setMode(Mode.MESSAGE).then(() => resolve(true));
|
||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => resolve(true));
|
||||
};
|
||||
|
||||
const onPokemonNotSelected = () => {
|
||||
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
displayYesNoOptions(scene, resolve);
|
||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
displayYesNoOptions(resolve);
|
||||
});
|
||||
};
|
||||
|
||||
selectPokemonForOption(scene, onPokemonSelected, onPokemonNotSelected);
|
||||
selectPokemonForOption(onPokemonSelected, onPokemonNotSelected);
|
||||
}
|
||||
|
||||
function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItems: number, tier: ModifierTier | "Berries") {
|
||||
function generateItemsOfTier(pokemon: PlayerPokemon, numItems: number, tier: ModifierTier | "Berries") {
|
||||
// These pools have to be defined at runtime so that modifierTypes exist
|
||||
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
|
||||
// This is to prevent "over-generating" a random item of a certain type during item swaps
|
||||
|
@ -495,11 +499,11 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
|
|||
const newItemType = pool[randIndex];
|
||||
let newMod: PokemonHeldItemModifierType;
|
||||
if (tier === "Berries") {
|
||||
newMod = generateModifierType(scene, modifierTypes.BERRY, [ newItemType[0] ]) as PokemonHeldItemModifierType;
|
||||
newMod = generateModifierType(modifierTypes.BERRY, [ newItemType[0] ]) as PokemonHeldItemModifierType;
|
||||
} else {
|
||||
newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType;
|
||||
newMod = generateModifierType(newItemType[0]) as PokemonHeldItemModifierType;
|
||||
}
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, newMod);
|
||||
applyModifierTypeToPlayerPokemon(pokemon, newMod);
|
||||
// Decrement max stacks and remove from pool if at max
|
||||
newItemType[1]--;
|
||||
if (newItemType[1] <= 0) {
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { DANCING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { catchPokemon, getEncounterPokemonLevelForWave, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { Biome } from "#enums/biome";
|
||||
import { EncounterAnim } from "#enums/encounter-anims";
|
||||
|
@ -91,10 +95,10 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
.withAutoHideIntroVisuals(false)
|
||||
.withCatchAllowed(true)
|
||||
.withFleeAllowed(false)
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
const oricorio = scene.getEnemyPokemon()!;
|
||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, oricorio, scene.getPlayerPokemon()!);
|
||||
danceAnim.play(scene, false, () => {
|
||||
.withOnVisualsStart(() => {
|
||||
const oricorio = globalScene.getEnemyPokemon()!;
|
||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, oricorio, globalScene.getPlayerPokemon()!);
|
||||
danceAnim.play(false, () => {
|
||||
if (oricorio.shiny) {
|
||||
oricorio.sparkle();
|
||||
}
|
||||
|
@ -110,12 +114,12 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const species = getPokemonSpecies(Species.ORICORIO);
|
||||
const level = getEncounterPokemonLevelForWave(scene, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
const enemyPokemon = new EnemyPokemon(scene, species, level, TrainerSlot.NONE, false);
|
||||
const level = getEncounterPokemonLevelForWave(STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
const enemyPokemon = new EnemyPokemon(species, level, TrainerSlot.NONE, false);
|
||||
if (!enemyPokemon.moveset.some(m => m && m.getMove().id === Moves.REVELATION_DANCE)) {
|
||||
if (enemyPokemon.moveset.length < 4) {
|
||||
enemyPokemon.moveset.push(new PokemonMove(Moves.REVELATION_DANCE));
|
||||
|
@ -126,7 +130,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
|
||||
// Set the form index based on the biome
|
||||
// Defaults to Baile style if somehow nothing matches
|
||||
const currentBiome = scene.arena.biomeType;
|
||||
const currentBiome = globalScene.arena.biomeType;
|
||||
if (BAILE_STYLE_BIOMES.includes(currentBiome)) {
|
||||
enemyPokemon.formIndex = 0;
|
||||
} else if (POM_POM_STYLE_BIOMES.includes(currentBiome)) {
|
||||
|
@ -140,14 +144,14 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
}
|
||||
|
||||
const oricorioData = new PokemonData(enemyPokemon);
|
||||
const oricorio = scene.addEnemyPokemon(species, level, TrainerSlot.NONE, false, false, oricorioData);
|
||||
const oricorio = globalScene.addEnemyPokemon(species, level, TrainerSlot.NONE, false, false, oricorioData);
|
||||
|
||||
// Adds a real Pokemon sprite to the field (required for the animation)
|
||||
scene.getEnemyParty().forEach(enemyPokemon => {
|
||||
scene.field.remove(enemyPokemon, true);
|
||||
globalScene.getEnemyParty().forEach(enemyPokemon => {
|
||||
globalScene.field.remove(enemyPokemon, true);
|
||||
});
|
||||
scene.currentBattle.enemyParty = [ oricorio ];
|
||||
scene.field.add(oricorio);
|
||||
globalScene.currentBattle.enemyParty = [ oricorio ];
|
||||
globalScene.field.add(oricorio);
|
||||
// Spawns on offscreen field
|
||||
oricorio.x -= 300;
|
||||
encounter.loadAssets.push(oricorio.loadAssets());
|
||||
|
@ -160,8 +164,8 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
// Gets +1 to all stats except SPD on battle start
|
||||
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF ], 1));
|
||||
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF ], 1));
|
||||
}
|
||||
}],
|
||||
};
|
||||
|
@ -186,9 +190,9 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
encounter.startOfBattleEffects.push({
|
||||
sourceBattlerIndex: BattlerIndex.ENEMY,
|
||||
|
@ -197,9 +201,9 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
ignorePp: true
|
||||
});
|
||||
|
||||
await hideOricorioPokemon(scene);
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.BATON ], fillRemaining: true });
|
||||
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
|
||||
await hideOricorioPokemon();
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.BATON ], fillRemaining: true });
|
||||
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -215,25 +219,25 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Learn its Dance
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
scene.unshiftPhase(new LearnMovePhase(scene, scene.getPlayerParty().indexOf(pokemon), Moves.REVELATION_DANCE));
|
||||
globalScene.unshiftPhase(new LearnMovePhase(globalScene.getPlayerParty().indexOf(pokemon), Moves.REVELATION_DANCE));
|
||||
|
||||
// Play animation again to "learn" the dance
|
||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getPlayerPokemon());
|
||||
danceAnim.play(scene);
|
||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, globalScene.getEnemyPokemon()!, globalScene.getPlayerPokemon());
|
||||
danceAnim.play();
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Learn its Dance
|
||||
await hideOricorioPokemon(scene);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await hideOricorioPokemon();
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -252,9 +256,9 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Open menu for selecting pokemon with a Dancing move
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for nature selection
|
||||
return pokemon.moveset
|
||||
|
@ -281,20 +285,20 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
if (!pokemon.isAllowedInBattle()) {
|
||||
return i18next.t("partyUiHandler:cantBeUsed", { pokemonName: pokemon.getNameToRender() }) ?? null;
|
||||
}
|
||||
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon);
|
||||
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(pokemon);
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
|
||||
return getEncounterText(`${namespace}:invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Show the Oricorio a dance, and recruit it
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const oricorio = encounter.misc.oricorioData.toPokemon(scene);
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const oricorio = encounter.misc.oricorioData.toPokemon();
|
||||
oricorio.passive = true;
|
||||
|
||||
// Ensure the Oricorio's moveset gains the Dance move the player used
|
||||
|
@ -307,18 +311,18 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
}
|
||||
}
|
||||
|
||||
await hideOricorioPokemon(scene);
|
||||
await catchPokemon(scene, oricorio, null, PokeballType.POKEBALL, false);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await hideOricorioPokemon();
|
||||
await catchPokemon(oricorio, null, PokeballType.POKEBALL, false);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
function hideOricorioPokemon(scene: BattleScene) {
|
||||
function hideOricorioPokemon() {
|
||||
return new Promise<void>(resolve => {
|
||||
const oricorioSprite = scene.getEnemyParty()[0];
|
||||
scene.tweens.add({
|
||||
const oricorioSprite = globalScene.getEnemyParty()[0];
|
||||
globalScene.tweens.add({
|
||||
targets: oricorioSprite,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
|
@ -326,7 +330,7 @@ function hideOricorioPokemon(scene: BattleScene) {
|
|||
ease: "Sine.easeInOut",
|
||||
duration: 750,
|
||||
onComplete: () => {
|
||||
scene.field.remove(oricorioSprite, true);
|
||||
globalScene.field.remove(oricorioSprite, true);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import { Type } from "#enums/type";
|
||||
import type { Type } from "#enums/type";
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils";
|
||||
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
||||
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils";
|
||||
import { getRandomPlayerPokemon, getRandomSpeciesByStarterCost } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||
import { PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
|
@ -138,16 +141,16 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Removes random pokemon (including fainted) from party and adds name to dialogue data tokens
|
||||
// Will never return last battle able mon and instead pick fainted/unable to battle
|
||||
const removedPokemon = getRandomPlayerPokemon(scene, true, false, true);
|
||||
const removedPokemon = getRandomPlayerPokemon(true, false, true);
|
||||
|
||||
// Get all the pokemon's held items
|
||||
const modifiers = removedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier));
|
||||
scene.removePokemonFromPlayerParty(removedPokemon);
|
||||
globalScene.removePokemonFromPlayerParty(removedPokemon);
|
||||
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
encounter.setDialogueToken("pokeName", removedPokemon.getNameToRender());
|
||||
|
||||
// Store removed pokemon types
|
||||
|
@ -156,16 +159,16 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
modifiers
|
||||
};
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Give the player 5 Rogue Balls
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ROGUE_BALL));
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.ROGUE_BALL));
|
||||
|
||||
// Start encounter with random legendary (7-10 starter strength) that has level additive
|
||||
// If this is a mono-type challenge, always ensure the required type is filtered for
|
||||
let bossTypes: Type[] = encounter.misc.removedTypes;
|
||||
const singleTypeChallenges = scene.gameMode.challenges.filter(c => c.value && c.id === Challenges.SINGLE_TYPE);
|
||||
if (scene.gameMode.isChallenge && singleTypeChallenges.length > 0) {
|
||||
const singleTypeChallenges = globalScene.gameMode.challenges.filter(c => c.value && c.id === Challenges.SINGLE_TYPE);
|
||||
if (globalScene.gameMode.isChallenge && singleTypeChallenges.length > 0) {
|
||||
bossTypes = singleTypeChallenges.map(c => (c.value - 1) as Type);
|
||||
}
|
||||
|
||||
|
@ -191,7 +194,7 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
const config: EnemyPartyConfig = {
|
||||
pokemonConfigs: [ pokemonConfig ],
|
||||
};
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
await initBattleWithEnemyConfig(config);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -206,9 +209,9 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { CombinationPokemonRequirement, HeldItemRequirement, MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { generateModifierType, leaveEncounterWithoutBattle, selectPokemonForOption, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
||||
import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { randSeedItem } from "#app/utils";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
@ -36,19 +40,19 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
|
|||
|
||||
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
|
||||
|
||||
const doEventReward = (scene: BattleScene) => {
|
||||
const event_buff = scene.eventManager.activeEvent()?.delibirdyBuff ?? [];
|
||||
const doEventReward = () => {
|
||||
const event_buff = globalScene.eventManager.getDelibirdyBuff();
|
||||
if (event_buff.length > 0) {
|
||||
const candidates = event_buff.filter((c => {
|
||||
const mtype = generateModifierType(scene, modifierTypes[c]);
|
||||
const existingCharm = scene.findModifier(m => m.type.id === mtype?.id);
|
||||
return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount(scene));
|
||||
const mtype = generateModifierType(modifierTypes[c]);
|
||||
const existingCharm = globalScene.findModifier(m => m.type.id === mtype?.id);
|
||||
return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount());
|
||||
}));
|
||||
if (candidates.length > 0) {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes[randSeedItem(candidates)]));
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)]));
|
||||
} else {
|
||||
// At max stacks, give a Voucher instead
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.VOUCHER));
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.VOUCHER));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -114,15 +118,15 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
text: `${namespace}:outro`,
|
||||
}
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
encounter.setDialogueToken("delibirdName", getPokemonSpecies(Species.DELIBIRD).getName());
|
||||
|
||||
scene.loadBgm("mystery_encounter_delibirdy", "mystery_encounter_delibirdy.mp3");
|
||||
globalScene.loadBgm("mystery_encounter_delibirdy", "mystery_encounter_delibirdy.mp3");
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
scene.fadeAndSwitchBgm("mystery_encounter_delibirdy");
|
||||
.withOnVisualsStart(() => {
|
||||
globalScene.fadeAndSwitchBgm("mystery_encounter_delibirdy");
|
||||
return true;
|
||||
})
|
||||
.withOption(
|
||||
|
@ -138,29 +142,29 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney, true, false);
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
updatePlayerMoney(-(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney, true, false);
|
||||
return true;
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Give the player an Amulet Coin
|
||||
// Check if the player has max stacks of that item already
|
||||
const existing = scene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier;
|
||||
const existing = globalScene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier;
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getPlayerPokemon()!, shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward(scene);
|
||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
||||
globalScene.playSound("item_fanfare");
|
||||
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward();
|
||||
} else {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.AMULET_COIN));
|
||||
doEventReward(scene);
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN));
|
||||
doEventReward();
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -178,8 +182,8 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter((it) => {
|
||||
|
@ -205,57 +209,57 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
// If pokemon has valid item, it can be selected
|
||||
const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(scene, pokemon);
|
||||
const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(pokemon);
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
|
||||
return getEncounterText(`${namespace}:invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const modifier: BerryModifier | PokemonInstantReviveModifier = encounter.misc.chosenModifier;
|
||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
// Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed
|
||||
if (modifier instanceof BerryModifier) {
|
||||
// Check if the player has max stacks of that Candy Jar already
|
||||
const existing = scene.findModifier(m => m instanceof LevelIncrementBoosterModifier) as LevelIncrementBoosterModifier;
|
||||
const existing = globalScene.findModifier(m => m instanceof LevelIncrementBoosterModifier) as LevelIncrementBoosterModifier;
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getPlayerPokemon()!, shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward(scene);
|
||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
||||
globalScene.playSound("item_fanfare");
|
||||
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward();
|
||||
} else {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR));
|
||||
doEventReward(scene);
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR));
|
||||
doEventReward();
|
||||
}
|
||||
} else {
|
||||
// Check if the player has max stacks of that Berry Pouch already
|
||||
const existing = scene.findModifier(m => m instanceof PreserveBerryModifier) as PreserveBerryModifier;
|
||||
const existing = globalScene.findModifier(m => m instanceof PreserveBerryModifier) as PreserveBerryModifier;
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getPlayerPokemon()!, shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward(scene);
|
||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
||||
globalScene.playSound("item_fanfare");
|
||||
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward();
|
||||
} else {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH));
|
||||
doEventReward(scene);
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH));
|
||||
doEventReward();
|
||||
}
|
||||
}
|
||||
|
||||
chosenPokemon.loseHeldItem(modifier, false);
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -273,8 +277,8 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter((it) => {
|
||||
|
@ -300,39 +304,39 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
// If pokemon has valid item, it can be selected
|
||||
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon);
|
||||
const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(pokemon);
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`) ?? null;
|
||||
return getEncounterText(`${namespace}:invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier;
|
||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
// Check if the player has max stacks of Healing Charm already
|
||||
const existing = scene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier;
|
||||
const existing = globalScene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier;
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getPlayerParty()[0], shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward(scene);
|
||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerParty()[0], shellBell);
|
||||
globalScene.playSound("item_fanfare");
|
||||
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
doEventReward();
|
||||
} else {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM));
|
||||
doEventReward(scene);
|
||||
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM));
|
||||
doEventReward();
|
||||
}
|
||||
|
||||
chosenPokemon.loseHeldItem(modifier, false);
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
|
|
@ -2,12 +2,13 @@ import {
|
|||
leaveEncounterWithoutBattle,
|
||||
setEncounterRewards,
|
||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { ModifierTypeFunc, modifierTypes } from "#app/modifier/modifier-type";
|
||||
import type { ModifierTypeFunc } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, {
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import {
|
||||
MysteryEncounterBuilder,
|
||||
} from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
@ -60,7 +61,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.1.label`,
|
||||
buttonTooltip: `${namespace}:option.1.tooltip`,
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Choose TMs
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
|
@ -77,8 +78,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
i++;
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -86,7 +87,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.2.label`,
|
||||
buttonTooltip: `${namespace}:option.2.tooltip`,
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Choose Vitamins
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
|
@ -101,8 +102,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
i++;
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -110,7 +111,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.3.label`,
|
||||
buttonTooltip: `${namespace}:option.3.tooltip`,
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Choose X Items
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
|
@ -125,8 +126,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
i++;
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -134,7 +135,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.4.label`,
|
||||
buttonTooltip: `${namespace}:option.4.tooltip`,
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Choose Pokeballs
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
|
@ -153,8 +154,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
|||
i++;
|
||||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
|
||||
leaveEncounterWithoutBattle();
|
||||
}
|
||||
)
|
||||
.withOutroDialogue([
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { MoveCategory } from "#app/data/move";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { Stat } from "#enums/stat";
|
||||
|
@ -64,8 +65,8 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.1.tooltip`,
|
||||
secondOptionPrompt: `${namespace}:second_option_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -74,7 +75,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
handler: () => {
|
||||
// Pokemon and move selected
|
||||
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:physical`));
|
||||
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.PHYSICAL);
|
||||
pokemonAndMoveChosen(pokemon, move, MoveCategory.PHYSICAL);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
@ -82,23 +83,23 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
});
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ATK ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.DEF ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
|
||||
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ATK ])!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.DEF ])!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(modifierTypes.DIRE_HIT)!,
|
||||
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
|
||||
];
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);
|
||||
leaveEncounterWithoutBattle(!encounter.misc.correctMove);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -110,8 +111,8 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.2.tooltip`,
|
||||
secondOptionPrompt: `${namespace}:second_option_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -120,7 +121,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
handler: () => {
|
||||
// Pokemon and move selected
|
||||
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:special`));
|
||||
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.SPECIAL);
|
||||
pokemonAndMoveChosen(pokemon, move, MoveCategory.SPECIAL);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
@ -128,23 +129,23 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
});
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPATK ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPDEF ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
|
||||
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPATK ])!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPDEF ])!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(modifierTypes.DIRE_HIT)!,
|
||||
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
|
||||
];
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);
|
||||
leaveEncounterWithoutBattle(!encounter.misc.correctMove);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -156,8 +157,8 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.3.tooltip`,
|
||||
secondOptionPrompt: `${namespace}:second_option_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -166,7 +167,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
handler: () => {
|
||||
// Pokemon and move selected
|
||||
encounter.setDialogueToken("moveCategory", i18next.t(`${namespace}:status`));
|
||||
pokemonAndMoveChosen(scene, pokemon, move, MoveCategory.STATUS);
|
||||
pokemonAndMoveChosen(pokemon, move, MoveCategory.STATUS);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
@ -174,30 +175,30 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
});
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ACC ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!,
|
||||
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!,
|
||||
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ACC ])!,
|
||||
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
|
||||
generateModifierTypeOption(modifierTypes.GREAT_BALL)!,
|
||||
generateModifierTypeOption(modifierTypes.IV_SCANNER)!,
|
||||
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
|
||||
];
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);
|
||||
leaveEncounterWithoutBattle(!encounter.misc.correctMove);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
function pokemonAndMoveChosen(scene: BattleScene, pokemon: PlayerPokemon, move: PokemonMove, correctMoveCategory: MoveCategory) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
function pokemonAndMoveChosen(pokemon: PlayerPokemon, move: PokemonMove, correctMoveCategory: MoveCategory) {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const correctMove = move.getMove().category === correctMoveCategory;
|
||||
encounter.setDialogueToken("pokeName", pokemon.getNameToRender());
|
||||
encounter.setDialogueToken("move", move.getName());
|
||||
|
@ -214,7 +215,7 @@ function pokemonAndMoveChosen(scene: BattleScene, pokemon: PlayerPokemon, move:
|
|||
text: `${namespace}:incorrect_exp`,
|
||||
},
|
||||
];
|
||||
setEncounterExp(scene, scene.getPlayerParty().map((p) => p.id), 50);
|
||||
setEncounterExp(globalScene.getPlayerParty().map((p) => p.id), 50);
|
||||
} else {
|
||||
encounter.selectedOption!.dialogue!.selected = [
|
||||
{
|
||||
|
@ -228,7 +229,7 @@ function pokemonAndMoveChosen(scene: BattleScene, pokemon: PlayerPokemon, move:
|
|||
text: `${namespace}:correct_exp`,
|
||||
},
|
||||
];
|
||||
setEncounterExp(scene, [ pokemon.id ], 100);
|
||||
setEncounterExp([ pokemon.id ], 100);
|
||||
}
|
||||
encounter.misc = {
|
||||
correctMove: correctMove,
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals, generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { AttackTypeBoosterModifierType, modifierTypes, } from "#app/modifier/modifier-type";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals, generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes, } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { AbilityRequirement, CombinationPokemonRequirement, TypeRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { Species } from "#enums/species";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import { Type } from "#enums/type";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import Pokemon, { PokemonMove } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
|
@ -58,8 +62,8 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mons
|
||||
const volcaronaSpecies = getPokemonSpecies(Species.VOLCARONA);
|
||||
|
@ -71,7 +75,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
gender: Gender.MALE,
|
||||
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1));
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -80,7 +84,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
gender: Gender.FEMALE,
|
||||
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1));
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -113,25 +117,25 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
];
|
||||
|
||||
// Load animations/sfx for Volcarona moves
|
||||
loadCustomMovesForEncounter(scene, [ Moves.FIRE_SPIN, Moves.QUIVER_DANCE ]);
|
||||
loadCustomMovesForEncounter([ Moves.FIRE_SPIN, Moves.QUIVER_DANCE ]);
|
||||
|
||||
scene.arena.trySetWeather(WeatherType.SUNNY, true);
|
||||
globalScene.arena.trySetWeather(WeatherType.SUNNY, true);
|
||||
|
||||
encounter.setDialogueToken("volcaronaName", getPokemonSpecies(Species.VOLCARONA).getName());
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
.withOnVisualsStart(() => {
|
||||
// Play animations
|
||||
const background = new EncounterBattleAnim(EncounterAnim.MAGMA_BG, scene.getPlayerPokemon()!, scene.getPlayerPokemon());
|
||||
background.playWithoutTargets(scene, 200, 70, 2, 3);
|
||||
const animation = new EncounterBattleAnim(EncounterAnim.MAGMA_SPOUT, scene.getPlayerPokemon()!, scene.getPlayerPokemon());
|
||||
animation.playWithoutTargets(scene, 80, 100, 2);
|
||||
scene.time.delayedCall(600, () => {
|
||||
animation.playWithoutTargets(scene, -20, 100, 2);
|
||||
const background = new EncounterBattleAnim(EncounterAnim.MAGMA_BG, globalScene.getPlayerPokemon()!, globalScene.getPlayerPokemon());
|
||||
background.playWithoutTargets(200, 70, 2, 3);
|
||||
const animation = new EncounterBattleAnim(EncounterAnim.MAGMA_SPOUT, globalScene.getPlayerPokemon()!, globalScene.getPlayerPokemon());
|
||||
animation.playWithoutTargets(80, 100, 2);
|
||||
globalScene.time.delayedCall(600, () => {
|
||||
animation.playWithoutTargets(-20, 100, 2);
|
||||
});
|
||||
scene.time.delayedCall(1200, () => {
|
||||
animation.playWithoutTargets(scene, 140, 150, 2);
|
||||
globalScene.time.delayedCall(1200, () => {
|
||||
animation.playWithoutTargets(140, 150, 2);
|
||||
});
|
||||
|
||||
return true;
|
||||
|
@ -150,10 +154,10 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards(scene, { fillRemaining: true }, undefined, () => giveLeadPokemonAttackTypeBoostItem(scene));
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards({ fillRemaining: true }, undefined, () => giveLeadPokemonAttackTypeBoostItem());
|
||||
|
||||
encounter.startOfBattleEffects.push(
|
||||
{
|
||||
|
@ -168,7 +172,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
move: new PokemonMove(Moves.FIRE_SPIN),
|
||||
ignorePp: true
|
||||
});
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -181,15 +185,15 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Damage non-fire types and burn 1 random non-fire type member + give it Heatproof
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const nonFireTypes = scene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.getTypes().includes(Type.FIRE));
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const nonFireTypes = globalScene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.getTypes().includes(Type.FIRE));
|
||||
|
||||
for (const pkm of nonFireTypes) {
|
||||
const percentage = DAMAGE_PERCENTAGE / 100;
|
||||
const damage = Math.floor(pkm.getMaxHp() * percentage);
|
||||
applyDamageToPokemon(scene, pkm, damage);
|
||||
applyDamageToPokemon(pkm, damage);
|
||||
}
|
||||
|
||||
// Burn random member
|
||||
|
@ -201,7 +205,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
// Burn applied
|
||||
encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender());
|
||||
encounter.setDialogueToken("abilityName", new Ability(Abilities.HEATPROOF, 3).name);
|
||||
queueEncounterMessage(scene, `${namespace}:option.2.target_burned`);
|
||||
queueEncounterMessage(`${namespace}:option.2.target_burned`);
|
||||
|
||||
// Also permanently change the burned Pokemon's ability to Heatproof
|
||||
applyAbilityOverrideToPokemon(chosenPokemon, Abilities.HEATPROOF);
|
||||
|
@ -209,7 +213,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
}
|
||||
|
||||
// No rewards
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
}
|
||||
)
|
||||
.withOption(
|
||||
|
@ -231,44 +235,44 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Do NOT await this, to prevent player from repeatedly pressing options
|
||||
transitionMysteryEncounterIntroVisuals(scene, false, false, 2000);
|
||||
transitionMysteryEncounterIntroVisuals(false, false, 2000);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Fire types help calm the Volcarona
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
await transitionMysteryEncounterIntroVisuals(scene);
|
||||
setEncounterRewards(scene,
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
await transitionMysteryEncounterIntroVisuals();
|
||||
setEncounterRewards(
|
||||
{ fillRemaining: true },
|
||||
undefined,
|
||||
() => {
|
||||
giveLeadPokemonAttackTypeBoostItem(scene);
|
||||
giveLeadPokemonAttackTypeBoostItem();
|
||||
});
|
||||
|
||||
const primary = encounter.options[2].primaryPokemon!;
|
||||
|
||||
setEncounterExp(scene, [ primary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterExp([ primary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2);
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
function giveLeadPokemonAttackTypeBoostItem(scene: BattleScene) {
|
||||
function giveLeadPokemonAttackTypeBoostItem() {
|
||||
// Give first party pokemon attack type boost item for free at end of battle
|
||||
const leadPokemon = scene.getPlayerParty()?.[0];
|
||||
const leadPokemon = globalScene.getPlayerParty()?.[0];
|
||||
if (leadPokemon) {
|
||||
// Generate type booster held item, default to Charcoal if item fails to generate
|
||||
let boosterModifierType = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER) as AttackTypeBoosterModifierType;
|
||||
let boosterModifierType = generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER) as AttackTypeBoosterModifierType;
|
||||
if (!boosterModifierType) {
|
||||
boosterModifierType = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType;
|
||||
boosterModifierType = generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType;
|
||||
}
|
||||
applyModifierTypeToPlayerPokemon(scene, leadPokemon, boosterModifierType);
|
||||
applyModifierTypeToPlayerPokemon(leadPokemon, boosterModifierType);
|
||||
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
encounter.setDialogueToken("itemName", boosterModifierType.name);
|
||||
encounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
||||
queueEncounterMessage(scene, `${namespace}:found_item`);
|
||||
queueEncounterMessage(`${namespace}:found_item`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,37 @@
|
|||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import type {
|
||||
EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import {
|
||||
EnemyPartyConfig,
|
||||
getRandomEncounterSpecies,
|
||||
initBattleWithEnemyConfig,
|
||||
leaveEncounterWithoutBattle, setEncounterExp,
|
||||
leaveEncounterWithoutBattle,
|
||||
setEncounterExp,
|
||||
setEncounterRewards
|
||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import Pokemon, { EnemyPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import type {
|
||||
ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||
import {
|
||||
getPartyLuckValue,
|
||||
getPlayerModifierTypeOptions,
|
||||
ModifierPoolType,
|
||||
ModifierTypeOption,
|
||||
regenerateModifierPoolThresholds,
|
||||
} from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { getEncounterPokemonLevelForWave, getSpriteKeysFromPokemon, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { randSeedInt, randSeedItem } from "#app/utils";
|
||||
import { randSeedInt } from "#app/utils";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/fightOrFlight";
|
||||
|
@ -52,33 +54,25 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const level = getEncounterPokemonLevelForWave(scene, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
let bossSpecies: PokemonSpecies;
|
||||
if (scene.eventManager.isEventActive() && scene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
|
||||
const eventEncounter = randSeedItem(scene.eventManager.activeEvent()!.uncommonBreedEncounters!);
|
||||
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, scene.gameMode);
|
||||
bossSpecies = getPokemonSpecies( levelSpecies );
|
||||
} else {
|
||||
bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getPlayerParty()), true);
|
||||
}
|
||||
const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true);
|
||||
const level = getEncounterPokemonLevelForWave(STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER);
|
||||
const bossPokemon = getRandomEncounterSpecies(level, true);
|
||||
encounter.setDialogueToken("enemyPokemon", bossPokemon.getNameToRender());
|
||||
const config: EnemyPartyConfig = {
|
||||
pokemonConfigs: [{
|
||||
level: level,
|
||||
species: bossSpecies,
|
||||
species: bossPokemon.species,
|
||||
dataSource: new PokemonData(bossPokemon),
|
||||
isBoss: true,
|
||||
tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`);
|
||||
queueEncounterMessage(`${namespace}:option.1.stat_boost`);
|
||||
// Randomly boost 1 stat 2 stages
|
||||
// Cannot boost Spd, Acc, or Evasion
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randSeedInt(4, 1) ], 2));
|
||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ randSeedInt(4, 1) ], 2));
|
||||
}
|
||||
}],
|
||||
};
|
||||
|
@ -87,18 +81,18 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
// Calculate item
|
||||
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
|
||||
const tier =
|
||||
scene.currentBattle.waveIndex > 160
|
||||
globalScene.currentBattle.waveIndex > 160
|
||||
? ModifierTier.MASTER
|
||||
: scene.currentBattle.waveIndex > 120
|
||||
: globalScene.currentBattle.waveIndex > 120
|
||||
? ModifierTier.ROGUE
|
||||
: scene.currentBattle.waveIndex > 40
|
||||
: globalScene.currentBattle.waveIndex > 40
|
||||
? ModifierTier.ULTRA
|
||||
: ModifierTier.GREAT;
|
||||
regenerateModifierPoolThresholds(scene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
||||
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
||||
let item: ModifierTypeOption | null = null;
|
||||
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
|
||||
while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") {
|
||||
item = getPlayerModifierTypeOptions(1, scene.getPlayerParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
|
||||
item = getPlayerModifierTypeOptions(1, globalScene.getPlayerParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
|
||||
}
|
||||
encounter.setDialogueToken("itemName", item.type.name);
|
||||
encounter.misc = item;
|
||||
|
@ -144,12 +138,12 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Pick battle
|
||||
// Pokemon will randomly boost 1 stat by 2 stages
|
||||
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
const item = globalScene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withOption(
|
||||
|
@ -166,16 +160,16 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
}
|
||||
]
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick steal
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const item = globalScene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
|
||||
// Use primaryPokemon to execute the thievery
|
||||
const primaryPokemon = encounter.options[1].primaryPokemon!;
|
||||
setEncounterExp(scene, primaryPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterExp(primaryPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -189,9 +183,9 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import Pokemon, { FieldPosition, PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { FieldPosition } from "#app/field/pokemon";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
|
@ -80,14 +83,14 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
scene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3");
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
globalScene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3");
|
||||
encounter.setDialogueToken("wobbuffetName", getPokemonSpecies(Species.WOBBUFFET).getName());
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
scene.fadeAndSwitchBgm("mystery_encounter_fun_and_games");
|
||||
.withOnVisualsStart(() => {
|
||||
globalScene.fadeAndSwitchBgm("mystery_encounter_fun_and_games");
|
||||
return true;
|
||||
})
|
||||
.withOption(MysteryEncounterOptionBuilder
|
||||
|
@ -102,9 +105,9 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Select Pokemon for minigame
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.misc = {
|
||||
playerPokemon: pokemon,
|
||||
|
@ -113,28 +116,28 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
|||
|
||||
// Only Pokemon that are not KOed/legal can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, `${namespace}:invalid_selection`);
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Start minigame
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
encounter.misc.turnsRemaining = 3;
|
||||
|
||||
// Update money
|
||||
const moneyCost = (encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney;
|
||||
updatePlayerMoney(scene, -moneyCost, true, false);
|
||||
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:paid_money", { amount: moneyCost }));
|
||||
updatePlayerMoney(-moneyCost, true, false);
|
||||
await showEncounterText(i18next.t("mysteryEncounterMessages:paid_money", { amount: moneyCost }));
|
||||
|
||||
// Handlers for battle events
|
||||
encounter.onTurnStart = handleNextTurn; // triggered during TurnInitPhase
|
||||
encounter.doContinueEncounter = handleLoseMinigame; // triggered during MysteryEncounterRewardsPhase, post VictoryPhase if the player KOs Wobbuffet
|
||||
|
||||
hideShowmanIntroSprite(scene);
|
||||
await summonPlayerPokemon(scene);
|
||||
await showWobbuffetHealthBar(scene);
|
||||
hideShowmanIntroSprite();
|
||||
await summonPlayerPokemon();
|
||||
await showWobbuffetHealthBar();
|
||||
|
||||
return true;
|
||||
})
|
||||
|
@ -150,22 +153,22 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
async function summonPlayerPokemon(scene: BattleScene) {
|
||||
async function summonPlayerPokemon() {
|
||||
return new Promise<void>(async resolve => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const playerPokemon = encounter.misc.playerPokemon;
|
||||
// Swaps the chosen Pokemon and the first player's lead Pokemon in the party
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
const chosenIndex = party.indexOf(playerPokemon);
|
||||
if (chosenIndex !== 0) {
|
||||
const leadPokemon = party[0];
|
||||
|
@ -175,36 +178,36 @@ async function summonPlayerPokemon(scene: BattleScene) {
|
|||
|
||||
// Do trainer summon animation
|
||||
let playerAnimationPromise: Promise<void> | undefined;
|
||||
scene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(playerPokemon) }));
|
||||
scene.pbTray.hide();
|
||||
scene.trainer.setTexture(`trainer_${scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
|
||||
scene.time.delayedCall(562, () => {
|
||||
scene.trainer.setFrame("2");
|
||||
scene.time.delayedCall(64, () => {
|
||||
scene.trainer.setFrame("3");
|
||||
globalScene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(playerPokemon) }));
|
||||
globalScene.pbTray.hide();
|
||||
globalScene.trainer.setTexture(`trainer_${globalScene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
|
||||
globalScene.time.delayedCall(562, () => {
|
||||
globalScene.trainer.setFrame("2");
|
||||
globalScene.time.delayedCall(64, () => {
|
||||
globalScene.trainer.setFrame("3");
|
||||
});
|
||||
});
|
||||
scene.tweens.add({
|
||||
targets: scene.trainer,
|
||||
globalScene.tweens.add({
|
||||
targets: globalScene.trainer,
|
||||
x: -36,
|
||||
duration: 1000,
|
||||
onComplete: () => scene.trainer.setVisible(false)
|
||||
onComplete: () => globalScene.trainer.setVisible(false)
|
||||
});
|
||||
scene.time.delayedCall(750, () => {
|
||||
playerAnimationPromise = summonPlayerPokemonAnimation(scene, playerPokemon);
|
||||
globalScene.time.delayedCall(750, () => {
|
||||
playerAnimationPromise = summonPlayerPokemonAnimation(playerPokemon);
|
||||
});
|
||||
|
||||
// Also loads Wobbuffet data (cannot be shiny)
|
||||
const enemySpecies = getPokemonSpecies(Species.WOBBUFFET);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false, true);
|
||||
globalScene.currentBattle.enemyParty = [];
|
||||
const wobbuffet = globalScene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false, true);
|
||||
wobbuffet.ivs = [ 0, 0, 0, 0, 0, 0 ];
|
||||
wobbuffet.setNature(Nature.MILD);
|
||||
wobbuffet.setAlpha(0);
|
||||
wobbuffet.setVisible(false);
|
||||
wobbuffet.calculateStats();
|
||||
scene.currentBattle.enemyParty[0] = wobbuffet;
|
||||
scene.gameData.setPokemonSeen(wobbuffet, true);
|
||||
globalScene.currentBattle.enemyParty[0] = wobbuffet;
|
||||
globalScene.gameData.setPokemonSeen(wobbuffet, true);
|
||||
await wobbuffet.loadAssets();
|
||||
const id = setInterval(checkPlayerAnimationPromise, 500);
|
||||
async function checkPlayerAnimationPromise() {
|
||||
|
@ -217,37 +220,37 @@ async function summonPlayerPokemon(scene: BattleScene) {
|
|||
});
|
||||
}
|
||||
|
||||
function handleLoseMinigame(scene: BattleScene) {
|
||||
function handleLoseMinigame() {
|
||||
return new Promise<void>(async resolve => {
|
||||
// Check Wobbuffet is still alive
|
||||
const wobbuffet = scene.getEnemyPokemon();
|
||||
const wobbuffet = globalScene.getEnemyPokemon();
|
||||
if (!wobbuffet || wobbuffet.isFainted(true) || wobbuffet.hp === 0) {
|
||||
// Player loses
|
||||
// End the battle
|
||||
if (wobbuffet) {
|
||||
wobbuffet.hideInfo();
|
||||
scene.field.remove(wobbuffet);
|
||||
globalScene.field.remove(wobbuffet);
|
||||
}
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, true);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await showEncounterText(scene, `${namespace}:ko`);
|
||||
const reviveCost = scene.getWaveMoneyAmount(1.5);
|
||||
updatePlayerMoney(scene, -reviveCost, true, false);
|
||||
transitionMysteryEncounterIntroVisuals(true, true);
|
||||
globalScene.currentBattle.enemyParty = [];
|
||||
globalScene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(true);
|
||||
await showEncounterText(`${namespace}:ko`);
|
||||
const reviveCost = globalScene.getWaveMoneyAmount(1.5);
|
||||
updatePlayerMoney(-reviveCost, true, false);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function handleNextTurn(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
function handleNextTurn() {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const wobbuffet = scene.getEnemyPokemon();
|
||||
const wobbuffet = globalScene.getEnemyPokemon();
|
||||
if (!wobbuffet) {
|
||||
// Should never be triggered, just handling the edge case
|
||||
handleLoseMinigame(scene);
|
||||
handleLoseMinigame();
|
||||
return true;
|
||||
}
|
||||
if (encounter.misc.turnsRemaining <= 0) {
|
||||
|
@ -257,15 +260,15 @@ function handleNextTurn(scene: BattleScene) {
|
|||
let isHealPhase = false;
|
||||
if (healthRatio < 0.03) {
|
||||
// Grand prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MULTI_LENS ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.MULTI_LENS ], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}:best_result`;
|
||||
} else if (healthRatio < 0.15) {
|
||||
// 2nd prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SCOPE_LENS ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.SCOPE_LENS ], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}:great_result`;
|
||||
} else if (healthRatio < 0.33) {
|
||||
// 3rd prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.WIDE_LENS ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.WIDE_LENS ], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}:good_result`;
|
||||
} else {
|
||||
// No prize
|
||||
|
@ -275,22 +278,22 @@ function handleNextTurn(scene: BattleScene) {
|
|||
|
||||
// End the battle
|
||||
wobbuffet.hideInfo();
|
||||
scene.field.remove(wobbuffet);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(scene, isHealPhase);
|
||||
globalScene.field.remove(wobbuffet);
|
||||
globalScene.currentBattle.enemyParty = [];
|
||||
globalScene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(isHealPhase);
|
||||
// Must end the TurnInit phase prematurely so battle phases aren't added to queue
|
||||
queueEncounterMessage(scene, `${namespace}:end_game`);
|
||||
queueEncounterMessage(scene, resultMessageKey);
|
||||
queueEncounterMessage(`${namespace}:end_game`);
|
||||
queueEncounterMessage(resultMessageKey);
|
||||
|
||||
// Skip remainder of TurnInitPhase
|
||||
return true;
|
||||
} else {
|
||||
if (encounter.misc.turnsRemaining < 3) {
|
||||
// Display charging messages on turns that aren't the initial turn
|
||||
queueEncounterMessage(scene, `${namespace}:charging_continue`);
|
||||
queueEncounterMessage(`${namespace}:charging_continue`);
|
||||
}
|
||||
queueEncounterMessage(scene, `${namespace}:turn_remaining_${encounter.misc.turnsRemaining}`);
|
||||
queueEncounterMessage(`${namespace}:turn_remaining_${encounter.misc.turnsRemaining}`);
|
||||
encounter.misc.turnsRemaining--;
|
||||
}
|
||||
|
||||
|
@ -298,33 +301,33 @@ function handleNextTurn(scene: BattleScene) {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function showWobbuffetHealthBar(scene: BattleScene) {
|
||||
const wobbuffet = scene.getEnemyPokemon()!;
|
||||
async function showWobbuffetHealthBar() {
|
||||
const wobbuffet = globalScene.getEnemyPokemon()!;
|
||||
|
||||
scene.add.existing(wobbuffet);
|
||||
scene.field.add(wobbuffet);
|
||||
globalScene.add.existing(wobbuffet);
|
||||
globalScene.field.add(wobbuffet);
|
||||
|
||||
const playerPokemon = scene.getPlayerPokemon() as Pokemon;
|
||||
const playerPokemon = globalScene.getPlayerPokemon() as Pokemon;
|
||||
if (playerPokemon?.isOnField()) {
|
||||
scene.field.moveBelow(wobbuffet, playerPokemon);
|
||||
globalScene.field.moveBelow(wobbuffet, playerPokemon);
|
||||
}
|
||||
// Show health bar and trigger cry
|
||||
wobbuffet.showInfo();
|
||||
scene.time.delayedCall(1000, () => {
|
||||
globalScene.time.delayedCall(1000, () => {
|
||||
wobbuffet.cry();
|
||||
});
|
||||
wobbuffet.resetSummonData();
|
||||
|
||||
// Track the HP change across turns
|
||||
scene.currentBattle.mysteryEncounter!.misc.wobbuffetHealth = wobbuffet.hp;
|
||||
globalScene.currentBattle.mysteryEncounter!.misc.wobbuffetHealth = wobbuffet.hp;
|
||||
}
|
||||
|
||||
function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon): Promise<void> {
|
||||
function summonPlayerPokemonAnimation(pokemon: PlayerPokemon): Promise<void> {
|
||||
return new Promise<void>(resolve => {
|
||||
const pokeball = scene.addFieldSprite(36, 80, "pb", getPokeballAtlasKey(pokemon.pokeball));
|
||||
const pokeball = globalScene.addFieldSprite(36, 80, "pb", getPokeballAtlasKey(pokemon.pokeball));
|
||||
pokeball.setVisible(false);
|
||||
pokeball.setOrigin(0.5, 0.625);
|
||||
scene.field.add(pokeball);
|
||||
globalScene.field.add(pokeball);
|
||||
|
||||
pokemon.setFieldPosition(FieldPosition.CENTER, 0);
|
||||
|
||||
|
@ -332,32 +335,32 @@ function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon
|
|||
|
||||
pokeball.setVisible(true);
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 650,
|
||||
x: 100 + fpOffset[0]
|
||||
});
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 150,
|
||||
ease: "Cubic.easeOut",
|
||||
y: 70 + fpOffset[1],
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 500,
|
||||
ease: "Cubic.easeIn",
|
||||
angle: 1440,
|
||||
y: 132 + fpOffset[1],
|
||||
onComplete: () => {
|
||||
scene.playSound("se/pb_rel");
|
||||
globalScene.playSound("se/pb_rel");
|
||||
pokeball.destroy();
|
||||
scene.add.existing(pokemon);
|
||||
scene.field.add(pokemon);
|
||||
addPokeballOpenParticles(scene, pokemon.x, pokemon.y - 16, pokemon.pokeball);
|
||||
scene.updateModifiers(true);
|
||||
scene.updateFieldScale();
|
||||
globalScene.add.existing(pokemon);
|
||||
globalScene.field.add(pokemon);
|
||||
addPokeballOpenParticles(pokemon.x, pokemon.y - 16, pokemon.pokeball);
|
||||
globalScene.updateModifiers(true);
|
||||
globalScene.updateFieldScale();
|
||||
pokemon.showInfo();
|
||||
pokemon.playAnim();
|
||||
pokemon.setVisible(true);
|
||||
|
@ -365,8 +368,8 @@ function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon
|
|||
pokemon.setScale(0.5);
|
||||
pokemon.tint(getPokeballTintColor(pokemon.pokeball));
|
||||
pokemon.untint(250, "Sine.easeIn");
|
||||
scene.updateFieldScale();
|
||||
scene.tweens.add({
|
||||
globalScene.updateFieldScale();
|
||||
globalScene.tweens.add({
|
||||
targets: pokemon,
|
||||
duration: 250,
|
||||
ease: "Sine.easeIn",
|
||||
|
@ -375,15 +378,15 @@ function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon
|
|||
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
|
||||
pokemon.getSprite().clearTint();
|
||||
pokemon.resetSummonData();
|
||||
scene.time.delayedCall(1000, () => {
|
||||
globalScene.time.delayedCall(1000, () => {
|
||||
if (pokemon.isShiny()) {
|
||||
scene.unshiftPhase(new ShinySparklePhase(scene, pokemon.getBattlerIndex()));
|
||||
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
|
||||
}
|
||||
|
||||
pokemon.resetTurnData();
|
||||
|
||||
scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
scene.pushPhase(new PostSummonPhase(scene, pokemon.getBattlerIndex()));
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
globalScene.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex()));
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
@ -395,13 +398,13 @@ function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon
|
|||
});
|
||||
}
|
||||
|
||||
function hideShowmanIntroSprite(scene: BattleScene) {
|
||||
const carnivalGame = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(0)[0];
|
||||
const wobbuffet = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1)[0];
|
||||
const showMan = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(2)[0];
|
||||
function hideShowmanIntroSprite() {
|
||||
const carnivalGame = globalScene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(0)[0];
|
||||
const wobbuffet = globalScene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1)[0];
|
||||
const showMan = globalScene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(2)[0];
|
||||
|
||||
// Hide the showman
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: showMan,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
|
@ -411,7 +414,7 @@ function hideShowmanIntroSprite(scene: BattleScene) {
|
|||
});
|
||||
|
||||
// Slide the Wobbuffet and Game over slightly
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: [ wobbuffet, carnivalGame ],
|
||||
x: "+=16",
|
||||
ease: "Sine.easeInOut",
|
||||
|
|
|
@ -2,20 +2,26 @@ import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterReward
|
|||
import { TrainerSlot, } from "#app/data/trainer-config";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { MusicPreference } from "#app/system/settings/settings";
|
||||
import { getPlayerModifierTypeOptions, ModifierPoolType, ModifierTypeOption, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||
import { getPlayerModifierTypeOptions, ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { Species } from "#enums/species";
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { NumberHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle } from "#app/utils";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, ShinyRateBoosterModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, ShinyRateBoosterModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import i18next from "i18next";
|
||||
import { Gender, getGenderSymbol } from "#app/data/gender";
|
||||
|
@ -102,24 +108,24 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Load bgm
|
||||
let bgmKey: string;
|
||||
if (scene.musicPreference === MusicPreference.GENFIVE) {
|
||||
if (globalScene.musicPreference === MusicPreference.GENFIVE) {
|
||||
bgmKey = "mystery_encounter_gen_5_gts";
|
||||
scene.loadBgm(bgmKey, `${bgmKey}.mp3`);
|
||||
globalScene.loadBgm(bgmKey, `${bgmKey}.mp3`);
|
||||
} else {
|
||||
// Mixed option
|
||||
bgmKey = "mystery_encounter_gen_6_gts";
|
||||
scene.loadBgm(bgmKey, `${bgmKey}.mp3`);
|
||||
globalScene.loadBgm(bgmKey, `${bgmKey}.mp3`);
|
||||
}
|
||||
|
||||
// Load possible trade options
|
||||
// Maps current party member's id to 3 EnemyPokemon objects
|
||||
// None of the trade options can be the same species
|
||||
const tradeOptionsMap: Map<number, EnemyPokemon[]> = getPokemonTradeOptions(scene);
|
||||
const tradeOptionsMap: Map<number, EnemyPokemon[]> = getPokemonTradeOptions();
|
||||
encounter.misc = {
|
||||
tradeOptionsMap,
|
||||
bgmKey
|
||||
|
@ -127,8 +133,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
scene.fadeAndSwitchBgm(scene.currentBattle.mysteryEncounter!.misc.bgmKey);
|
||||
.withOnVisualsStart(() => {
|
||||
globalScene.fadeAndSwitchBgm(globalScene.currentBattle.mysteryEncounter!.misc.bgmKey);
|
||||
return true;
|
||||
})
|
||||
.withOption(
|
||||
|
@ -140,8 +146,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.1.tooltip`,
|
||||
secondOptionPrompt: `${namespace}:option.1.trade_options_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get the trade species options for the selected pokemon
|
||||
const tradeOptionsMap: Map<number, EnemyPokemon[]> = encounter.misc.tradeOptionsMap;
|
||||
|
@ -165,17 +171,17 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[tradePokemon.formIndex].formName : null;
|
||||
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
|
||||
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
|
||||
showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false);
|
||||
showEncounterText(`${line1}\n${line2}`, 0, 0, false);
|
||||
},
|
||||
};
|
||||
return option;
|
||||
});
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||
const modifiers = tradedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
||||
|
@ -185,32 +191,32 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
encounter.setDialogueToken("tradeTrainerName", traderName.trim());
|
||||
|
||||
// Remove the original party member from party
|
||||
scene.removePokemonFromPlayerParty(tradedPokemon, false);
|
||||
globalScene.removePokemonFromPlayerParty(tradedPokemon, false);
|
||||
|
||||
// Set data properly, then generate the new Pokemon's assets
|
||||
receivedPokemonData.passive = tradedPokemon.passive;
|
||||
// Pokeball to Ultra ball, randomly
|
||||
receivedPokemonData.pokeball = randInt(4) as PokeballType;
|
||||
const dataSource = new PokemonData(receivedPokemonData);
|
||||
const newPlayerPokemon = scene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, dataSource.abilityIndex, dataSource.formIndex, dataSource.gender, dataSource.shiny, dataSource.variant, dataSource.ivs, dataSource.nature, dataSource);
|
||||
scene.getPlayerParty().push(newPlayerPokemon);
|
||||
const newPlayerPokemon = globalScene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, dataSource.abilityIndex, dataSource.formIndex, dataSource.gender, dataSource.shiny, dataSource.variant, dataSource.ivs, dataSource.nature, dataSource);
|
||||
globalScene.getPlayerParty().push(newPlayerPokemon);
|
||||
await newPlayerPokemon.loadAssets();
|
||||
|
||||
for (const mod of modifiers) {
|
||||
mod.pokemonId = newPlayerPokemon.id;
|
||||
scene.addModifier(mod, true, false, false, true);
|
||||
globalScene.addModifier(mod, true, false, false, true);
|
||||
}
|
||||
|
||||
// Show the trade animation
|
||||
await showTradeBackground(scene);
|
||||
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
||||
await showEncounterText(scene, `${namespace}:trade_received`, null, 0, true, 4000);
|
||||
scene.playBgm(encounter.misc.bgmKey);
|
||||
await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon);
|
||||
await hideTradeBackground(scene);
|
||||
await showTradeBackground();
|
||||
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
||||
await showEncounterText(`${namespace}:trade_received`, null, 0, true, 4000);
|
||||
globalScene.playBgm(encounter.misc.bgmKey);
|
||||
await addPokemonDataToDexAndValidateAchievements(newPlayerPokemon);
|
||||
await hideTradeBackground();
|
||||
tradedPokemon.destroy();
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -222,19 +228,19 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
buttonLabel: `${namespace}:option.2.label`,
|
||||
buttonTooltip: `${namespace}:option.2.tooltip`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Randomly generate a Wonder Trade pokemon
|
||||
const randomTradeOption = generateTradeOption(scene.getPlayerParty().map(p => p.species));
|
||||
const tradePokemon = new EnemyPokemon(scene, randomTradeOption, pokemon.level, TrainerSlot.NONE, false);
|
||||
const randomTradeOption = generateTradeOption(globalScene.getPlayerParty().map(p => p.species));
|
||||
const tradePokemon = new EnemyPokemon(randomTradeOption, pokemon.level, TrainerSlot.NONE, false);
|
||||
// Extra shiny roll at 1/128 odds (boosted by events and charms)
|
||||
if (!tradePokemon.shiny) {
|
||||
const shinyThreshold = new NumberHolder(WONDER_TRADE_SHINY_CHANCE);
|
||||
if (scene.eventManager.isEventActive()) {
|
||||
shinyThreshold.value *= scene.eventManager.getShinyMultiplier();
|
||||
if (globalScene.eventManager.isEventActive()) {
|
||||
shinyThreshold.value *= globalScene.eventManager.getShinyMultiplier();
|
||||
}
|
||||
scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
|
||||
globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
|
||||
|
||||
// Base shiny chance of 512/65536 -> 1/128, affected by events and Shiny Charms
|
||||
// Maximum shiny chance of 4096/65536 -> 1/16, cannot improve further after that
|
||||
|
@ -248,7 +254,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
if (tradePokemon.species.abilityHidden) {
|
||||
if (tradePokemon.abilityIndex < hiddenIndex) {
|
||||
const hiddenAbilityChance = new NumberHolder(64);
|
||||
scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||
globalScene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||
|
||||
const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
|
||||
|
||||
|
@ -281,10 +287,10 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
encounter.misc.receivedPokemon = tradePokemon;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
return selectPokemonForOption(onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||
const modifiers = tradedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
||||
|
@ -294,31 +300,31 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
encounter.setDialogueToken("tradeTrainerName", traderName.trim());
|
||||
|
||||
// Remove the original party member from party
|
||||
scene.removePokemonFromPlayerParty(tradedPokemon, false);
|
||||
globalScene.removePokemonFromPlayerParty(tradedPokemon, false);
|
||||
|
||||
// Set data properly, then generate the new Pokemon's assets
|
||||
receivedPokemonData.passive = tradedPokemon.passive;
|
||||
receivedPokemonData.pokeball = randInt(4) as PokeballType;
|
||||
const dataSource = new PokemonData(receivedPokemonData);
|
||||
const newPlayerPokemon = scene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, dataSource.abilityIndex, dataSource.formIndex, dataSource.gender, dataSource.shiny, dataSource.variant, dataSource.ivs, dataSource.nature, dataSource);
|
||||
scene.getPlayerParty().push(newPlayerPokemon);
|
||||
const newPlayerPokemon = globalScene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, dataSource.abilityIndex, dataSource.formIndex, dataSource.gender, dataSource.shiny, dataSource.variant, dataSource.ivs, dataSource.nature, dataSource);
|
||||
globalScene.getPlayerParty().push(newPlayerPokemon);
|
||||
await newPlayerPokemon.loadAssets();
|
||||
|
||||
for (const mod of modifiers) {
|
||||
mod.pokemonId = newPlayerPokemon.id;
|
||||
scene.addModifier(mod, true, false, false, true);
|
||||
globalScene.addModifier(mod, true, false, false, true);
|
||||
}
|
||||
|
||||
// Show the trade animation
|
||||
await showTradeBackground(scene);
|
||||
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
||||
await showEncounterText(scene, `${namespace}:trade_received`, null, 0, true, 4000);
|
||||
scene.playBgm(encounter.misc.bgmKey);
|
||||
await addPokemonDataToDexAndValidateAchievements(scene, newPlayerPokemon);
|
||||
await hideTradeBackground(scene);
|
||||
await showTradeBackground();
|
||||
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
||||
await showEncounterText(`${namespace}:trade_received`, null, 0, true, 4000);
|
||||
globalScene.playBgm(encounter.misc.bgmKey);
|
||||
await addPokemonDataToDexAndValidateAchievements(newPlayerPokemon);
|
||||
await hideTradeBackground();
|
||||
tradedPokemon.destroy();
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -330,8 +336,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}:option.3.tooltip`,
|
||||
secondOptionPrompt: `${namespace}:option.3.trade_options_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async (): Promise<boolean> => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter((it) => {
|
||||
|
@ -359,18 +365,18 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
return it.isTransferable;
|
||||
}).length > 0;
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:option.3.invalid_selection`) ?? null;
|
||||
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier as PokemonHeldItemModifier;
|
||||
const party = scene.getPlayerParty();
|
||||
const party = globalScene.getPlayerParty();
|
||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
// Check tier of the traded item, the received item will be one tier up
|
||||
|
@ -397,16 +403,16 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
}
|
||||
|
||||
encounter.setDialogueToken("itemName", item.type.name);
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
setEncounterRewards({ guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
|
||||
|
||||
chosenPokemon.loseHeldItem(modifier, false);
|
||||
await scene.updateModifiers(true, true);
|
||||
await globalScene.updateModifiers(true, true);
|
||||
|
||||
// Generate a trainer name
|
||||
const traderName = generateRandomTraderName();
|
||||
encounter.setDialogueToken("tradeTrainerName", traderName.trim());
|
||||
await showEncounterText(scene, `${namespace}:item_trade_selected`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
await showEncounterText(`${namespace}:item_trade_selected`);
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -420,26 +426,26 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
function getPokemonTradeOptions(scene: BattleScene): Map<number, EnemyPokemon[]> {
|
||||
function getPokemonTradeOptions(): Map<number, EnemyPokemon[]> {
|
||||
const tradeOptionsMap: Map<number, EnemyPokemon[]> = new Map<number, EnemyPokemon[]>();
|
||||
// Starts by filtering out any current party members as valid resulting species
|
||||
const alreadyUsedSpecies: PokemonSpecies[] = scene.getPlayerParty().map(p => p.species);
|
||||
const alreadyUsedSpecies: PokemonSpecies[] = globalScene.getPlayerParty().map(p => p.species);
|
||||
|
||||
scene.getPlayerParty().forEach(pokemon => {
|
||||
globalScene.getPlayerParty().forEach(pokemon => {
|
||||
// If the party member is legendary/mythical, the only trade options available are always pulled from generation-specific legendary trade pools
|
||||
if (pokemon.species.legendary || pokemon.species.subLegendary || pokemon.species.mythical) {
|
||||
const generation = pokemon.species.generation;
|
||||
const tradeOptions: EnemyPokemon[] = LEGENDARY_TRADE_POOLS[generation].map(s => {
|
||||
const pokemonSpecies = getPokemonSpecies(s);
|
||||
return new EnemyPokemon(scene, pokemonSpecies, 5, TrainerSlot.NONE, false);
|
||||
return new EnemyPokemon(pokemonSpecies, 5, TrainerSlot.NONE, false);
|
||||
});
|
||||
tradeOptionsMap.set(pokemon.id, tradeOptions);
|
||||
} else {
|
||||
|
@ -454,7 +460,7 @@ function getPokemonTradeOptions(scene: BattleScene): Map<number, EnemyPokemon[]>
|
|||
|
||||
// Add trade options to map
|
||||
tradeOptionsMap.set(pokemon.id, tradeOptions.map(s => {
|
||||
return new EnemyPokemon(scene, s, pokemon.level, TrainerSlot.NONE, false);
|
||||
return new EnemyPokemon(s, pokemon.level, TrainerSlot.NONE, false);
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
@ -497,28 +503,28 @@ function generateTradeOption(alreadyUsedSpecies: PokemonSpecies[], originalBst?:
|
|||
return newSpecies!;
|
||||
}
|
||||
|
||||
function showTradeBackground(scene: BattleScene) {
|
||||
function showTradeBackground() {
|
||||
return new Promise<void>(resolve => {
|
||||
const tradeContainer = scene.add.container(0, -scene.game.canvas.height / 6);
|
||||
const tradeContainer = globalScene.add.container(0, -globalScene.game.canvas.height / 6);
|
||||
tradeContainer.setName("Trade Background");
|
||||
|
||||
const flyByStaticBg = scene.add.rectangle(0, 0, scene.game.canvas.width / 6, scene.game.canvas.height / 6, 0);
|
||||
const flyByStaticBg = globalScene.add.rectangle(0, 0, globalScene.game.canvas.width / 6, globalScene.game.canvas.height / 6, 0);
|
||||
flyByStaticBg.setName("Black Background");
|
||||
flyByStaticBg.setOrigin(0, 0);
|
||||
flyByStaticBg.setVisible(false);
|
||||
tradeContainer.add(flyByStaticBg);
|
||||
|
||||
const tradeBaseBg = scene.add.image(0, 0, "default_bg");
|
||||
const tradeBaseBg = globalScene.add.image(0, 0, "default_bg");
|
||||
tradeBaseBg.setName("Trade Background Image");
|
||||
tradeBaseBg.setOrigin(0, 0);
|
||||
tradeContainer.add(tradeBaseBg);
|
||||
|
||||
scene.fieldUI.add(tradeContainer);
|
||||
scene.fieldUI.bringToTop(tradeContainer);
|
||||
globalScene.fieldUI.add(tradeContainer);
|
||||
globalScene.fieldUI.bringToTop(tradeContainer);
|
||||
tradeContainer.setVisible(true);
|
||||
tradeContainer.alpha = 0;
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradeContainer,
|
||||
alpha: 1,
|
||||
duration: 500,
|
||||
|
@ -530,17 +536,17 @@ function showTradeBackground(scene: BattleScene) {
|
|||
});
|
||||
}
|
||||
|
||||
function hideTradeBackground(scene: BattleScene) {
|
||||
function hideTradeBackground() {
|
||||
return new Promise<void>(resolve => {
|
||||
const transformationContainer = scene.fieldUI.getByName("Trade Background");
|
||||
const transformationContainer = globalScene.fieldUI.getByName("Trade Background");
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: transformationContainer,
|
||||
alpha: 0,
|
||||
duration: 1000,
|
||||
ease: "Sine.easeInOut",
|
||||
onComplete: () => {
|
||||
scene.fieldUI.remove(transformationContainer, true);
|
||||
globalScene.fieldUI.remove(transformationContainer, true);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
@ -549,13 +555,12 @@ function hideTradeBackground(scene: BattleScene) {
|
|||
|
||||
/**
|
||||
* Initiates an "evolution-like" animation to transform a previousPokemon (presumably from the player's party) into a new one, not necessarily an evolution species.
|
||||
* @param scene
|
||||
* @param tradedPokemon
|
||||
* @param receivedPokemon
|
||||
*/
|
||||
function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon, receivedPokemon: PlayerPokemon) {
|
||||
function doPokemonTradeSequence(tradedPokemon: PlayerPokemon, receivedPokemon: PlayerPokemon) {
|
||||
return new Promise<void>(resolve => {
|
||||
const tradeContainer = scene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeContainer = globalScene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeBaseBg = tradeContainer.getByName("Trade Background Image") as Phaser.GameObjects.Image;
|
||||
|
||||
let tradedPokemonSprite: Phaser.GameObjects.Sprite;
|
||||
|
@ -564,8 +569,8 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
let receivedPokemonTintSprite: Phaser.GameObjects.Sprite;
|
||||
|
||||
const getPokemonSprite = () => {
|
||||
const ret = scene.addPokemonSprite(tradedPokemon, tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pkmn__sub");
|
||||
ret.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
|
||||
const ret = globalScene.addPokemonSprite(tradedPokemon, tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pkmn__sub");
|
||||
ret.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -589,7 +594,7 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", tradedPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", tradedPokemon.shiny);
|
||||
|
@ -610,7 +615,7 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", receivedPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", receivedPokemon.shiny);
|
||||
|
@ -625,45 +630,45 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
|
||||
// Traded pokemon pokeball
|
||||
const tradedPbAtlasKey = getPokeballAtlasKey(tradedPokemon.pokeball);
|
||||
const tradedPokeball: Phaser.GameObjects.Sprite = scene.add.sprite(tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pb", tradedPbAtlasKey);
|
||||
const tradedPokeball: Phaser.GameObjects.Sprite = globalScene.add.sprite(tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pb", tradedPbAtlasKey);
|
||||
tradedPokeball.setVisible(false);
|
||||
tradeContainer.add(tradedPokeball);
|
||||
|
||||
// Received pokemon pokeball
|
||||
const receivedPbAtlasKey = getPokeballAtlasKey(receivedPokemon.pokeball);
|
||||
const receivedPokeball: Phaser.GameObjects.Sprite = scene.add.sprite(tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pb", receivedPbAtlasKey);
|
||||
const receivedPokeball: Phaser.GameObjects.Sprite = globalScene.add.sprite(tradeBaseBg.displayWidth / 2, tradeBaseBg.displayHeight / 2, "pb", receivedPbAtlasKey);
|
||||
receivedPokeball.setVisible(false);
|
||||
tradeContainer.add(receivedPokeball);
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokemonSprite,
|
||||
alpha: 1,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: 500,
|
||||
onComplete: async () => {
|
||||
scene.fadeOutBgm(1000, false);
|
||||
await showEncounterText(scene, `${namespace}:pokemon_trade_selected`);
|
||||
globalScene.fadeOutBgm(1000, false);
|
||||
await showEncounterText(`${namespace}:pokemon_trade_selected`);
|
||||
tradedPokemon.cry();
|
||||
scene.playBgm("evolution");
|
||||
await showEncounterText(scene, `${namespace}:pokemon_trade_goodbye`);
|
||||
globalScene.playBgm("evolution");
|
||||
await showEncounterText(`${namespace}:pokemon_trade_goodbye`);
|
||||
|
||||
tradedPokeball.setAlpha(0);
|
||||
tradedPokeball.setVisible(true);
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokeball,
|
||||
alpha: 1,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: 250,
|
||||
onComplete: () => {
|
||||
tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}_opening`);
|
||||
scene.time.delayedCall(17, () => tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}_open`));
|
||||
scene.playSound("se/pb_rel");
|
||||
globalScene.time.delayedCall(17, () => tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}_open`));
|
||||
globalScene.playSound("se/pb_rel");
|
||||
tradedPokemonTintSprite.setVisible(true);
|
||||
|
||||
// TODO: need to add particles to fieldUI instead of field
|
||||
// addPokeballOpenParticles(scene, tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball);
|
||||
// addPokeballOpenParticles(tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball);
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: [ tradedPokemonTintSprite, tradedPokemonSprite ],
|
||||
duration: 500,
|
||||
ease: "Sine.easeIn",
|
||||
|
@ -672,30 +677,30 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
tradedPokemonSprite.setVisible(false);
|
||||
tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}_opening`);
|
||||
tradedPokemonTintSprite.setVisible(false);
|
||||
scene.playSound("se/pb_catch");
|
||||
scene.time.delayedCall(17, () => tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}`));
|
||||
globalScene.playSound("se/pb_catch");
|
||||
globalScene.time.delayedCall(17, () => tradedPokeball.setTexture("pb", `${tradedPbAtlasKey}`));
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokeball,
|
||||
y: "+=10",
|
||||
duration: 200,
|
||||
delay: 250,
|
||||
ease: "Cubic.easeIn",
|
||||
onComplete: () => {
|
||||
scene.playSound("se/pb_bounce_1");
|
||||
globalScene.playSound("se/pb_bounce_1");
|
||||
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokeball,
|
||||
y: "-=100",
|
||||
duration: 200,
|
||||
delay: 1000,
|
||||
ease: "Cubic.easeInOut",
|
||||
onStart: () => {
|
||||
scene.playSound("se/pb_throw");
|
||||
globalScene.playSound("se/pb_throw");
|
||||
},
|
||||
onComplete: async () => {
|
||||
await doPokemonTradeFlyBySequence(scene, tradedPokemonSprite, receivedPokemonSprite);
|
||||
await doTradeReceivedSequence(scene, receivedPokemon, receivedPokemonSprite, receivedPokemonTintSprite, receivedPokeball, receivedPbAtlasKey);
|
||||
await doPokemonTradeFlyBySequence(tradedPokemonSprite, receivedPokemonSprite);
|
||||
await doTradeReceivedSequence(receivedPokemon, receivedPokemonSprite, receivedPokemonTintSprite, receivedPokeball, receivedPbAtlasKey);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
@ -710,9 +715,9 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
|
|||
});
|
||||
}
|
||||
|
||||
function doPokemonTradeFlyBySequence(scene: BattleScene, tradedPokemonSprite: Phaser.GameObjects.Sprite, receivedPokemonSprite: Phaser.GameObjects.Sprite) {
|
||||
function doPokemonTradeFlyBySequence(tradedPokemonSprite: Phaser.GameObjects.Sprite, receivedPokemonSprite: Phaser.GameObjects.Sprite) {
|
||||
return new Promise<void>(resolve => {
|
||||
const tradeContainer = scene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeContainer = globalScene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeBaseBg = tradeContainer.getByName("Trade Background Image") as Phaser.GameObjects.Image;
|
||||
const flyByStaticBg = tradeContainer.getByName("Black Background") as Phaser.GameObjects.Rectangle;
|
||||
flyByStaticBg.setVisible(true);
|
||||
|
@ -733,47 +738,47 @@ function doPokemonTradeFlyBySequence(scene: BattleScene, tradedPokemonSprite: Ph
|
|||
const BASE_ANIM_DURATION = 1000;
|
||||
|
||||
// Fade out trade background
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradeBaseBg,
|
||||
alpha: 0,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: FADE_DELAY,
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: [ receivedPokemonSprite, tradedPokemonSprite ],
|
||||
y: tradeBaseBg.displayWidth / 2 - 100,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION * 3,
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: receivedPokemonSprite,
|
||||
x: tradeBaseBg.displayWidth / 4,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION / 2,
|
||||
delay: ANIM_DELAY
|
||||
});
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokemonSprite,
|
||||
x: tradeBaseBg.displayWidth * 3 / 4,
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION / 2,
|
||||
delay: ANIM_DELAY,
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: receivedPokemonSprite,
|
||||
y: "+=200",
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION * 2,
|
||||
delay: ANIM_DELAY,
|
||||
});
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradedPokemonSprite,
|
||||
y: "-=200",
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION * 2,
|
||||
delay: ANIM_DELAY,
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: tradeBaseBg,
|
||||
alpha: 1,
|
||||
ease: "Cubic.easeInOut",
|
||||
|
@ -793,9 +798,9 @@ function doPokemonTradeFlyBySequence(scene: BattleScene, tradedPokemonSprite: Ph
|
|||
});
|
||||
}
|
||||
|
||||
function doTradeReceivedSequence(scene: BattleScene, receivedPokemon: PlayerPokemon, receivedPokemonSprite: Phaser.GameObjects.Sprite, receivedPokemonTintSprite: Phaser.GameObjects.Sprite, receivedPokeballSprite: Phaser.GameObjects.Sprite, receivedPbAtlasKey: string) {
|
||||
function doTradeReceivedSequence(receivedPokemon: PlayerPokemon, receivedPokemonSprite: Phaser.GameObjects.Sprite, receivedPokemonTintSprite: Phaser.GameObjects.Sprite, receivedPokeballSprite: Phaser.GameObjects.Sprite, receivedPbAtlasKey: string) {
|
||||
return new Promise<void>(resolve => {
|
||||
const tradeContainer = scene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeContainer = globalScene.fieldUI.getByName("Trade Background") as Phaser.GameObjects.Container;
|
||||
const tradeBaseBg = tradeContainer.getByName("Trade Background Image") as Phaser.GameObjects.Image;
|
||||
|
||||
receivedPokemonSprite.setVisible(false);
|
||||
|
@ -812,7 +817,7 @@ function doTradeReceivedSequence(scene: BattleScene, receivedPokemon: PlayerPoke
|
|||
// Received pokemon sparkles
|
||||
let pokemonShinySparkle: Phaser.GameObjects.Sprite;
|
||||
if (receivedPokemon.shiny) {
|
||||
pokemonShinySparkle = scene.add.sprite(receivedPokemonSprite.x, receivedPokemonSprite.y, "shiny");
|
||||
pokemonShinySparkle = globalScene.add.sprite(receivedPokemonSprite.x, receivedPokemonSprite.y, "shiny");
|
||||
pokemonShinySparkle.setVisible(false);
|
||||
tradeContainer.add(pokemonShinySparkle);
|
||||
}
|
||||
|
@ -820,19 +825,19 @@ function doTradeReceivedSequence(scene: BattleScene, receivedPokemon: PlayerPoke
|
|||
const BASE_ANIM_DURATION = 1000;
|
||||
|
||||
// Pokeball falls to the screen
|
||||
scene.playSound("se/pb_throw");
|
||||
scene.tweens.add({
|
||||
globalScene.playSound("se/pb_throw");
|
||||
globalScene.tweens.add({
|
||||
targets: receivedPokeballSprite,
|
||||
y: "+=100",
|
||||
ease: "Cubic.easeInOut",
|
||||
duration: BASE_ANIM_DURATION,
|
||||
onComplete: () => {
|
||||
scene.playSound("se/pb_bounce_1");
|
||||
scene.time.delayedCall(100, () => scene.playSound("se/pb_bounce_1"));
|
||||
globalScene.playSound("se/pb_bounce_1");
|
||||
globalScene.time.delayedCall(100, () => globalScene.playSound("se/pb_bounce_1"));
|
||||
|
||||
scene.time.delayedCall(2000, () => {
|
||||
scene.playSound("se/pb_rel");
|
||||
scene.fadeOutBgm(500, false);
|
||||
globalScene.time.delayedCall(2000, () => {
|
||||
globalScene.playSound("se/pb_rel");
|
||||
globalScene.fadeOutBgm(500, false);
|
||||
receivedPokemon.cry();
|
||||
receivedPokemonTintSprite.scale = 0.25;
|
||||
receivedPokemonTintSprite.alpha = 1;
|
||||
|
@ -841,14 +846,14 @@ function doTradeReceivedSequence(scene: BattleScene, receivedPokemon: PlayerPoke
|
|||
receivedPokemonTintSprite.alpha = 1;
|
||||
receivedPokemonTintSprite.setVisible(true);
|
||||
receivedPokeballSprite.setTexture("pb", `${receivedPbAtlasKey}_opening`);
|
||||
scene.time.delayedCall(17, () => receivedPokeballSprite.setTexture("pb", `${receivedPbAtlasKey}_open`));
|
||||
scene.tweens.add({
|
||||
globalScene.time.delayedCall(17, () => receivedPokeballSprite.setTexture("pb", `${receivedPbAtlasKey}_open`));
|
||||
globalScene.tweens.add({
|
||||
targets: receivedPokemonSprite,
|
||||
duration: 250,
|
||||
ease: "Sine.easeOut",
|
||||
scale: 1
|
||||
});
|
||||
scene.tweens.add({
|
||||
globalScene.tweens.add({
|
||||
targets: receivedPokemonTintSprite,
|
||||
duration: 250,
|
||||
ease: "Sine.easeOut",
|
||||
|
@ -856,12 +861,12 @@ function doTradeReceivedSequence(scene: BattleScene, receivedPokemon: PlayerPoke
|
|||
alpha: 0,
|
||||
onComplete: () => {
|
||||
if (receivedPokemon.shiny) {
|
||||
scene.time.delayedCall(500, () => {
|
||||
doShinySparkleAnim(scene, pokemonShinySparkle, receivedPokemon.variant);
|
||||
globalScene.time.delayedCall(500, () => {
|
||||
doShinySparkleAnim(pokemonShinySparkle, receivedPokemon.variant);
|
||||
});
|
||||
}
|
||||
receivedPokeballSprite.destroy();
|
||||
scene.time.delayedCall(2000, () => resolve());
|
||||
globalScene.time.delayedCall(2000, () => resolve());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,8 +2,9 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
|
|||
import { Moves } from "#app/enums/moves";
|
||||
import { Species } from "#app/enums/species";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { leaveEncounterWithoutBattle, setEncounterExp } from "../utils/encounter-phase-utils";
|
||||
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
|
@ -41,8 +42,8 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
},
|
||||
])
|
||||
.withIntroDialogue([{ text: `${namespace}:intro` }])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
encounter.setDialogueToken("damagePercentage", String(DAMAGE_PERCENTAGE));
|
||||
encounter.setDialogueToken("option1RequiredMove", new PokemonMove(OPTION_1_REQUIRED_MOVE).getName());
|
||||
|
@ -70,7 +71,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => handlePokemonGuidingYouPhase(scene))
|
||||
.withOptionPhase(async () => handlePokemonGuidingYouPhase())
|
||||
.build()
|
||||
)
|
||||
.withOption(
|
||||
|
@ -89,7 +90,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
},
|
||||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => handlePokemonGuidingYouPhase(scene))
|
||||
.withOptionPhase(async () => handlePokemonGuidingYouPhase())
|
||||
.build()
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -103,16 +104,16 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const allowedPokemon = scene.getPlayerParty().filter((p) => p.isAllowedInBattle());
|
||||
async () => {
|
||||
const allowedPokemon = globalScene.getPlayerParty().filter((p) => p.isAllowedInBattle());
|
||||
|
||||
for (const pkm of allowedPokemon) {
|
||||
const percentage = DAMAGE_PERCENTAGE / 100;
|
||||
const damage = Math.floor(pkm.getMaxHp() * percentage);
|
||||
applyDamageToPokemon(scene, pkm, damage);
|
||||
applyDamageToPokemon(pkm, damage);
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
leaveEncounterWithoutBattle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -126,19 +127,17 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
|
||||
/**
|
||||
* Generic handler for using a guiding pokemon to guide you back.
|
||||
*
|
||||
* @param scene Battle scene
|
||||
*/
|
||||
function handlePokemonGuidingYouPhase(scene: BattleScene) {
|
||||
function handlePokemonGuidingYouPhase() {
|
||||
const laprasSpecies = getPokemonSpecies(Species.LAPRAS);
|
||||
const { mysteryEncounter } = scene.currentBattle;
|
||||
const { mysteryEncounter } = globalScene.currentBattle;
|
||||
|
||||
if (mysteryEncounter?.selectedOption?.primaryPokemon?.id) {
|
||||
setEncounterExp(scene, mysteryEncounter.selectedOption.primaryPokemon.id, laprasSpecies.baseExp, true);
|
||||
setEncounterExp(mysteryEncounter.selectedOption.primaryPokemon.id, laprasSpecies.baseExp, true);
|
||||
} else {
|
||||
console.warn("Lost at sea: No guide pokemon found but pokemon guides player. huh!?");
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
leaveEncounterWithoutBattle();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type {
|
||||
EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import {
|
||||
EnemyPartyConfig,
|
||||
initBattleWithEnemyConfig,
|
||||
setEncounterRewards,
|
||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
|
@ -13,9 +14,10 @@ import { ModifierTier } from "#app/modifier/modifier-tier";
|
|||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import * as Utils from "#app/utils";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
|
||||
|
@ -37,12 +39,12 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Calculates what trainers are available for battle in the encounter
|
||||
|
||||
// Normal difficulty trainer is randomly pulled from biome
|
||||
const normalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
|
||||
const normalTrainerType = globalScene.arena.randomTrainerType(globalScene.currentBattle.waveIndex);
|
||||
const normalConfig = trainerConfigs[normalTrainerType].clone();
|
||||
let female = false;
|
||||
if (normalConfig.hasGenders) {
|
||||
|
@ -57,16 +59,16 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
// Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
|
||||
// Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100
|
||||
let retries = 0;
|
||||
let hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
|
||||
let hardTrainerType = globalScene.arena.randomTrainerType(globalScene.currentBattle.waveIndex);
|
||||
while (retries < 5 && hardTrainerType === normalTrainerType) {
|
||||
// Will try to use a different trainer from the normal trainer type
|
||||
hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
|
||||
hardTrainerType = globalScene.arena.randomTrainerType(globalScene.currentBattle.waveIndex);
|
||||
retries++;
|
||||
}
|
||||
const hardTemplate = new TrainerPartyCompoundTemplate(
|
||||
new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true),
|
||||
new TrainerPartyTemplate(
|
||||
Math.min(Math.ceil(scene.currentBattle.waveIndex / 20), 5),
|
||||
Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 20), 5),
|
||||
PartyMemberStrength.AVERAGE,
|
||||
false,
|
||||
true
|
||||
|
@ -87,8 +89,8 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
|
||||
// Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome
|
||||
// They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons
|
||||
const brutalTrainerType = scene.arena.randomTrainerType(
|
||||
scene.currentBattle.waveIndex,
|
||||
const brutalTrainerType = globalScene.arena.randomTrainerType(
|
||||
globalScene.currentBattle.waveIndex,
|
||||
true
|
||||
);
|
||||
const e4Template = trainerPartyTemplates.ELITE_FOUR;
|
||||
|
@ -145,18 +147,18 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Spawn standard trainer battle with memory mushroom reward
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM ], fillRemaining: true });
|
||||
setEncounterRewards({ guaranteedModifierTypeFuncs: [ modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM ], fillRemaining: true });
|
||||
|
||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||
let initBattlePromise: Promise<void>;
|
||||
scene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(scene, config);
|
||||
}, scene.currentBattle.waveIndex * 10);
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(config);
|
||||
}, globalScene.currentBattle.waveIndex * 10);
|
||||
await initBattlePromise!;
|
||||
}
|
||||
)
|
||||
|
@ -170,18 +172,18 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Spawn hard fight
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: true });
|
||||
setEncounterRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: true });
|
||||
|
||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||
let initBattlePromise: Promise<void>;
|
||||
scene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(scene, config);
|
||||
}, scene.currentBattle.waveIndex * 100);
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(config);
|
||||
}, globalScene.currentBattle.waveIndex * 100);
|
||||
await initBattlePromise!;
|
||||
}
|
||||
)
|
||||
|
@ -195,21 +197,21 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
// Spawn brutal fight
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2];
|
||||
|
||||
// To avoid player level snowballing from picking this option
|
||||
encounter.expMultiplier = 0.9;
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
|
||||
setEncounterRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
|
||||
|
||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||
let initBattlePromise: Promise<void>;
|
||||
scene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(scene, config);
|
||||
}, scene.currentBattle.waveIndex * 1000);
|
||||
globalScene.executeWithSeedOffset(() => {
|
||||
initBattlePromise = initBattleWithEnemyConfig(config);
|
||||
}, globalScene.currentBattle.waveIndex * 1000);
|
||||
await initBattlePromise!;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { getHighestLevelPlayerPokemon, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
|
@ -66,8 +68,8 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withOnInit(() => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const config: EnemyPartyConfig = {
|
||||
|
@ -106,9 +108,9 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
.withPreOptionPhase(async () => {
|
||||
// Play animation
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const introVisuals = encounter.introVisuals!;
|
||||
|
||||
// Determine roll first
|
||||
|
@ -128,13 +130,13 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
introVisuals.spriteConfigs[1].disableAnimation = false;
|
||||
introVisuals.playAnim();
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Open the chest
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const roll = encounter.misc.roll;
|
||||
if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT) {
|
||||
// Choose between 2 COMMON / 2 GREAT tier items (20%)
|
||||
setEncounterRewards(scene, {
|
||||
setEncounterRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.COMMON,
|
||||
ModifierTier.COMMON,
|
||||
|
@ -143,11 +145,11 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
],
|
||||
});
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}:option.1.normal`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
queueEncounterMessage(`${namespace}:option.1.normal`);
|
||||
leaveEncounterWithoutBattle();
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
|
||||
// Choose between 3 ULTRA tier items (30%)
|
||||
setEncounterRewards(scene, {
|
||||
setEncounterRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
|
@ -155,39 +157,39 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
],
|
||||
});
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}:option.1.good`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
queueEncounterMessage(`${namespace}:option.1.good`);
|
||||
leaveEncounterWithoutBattle();
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
|
||||
// Choose between 2 ROGUE tier items (10%)
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE ]});
|
||||
setEncounterRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE ]});
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}:option.1.great`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
queueEncounterMessage(`${namespace}:option.1.great`);
|
||||
leaveEncounterWithoutBattle();
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) {
|
||||
// Choose 1 MASTER tier item (5%)
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.MASTER ]});
|
||||
setEncounterRewards({ guaranteedModifierTiers: [ ModifierTier.MASTER ]});
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}:option.1.amazing`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
queueEncounterMessage(`${namespace}:option.1.amazing`);
|
||||
leaveEncounterWithoutBattle();
|
||||
} else {
|
||||
// Your highest level unfainted Pokemon gets OHKO. Start battle against a Gimmighoul (35%)
|
||||
const highestLevelPokemon = getHighestLevelPlayerPokemon(scene, true, false);
|
||||
koPlayerPokemon(scene, highestLevelPokemon);
|
||||
const highestLevelPokemon = getHighestLevelPlayerPokemon(true, false);
|
||||
koPlayerPokemon(highestLevelPokemon);
|
||||
|
||||
encounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
|
||||
await showEncounterText(scene, `${namespace}:option.1.bad`);
|
||||
await showEncounterText(`${namespace}:option.1.bad`);
|
||||
|
||||
// Handle game over edge case
|
||||
const allowedPokemon = scene.getPokemonAllowedInBattle();
|
||||
const allowedPokemon = globalScene.getPokemonAllowedInBattle();
|
||||
if (allowedPokemon.length === 0) {
|
||||
// If there are no longer any legal pokemon in the party, game over.
|
||||
scene.clearPhaseQueue();
|
||||
scene.unshiftPhase(new GameOverPhase(scene));
|
||||
globalScene.clearPhaseQueue();
|
||||
globalScene.unshiftPhase(new GameOverPhase());
|
||||
} else {
|
||||
// Show which Pokemon was KOed, then start battle against Gimmighoul
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
|
||||
await transitionMysteryEncounterIntroVisuals(true, true, 500);
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -203,9 +205,9 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
async () => {
|
||||
// Leave encounter with no rewards or exp
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
leaveEncounterWithoutBattle(true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals, updatePlayerMoney } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
@ -10,7 +11,8 @@ import { Stat } from "#enums/stat";
|
|||
import { CHARMING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import i18next from "i18next";
|
||||
import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
|
||||
|
@ -52,20 +54,20 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
text: `${namespace}:intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
.withOnInit(() => {
|
||||
// Load sfx
|
||||
scene.loadSe("PRSFX- Horn Drill1", "battle_anims", "PRSFX- Horn Drill1.wav");
|
||||
scene.loadSe("PRSFX- Horn Drill3", "battle_anims", "PRSFX- Horn Drill3.wav");
|
||||
scene.loadSe("PRSFX- Guillotine2", "battle_anims", "PRSFX- Guillotine2.wav");
|
||||
scene.loadSe("PRSFX- Heavy Slam2", "battle_anims", "PRSFX- Heavy Slam2.wav");
|
||||
globalScene.loadSe("PRSFX- Horn Drill1", "battle_anims", "PRSFX- Horn Drill1.wav");
|
||||
globalScene.loadSe("PRSFX- Horn Drill3", "battle_anims", "PRSFX- Horn Drill3.wav");
|
||||
globalScene.loadSe("PRSFX- Guillotine2", "battle_anims", "PRSFX- Guillotine2.wav");
|
||||
globalScene.loadSe("PRSFX- Heavy Slam2", "battle_anims", "PRSFX- Heavy Slam2.wav");
|
||||
|
||||
scene.loadSe("PRSFX- Agility", "battle_anims", "PRSFX- Agility.wav");
|
||||
scene.loadSe("PRSFX- Extremespeed1", "battle_anims", "PRSFX- Extremespeed1.wav");
|
||||
scene.loadSe("PRSFX- Accelerock1", "battle_anims", "PRSFX- Accelerock1.wav");
|
||||
globalScene.loadSe("PRSFX- Agility", "battle_anims", "PRSFX- Agility.wav");
|
||||
globalScene.loadSe("PRSFX- Extremespeed1", "battle_anims", "PRSFX- Extremespeed1.wav");
|
||||
globalScene.loadSe("PRSFX- Accelerock1", "battle_anims", "PRSFX- Accelerock1.wav");
|
||||
|
||||
scene.loadSe("PRSFX- Captivate", "battle_anims", "PRSFX- Captivate.wav");
|
||||
scene.loadSe("PRSFX- Attract2", "battle_anims", "PRSFX- Attract2.wav");
|
||||
scene.loadSe("PRSFX- Aurora Veil2", "battle_anims", "PRSFX- Aurora Veil2.wav");
|
||||
globalScene.loadSe("PRSFX- Captivate", "battle_anims", "PRSFX- Captivate.wav");
|
||||
globalScene.loadSe("PRSFX- Attract2", "battle_anims", "PRSFX- Attract2.wav");
|
||||
globalScene.loadSe("PRSFX- Aurora Veil2", "battle_anims", "PRSFX- Aurora Veil2.wav");
|
||||
|
||||
return true;
|
||||
})
|
||||
|
@ -84,8 +86,8 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
}
|
||||
]
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
|
@ -109,41 +111,41 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
}
|
||||
});
|
||||
|
||||
setEncounterExp(scene, pokemon.id, 100);
|
||||
setEncounterExp(pokemon.id, 100);
|
||||
|
||||
// Hide intro visuals
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, false);
|
||||
transitionMysteryEncounterIntroVisuals(true, false);
|
||||
// Play sfx for "working"
|
||||
doDeliverySfx(scene);
|
||||
doDeliverySfx();
|
||||
};
|
||||
|
||||
// Only Pokemon non-KOd pokemon can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, `${namespace}:invalid_selection`);
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick Deliveries
|
||||
// Bring visuals back in
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
await transitionMysteryEncounterIntroVisuals(false, false);
|
||||
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
const moneyMultiplier = globalScene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
|
||||
// Give money and do dialogue
|
||||
if (moneyMultiplier > 2.5) {
|
||||
await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
await showEncounterDialogue(`${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
} else {
|
||||
await showEncounterDialogue(scene, `${namespace}:job_complete_bad`, `${namespace}:speaker`);
|
||||
await showEncounterDialogue(`${namespace}:job_complete_bad`, `${namespace}:speaker`);
|
||||
}
|
||||
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
|
||||
updatePlayerMoney(scene, moneyChange, true, false);
|
||||
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(scene, `${namespace}:pokemon_tired`);
|
||||
const moneyChange = globalScene.getWaveMoneyAmount(moneyMultiplier);
|
||||
updatePlayerMoney(moneyChange, true, false);
|
||||
await showEncounterText(i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(`${namespace}:pokemon_tired`);
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -158,8 +160,8 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
}
|
||||
]
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
|
@ -186,41 +188,41 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
}
|
||||
});
|
||||
|
||||
setEncounterExp(scene, pokemon.id, 100);
|
||||
setEncounterExp(pokemon.id, 100);
|
||||
|
||||
// Hide intro visuals
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, false);
|
||||
transitionMysteryEncounterIntroVisuals(true, false);
|
||||
// Play sfx for "working"
|
||||
doStrongWorkSfx(scene);
|
||||
doStrongWorkSfx();
|
||||
};
|
||||
|
||||
// Only Pokemon non-KOd pokemon can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, scene, `${namespace}:invalid_selection`);
|
||||
return isPokemonValidForEncounterOptionSelection(pokemon, `${namespace}:invalid_selection`);
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
return selectPokemonForOption(onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Pick Move Warehouse items
|
||||
// Bring visuals back in
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
await transitionMysteryEncounterIntroVisuals(false, false);
|
||||
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
const moneyMultiplier = globalScene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
|
||||
// Give money and do dialogue
|
||||
if (moneyMultiplier > 2.5) {
|
||||
await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
await showEncounterDialogue(`${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
} else {
|
||||
await showEncounterDialogue(scene, `${namespace}:job_complete_bad`, `${namespace}:speaker`);
|
||||
await showEncounterDialogue(`${namespace}:job_complete_bad`, `${namespace}:speaker`);
|
||||
}
|
||||
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
|
||||
updatePlayerMoney(scene, moneyChange, true, false);
|
||||
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(scene, `${namespace}:pokemon_tired`);
|
||||
const moneyChange = globalScene.getWaveMoneyAmount(moneyMultiplier);
|
||||
updatePlayerMoney(moneyChange, true, false);
|
||||
await showEncounterText(i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(`${namespace}:pokemon_tired`);
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -238,8 +240,8 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
.withPreOptionPhase(async () => {
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const selectedPokemon = encounter.selectedOption?.primaryPokemon!;
|
||||
encounter.setDialogueToken("selectedPokemon", selectedPokemon.getNameToRender());
|
||||
|
||||
|
@ -251,28 +253,28 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
}
|
||||
});
|
||||
|
||||
setEncounterExp(scene, selectedPokemon.id, 100);
|
||||
setEncounterExp(selectedPokemon.id, 100);
|
||||
|
||||
// Hide intro visuals
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, false);
|
||||
transitionMysteryEncounterIntroVisuals(true, false);
|
||||
// Play sfx for "working"
|
||||
doSalesSfx(scene);
|
||||
doSalesSfx();
|
||||
return true;
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
.withOptionPhase(async () => {
|
||||
// Assist with Sales
|
||||
// Bring visuals back in
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
await transitionMysteryEncounterIntroVisuals(false, false);
|
||||
|
||||
// Give money and do dialogue
|
||||
await showEncounterDialogue(scene, `${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
const moneyChange = scene.getWaveMoneyAmount(2.5);
|
||||
updatePlayerMoney(scene, moneyChange, true, false);
|
||||
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(scene, `${namespace}:pokemon_tired`);
|
||||
await showEncounterDialogue(`${namespace}:job_complete_good`, `${namespace}:speaker`);
|
||||
const moneyChange = globalScene.getWaveMoneyAmount(2.5);
|
||||
updatePlayerMoney(moneyChange, true, false);
|
||||
await showEncounterText(i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
|
||||
await showEncounterText(`${namespace}:pokemon_tired`);
|
||||
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
setEncounterRewards({ fillRemaining: true });
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build()
|
||||
)
|
||||
|
@ -284,51 +286,51 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
])
|
||||
.build();
|
||||
|
||||
function doStrongWorkSfx(scene: BattleScene) {
|
||||
scene.playSound("battle_anims/PRSFX- Horn Drill1");
|
||||
scene.playSound("battle_anims/PRSFX- Horn Drill1");
|
||||
function doStrongWorkSfx() {
|
||||
globalScene.playSound("battle_anims/PRSFX- Horn Drill1");
|
||||
globalScene.playSound("battle_anims/PRSFX- Horn Drill1");
|
||||
|
||||
scene.time.delayedCall(1000, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Guillotine2");
|
||||
globalScene.time.delayedCall(1000, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Guillotine2");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(2000, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Heavy Slam2");
|
||||
globalScene.time.delayedCall(2000, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Heavy Slam2");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(2500, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Guillotine2");
|
||||
globalScene.time.delayedCall(2500, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Guillotine2");
|
||||
});
|
||||
}
|
||||
|
||||
function doDeliverySfx(scene: BattleScene) {
|
||||
scene.playSound("battle_anims/PRSFX- Accelerock1");
|
||||
function doDeliverySfx() {
|
||||
globalScene.playSound("battle_anims/PRSFX- Accelerock1");
|
||||
|
||||
scene.time.delayedCall(1500, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Extremespeed1");
|
||||
globalScene.time.delayedCall(1500, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Extremespeed1");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(2000, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Extremespeed1");
|
||||
globalScene.time.delayedCall(2000, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Extremespeed1");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(2250, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Agility");
|
||||
globalScene.time.delayedCall(2250, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Agility");
|
||||
});
|
||||
}
|
||||
|
||||
function doSalesSfx(scene: BattleScene) {
|
||||
scene.playSound("battle_anims/PRSFX- Captivate");
|
||||
function doSalesSfx() {
|
||||
globalScene.playSound("battle_anims/PRSFX- Captivate");
|
||||
|
||||
scene.time.delayedCall(1500, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Attract2");
|
||||
globalScene.time.delayedCall(1500, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Attract2");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(2000, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Aurora Veil2");
|
||||
globalScene.time.delayedCall(2000, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Aurora Veil2");
|
||||
});
|
||||
|
||||
scene.time.delayedCall(3000, () => {
|
||||
scene.playSound("battle_anims/PRSFX- Attract2");
|
||||
globalScene.time.delayedCall(3000, () => {
|
||||
globalScene.playSound("battle_anims/PRSFX- Attract2");
|
||||
});
|
||||
}
|
||||
|
|