diff --git a/public/images/items.json b/public/images/items.json index c347790b92f..b318f79b0a0 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -4,8 +4,8 @@ "image": "items.png", "format": "RGBA8888", "size": { - "w": 425, - "h": 425 + "w": 428, + "h": 428 }, "scale": 1, "frames": [ @@ -387,6 +387,27 @@ "h": 28 } }, + { + "filename": "mega_bracelet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 16 + }, + "frame": { + "x": 0, + "y": 412, + "w": 20, + "h": 16 + } + }, { "filename": "ability_charm", "rotated": false, @@ -619,7 +640,7 @@ } }, { - "filename": "elixir", + "filename": "catching_charm", "rotated": false, "trimmed": true, "sourceSize": { @@ -627,15 +648,15 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 5, "y": 4, - "w": 18, + "w": 21, "h": 24 }, "frame": { "x": 407, "y": 0, - "w": 18, + "w": 21, "h": 24 } }, @@ -892,7 +913,7 @@ } }, { - "filename": "coupon", + "filename": "exp_balance", "rotated": false, "trimmed": true, "sourceSize": { @@ -901,36 +922,15 @@ }, "spriteSourceSize": { "x": 4, - "y": 7, - "w": 23, - "h": 19 + "y": 5, + "w": 24, + "h": 22 }, "frame": { "x": 22, "y": 406, - "w": 23, - "h": 19 - } - }, - { - "filename": "golden_mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 45, - "y": 406, - "w": 23, - "h": 19 + "w": 24, + "h": 22 } }, { @@ -955,7 +955,7 @@ } }, { - "filename": "mega_bracelet", + "filename": "relic_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -963,20 +963,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, + "x": 7, + "y": 9, + "w": 17, "h": 16 }, "frame": { "x": 28, "y": 70, - "w": 20, + "w": 17, "h": 16 } }, { - "filename": "calcium", + "filename": "abomasite", "rotated": false, "trimmed": true, "sourceSize": { @@ -985,57 +985,15 @@ }, "spriteSourceSize": { "x": 8, - "y": 4, + "y": 8, "w": 16, - "h": 24 + "h": 16 }, "frame": { - "x": 39, - "y": 86, + "x": 45, + "y": 70, "w": 16, - "h": 24 - } - }, - { - "filename": "carbos", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 39, - "y": 110, - "w": 16, - "h": 24 - } - }, - { - "filename": "catching_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 39, - "y": 134, - "w": 21, - "h": 24 + "h": 16 } }, { @@ -1054,7 +1012,7 @@ }, "frame": { "x": 39, - "y": 158, + "y": 86, "w": 24, "h": 24 } @@ -1075,7 +1033,7 @@ }, "frame": { "x": 39, - "y": 182, + "y": 110, "w": 24, "h": 24 } @@ -1094,6 +1052,69 @@ "w": 24, "h": 24 }, + "frame": { + "x": 39, + "y": 134, + "w": 24, + "h": 24 + } + }, + { + "filename": "golden_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 39, + "y": 158, + "w": 24, + "h": 24 + } + }, + { + "filename": "gracidea", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 39, + "y": 182, + "w": 24, + "h": 24 + } + }, + { + "filename": "grip_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, "frame": { "x": 44, "y": 206, @@ -1102,7 +1123,7 @@ } }, { - "filename": "golden_punch", + "filename": "icicle_plate", "rotated": false, "trimmed": true, "sourceSize": { @@ -1123,7 +1144,7 @@ } }, { - "filename": "gracidea", + "filename": "insect_plate", "rotated": false, "trimmed": true, "sourceSize": { @@ -1143,69 +1164,6 @@ "h": 24 } }, - { - "filename": "grip_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 46, - "y": 278, - "w": 24, - "h": 24 - } - }, - { - "filename": "icicle_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 46, - "y": 302, - "w": 24, - "h": 24 - } - }, - { - "filename": "insect_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 46, - "y": 326, - "w": 24, - "h": 24 - } - }, { "filename": "iron_plate", "rotated": false, @@ -1222,7 +1180,7 @@ }, "frame": { "x": 46, - "y": 350, + "y": 278, "w": 24, "h": 24 } @@ -1243,137 +1201,11 @@ }, "frame": { "x": 46, - "y": 374, + "y": 302, "w": 24, "h": 24 } }, - { - "filename": "abomasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 48, - "y": 70, - "w": 16, - "h": 16 - } - }, - { - "filename": "ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 55, - "y": 86, - "w": 18, - "h": 24 - } - }, - { - "filename": "full_restore", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 55, - "y": 110, - "w": 18, - "h": 24 - } - }, - { - "filename": "hp_up", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 60, - "y": 134, - "w": 16, - "h": 24 - } - }, - { - "filename": "iron", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 63, - "y": 158, - "w": 16, - "h": 24 - } - }, - { - "filename": "kings_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 63, - "y": 182, - "w": 23, - "h": 24 - } - }, { "filename": "lucky_punch_great", "rotated": false, @@ -1389,8 +1221,8 @@ "h": 24 }, "frame": { - "x": 68, - "y": 206, + "x": 46, + "y": 326, "w": 24, "h": 24 } @@ -1410,8 +1242,8 @@ "h": 24 }, "frame": { - "x": 68, - "y": 230, + "x": 46, + "y": 350, "w": 24, "h": 24 } @@ -1431,8 +1263,8 @@ "h": 24 }, "frame": { - "x": 69, - "y": 254, + "x": 46, + "y": 374, "w": 24, "h": 24 } @@ -1452,112 +1284,7 @@ "h": 24 }, "frame": { - "x": 70, - "y": 278, - "w": 24, - "h": 24 - } - }, - { - "filename": "meadow_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 70, - "y": 302, - "w": 24, - "h": 24 - } - }, - { - "filename": "mind_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 70, - "y": 326, - "w": 24, - "h": 24 - } - }, - { - "filename": "muscle_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 70, - "y": 350, - "w": 24, - "h": 24 - } - }, - { - "filename": "pixie_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 70, - "y": 374, - "w": 24, - "h": 24 - } - }, - { - "filename": "salac_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 68, + "x": 46, "y": 398, "w": 24, "h": 24 @@ -1585,7 +1312,7 @@ } }, { - "filename": "lure", + "filename": "calcium", "rotated": false, "trimmed": true, "sourceSize": { @@ -1595,39 +1322,18 @@ "spriteSourceSize": { "x": 8, "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 92, - "y": 398, - "w": 17, - "h": 24 - } - }, - { - "filename": "max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, + "w": 16, "h": 24 }, "frame": { "x": 59, "y": 27, - "w": 18, + "w": 16, "h": 24 } }, { - "filename": "scanner", + "filename": "meadow_plate", "rotated": false, "trimmed": true, "sourceSize": { @@ -1641,14 +1347,14 @@ "h": 24 }, "frame": { - "x": 77, + "x": 75, "y": 26, "w": 24, "h": 24 } }, { - "filename": "silk_scarf", + "filename": "mind_plate", "rotated": false, "trimmed": true, "sourceSize": { @@ -1662,12 +1368,33 @@ "h": 24 }, "frame": { - "x": 101, + "x": 99, "y": 26, "w": 24, "h": 24 } }, + { + "filename": "revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 12, + "h": 17 + }, + "frame": { + "x": 123, + "y": 26, + "w": 12, + "h": 17 + } + }, { "filename": "big_mushroom", "rotated": false, @@ -1732,7 +1459,7 @@ } }, { - "filename": "sky_plate", + "filename": "absolite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1740,20 +1467,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 61, + "y": 70, + "w": 16, + "h": 16 + } + }, + { + "filename": "carbos", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, "y": 4, - "w": 24, + "w": 16, "h": 24 }, "frame": { - "x": 125, - "y": 36, - "w": 24, + "x": 63, + "y": 86, + "w": 16, "h": 24 } }, { - "filename": "choice_specs", + "filename": "elixir", "rotated": false, "trimmed": true, "sourceSize": { @@ -1761,16 +1509,100 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 + "x": 7, + "y": 4, + "w": 18, + "h": 24 }, "frame": { - "x": 125, - "y": 60, - "w": 24, - "h": 18 + "x": 63, + "y": 110, + "w": 18, + "h": 24 + } + }, + { + "filename": "ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 63, + "y": 134, + "w": 18, + "h": 24 + } + }, + { + "filename": "full_restore", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 63, + "y": 158, + "w": 18, + "h": 24 + } + }, + { + "filename": "kings_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 63, + "y": 182, + "w": 23, + "h": 24 + } + }, + { + "filename": "max_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 68, + "y": 206, + "w": 18, + "h": 24 } }, { @@ -1788,14 +1620,140 @@ "h": 24 }, "frame": { - "x": 149, - "y": 36, + "x": 68, + "y": 230, "w": 18, "h": 24 } }, { - "filename": "adamant_crystal", + "filename": "lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 69, + "y": 254, + "w": 17, + "h": 24 + } + }, + { + "filename": "hp_up", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 70, + "y": 278, + "w": 16, + "h": 24 + } + }, + { + "filename": "iron", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 70, + "y": 302, + "w": 16, + "h": 24 + } + }, + { + "filename": "max_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 70, + "y": 326, + "w": 17, + "h": 24 + } + }, + { + "filename": "max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 70, + "y": 350, + "w": 18, + "h": 24 + } + }, + { + "filename": "max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 24 + }, + "frame": { + "x": 70, + "y": 374, + "w": 22, + "h": 24 + } + }, + { + "filename": "muscle_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -1804,15 +1762,183 @@ }, "spriteSourceSize": { "x": 4, - "y": 6, - "w": 23, - "h": 21 + "y": 4, + "w": 24, + "h": 24 }, "frame": { - "x": 149, - "y": 60, + "x": 70, + "y": 398, + "w": 24, + "h": 24 + } + }, + { + "filename": "pixie_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 79, + "y": 73, + "w": 24, + "h": 24 + } + }, + { + "filename": "reveal_glass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, "w": 23, - "h": 21 + "h": 24 + }, + "frame": { + "x": 103, + "y": 73, + "w": 23, + "h": 24 + } + }, + { + "filename": "salac_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 81, + "y": 97, + "w": 24, + "h": 24 + } + }, + { + "filename": "scanner", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 81, + "y": 121, + "w": 24, + "h": 24 + } + }, + { + "filename": "silk_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 81, + "y": 145, + "w": 24, + "h": 24 + } + }, + { + "filename": "oval_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 105, + "y": 97, + "w": 21, + "h": 24 + } + }, + { + "filename": "shiny_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 105, + "y": 121, + "w": 21, + "h": 24 + } + }, + { + "filename": "sky_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 105, + "y": 145, + "w": 24, + "h": 24 } }, { @@ -1830,8 +1956,8 @@ "h": 24 }, "frame": { - "x": 167, - "y": 21, + "x": 86, + "y": 169, "w": 24, "h": 24 } @@ -1851,8 +1977,8 @@ "h": 24 }, "frame": { - "x": 191, - "y": 21, + "x": 86, + "y": 193, "w": 24, "h": 24 } @@ -1872,8 +1998,8 @@ "h": 24 }, "frame": { - "x": 215, - "y": 21, + "x": 86, + "y": 217, "w": 24, "h": 24 } @@ -1893,8 +2019,8 @@ "h": 24 }, "frame": { - "x": 239, - "y": 21, + "x": 86, + "y": 241, "w": 24, "h": 24 } @@ -1914,8 +2040,8 @@ "h": 24 }, "frame": { - "x": 263, - "y": 21, + "x": 86, + "y": 265, "w": 24, "h": 24 } @@ -1935,14 +2061,14 @@ "h": 24 }, "frame": { - "x": 287, - "y": 21, + "x": 86, + "y": 289, "w": 24, "h": 24 } }, { - "filename": "silver_powder", + "filename": "red_orb", "rotated": false, "trimmed": true, "sourceSize": { @@ -1950,20 +2076,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 11, - "w": 24, - "h": 15 + "x": 6, + "y": 4, + "w": 20, + "h": 24 }, "frame": { - "x": 167, - "y": 45, - "w": 24, - "h": 15 + "x": 110, + "y": 169, + "w": 20, + "h": 24 } }, { - "filename": "max_revive", + "filename": "black_belt", "rotated": false, "trimmed": true, "sourceSize": { @@ -1974,13 +2100,34 @@ "x": 5, "y": 4, "w": 22, - "h": 24 + "h": 23 }, "frame": { - "x": 311, - "y": 21, + "x": 110, + "y": 193, "w": 22, - "h": 24 + "h": 23 + } + }, + { + "filename": "bug_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 110, + "y": 216, + "w": 22, + "h": 23 } }, { @@ -1998,8 +2145,8 @@ "h": 23 }, "frame": { - "x": 333, - "y": 20, + "x": 110, + "y": 239, "w": 24, "h": 23 } @@ -2019,8 +2166,8 @@ "h": 23 }, "frame": { - "x": 357, - "y": 20, + "x": 110, + "y": 262, "w": 24, "h": 23 } @@ -2040,281 +2187,8 @@ "h": 23 }, "frame": { - "x": 381, - "y": 20, - "w": 24, - "h": 23 - } - }, - { - "filename": "red_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 20, - "h": 24 - }, - "frame": { - "x": 405, - "y": 24, - "w": 20, - "h": 24 - } - }, - { - "filename": "amulet_coin", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 172, - "y": 60, - "w": 23, - "h": 21 - } - }, - { - "filename": "candy_overlay", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 12, - "w": 16, - "h": 15 - }, - "frame": { - "x": 191, - "y": 45, - "w": 16, - "h": 15 - } - }, - { - "filename": "dragon_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 207, - "y": 45, - "w": 24, - "h": 18 - } - }, - { - "filename": "exp_balance", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 231, - "y": 45, - "w": 24, - "h": 22 - } - }, - { - "filename": "exp_share", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 255, - "y": 45, - "w": 24, - "h": 22 - } - }, - { - "filename": "leppa_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 279, - "y": 45, - "w": 24, - "h": 23 - } - }, - { - "filename": "scope_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 303, - "y": 45, - "w": 24, - "h": 23 - } - }, - { - "filename": "revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 10, - "y": 8, - "w": 12, - "h": 17 - }, - "frame": { - "x": 195, - "y": 60, - "w": 12, - "h": 17 - } - }, - { - "filename": "icy_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 207, - "y": 63, - "w": 24, - "h": 20 - } - }, - { - "filename": "metal_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 231, - "y": 67, - "w": 24, - "h": 20 - } - }, - { - "filename": "peat_block", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 255, - "y": 67, - "w": 24, - "h": 22 - } - }, - { - "filename": "twisted_spoon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 279, - "y": 68, + "x": 110, + "y": 285, "w": 24, "h": 23 } @@ -2334,77 +2208,14 @@ "h": 23 }, "frame": { - "x": 303, - "y": 68, + "x": 87, + "y": 313, "w": 23, "h": 23 } }, { - "filename": "black_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 327, - "y": 45, - "w": 22, - "h": 23 - } - }, - { - "filename": "griseous_core", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 326, - "y": 68, - "w": 23, - "h": 23 - } - }, - { - "filename": "reveal_glass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 349, - "y": 43, - "w": 23, - "h": 24 - } - }, - { - "filename": "leek", + "filename": "leppa_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -2414,144 +2225,18 @@ "spriteSourceSize": { "x": 4, "y": 5, - "w": 23, + "w": 24, "h": 23 }, "frame": { - "x": 372, - "y": 43, - "w": 23, + "x": 110, + "y": 308, + "w": 24, "h": 23 } }, { - "filename": "rare_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 349, - "y": 67, - "w": 23, - "h": 23 - } - }, - { - "filename": "rarer_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 372, - "y": 66, - "w": 23, - "h": 23 - } - }, - { - "filename": "bug_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 395, - "y": 48, - "w": 22, - "h": 23 - } - }, - { - "filename": "auspicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 395, - "y": 71, - "w": 23, - "h": 21 - } - }, - { - "filename": "binding_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 23, - "h": 20 - }, - "frame": { - "x": 372, - "y": 89, - "w": 23, - "h": 20 - } - }, - { - "filename": "healing_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 349, - "y": 90, - "w": 23, - "h": 22 - } - }, - { - "filename": "black_glasses", + "filename": "choice_specs", "rotated": false, "trimmed": true, "sourceSize": { @@ -2561,14 +2246,35 @@ "spriteSourceSize": { "x": 4, "y": 8, - "w": 23, - "h": 17 + "w": 24, + "h": 18 }, "frame": { - "x": 395, - "y": 92, + "x": 135, + "y": 36, + "w": 24, + "h": 18 + } + }, + { + "filename": "coupon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, "w": 23, - "h": 17 + "h": 19 + }, + "frame": { + "x": 125, + "y": 54, + "w": 23, + "h": 19 } }, { @@ -2586,7 +2292,7 @@ "h": 23 }, "frame": { - "x": 73, + "x": 126, "y": 73, "w": 22, "h": 23 @@ -2607,8 +2313,8 @@ "h": 23 }, "frame": { - "x": 95, - "y": 73, + "x": 126, + "y": 96, "w": 22, "h": 23 } @@ -2628,12 +2334,33 @@ "h": 23 }, "frame": { - "x": 73, - "y": 96, + "x": 126, + "y": 119, "w": 22, "h": 23 } }, + { + "filename": "dragon_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 129, + "y": 142, + "w": 21, + "h": 23 + } + }, { "filename": "fairy_tera_shard", "rotated": false, @@ -2649,8 +2376,8 @@ "h": 23 }, "frame": { - "x": 95, - "y": 96, + "x": 130, + "y": 165, "w": 22, "h": 23 } @@ -2670,33 +2397,12 @@ "h": 23 }, "frame": { - "x": 117, - "y": 78, + "x": 132, + "y": 188, "w": 22, "h": 23 } }, - { - "filename": "blank_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 117, - "y": 101, - "w": 22, - "h": 22 - } - }, { "filename": "fire_stone", "rotated": false, @@ -2712,8 +2418,8 @@ "h": 23 }, "frame": { - "x": 139, - "y": 81, + "x": 132, + "y": 211, "w": 22, "h": 23 } @@ -2733,180 +2439,12 @@ "h": 23 }, "frame": { - "x": 161, - "y": 81, + "x": 134, + "y": 234, "w": 22, "h": 23 } }, - { - "filename": "quick_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 139, - "y": 104, - "w": 24, - "h": 20 - } - }, - { - "filename": "big_nugget", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 163, - "y": 104, - "w": 20, - "h": 20 - } - }, - { - "filename": "max_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 183, - "y": 81, - "w": 17, - "h": 24 - } - }, - { - "filename": "rusted_sword", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 200, - "y": 83, - "w": 23, - "h": 22 - } - }, - { - "filename": "rusted_shield", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 183, - "y": 105, - "w": 24, - "h": 20 - } - }, - { - "filename": "apicot_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 207, - "y": 105, - "w": 19, - "h": 20 - } - }, - { - "filename": "relic_crown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 18 - }, - "frame": { - "x": 223, - "y": 87, - "w": 23, - "h": 18 - } - }, - { - "filename": "blue_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 226, - "y": 105, - "w": 20, - "h": 20 - } - }, { "filename": "flying_tera_shard", "rotated": false, @@ -2922,33 +2460,12 @@ "h": 23 }, "frame": { - "x": 246, - "y": 89, + "x": 134, + "y": 257, "w": 22, "h": 23 } }, - { - "filename": "blunder_policy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 19 - }, - "frame": { - "x": 246, - "y": 112, - "w": 22, - "h": 19 - } - }, { "filename": "focus_sash", "rotated": false, @@ -2964,8 +2481,8 @@ "h": 23 }, "frame": { - "x": 268, - "y": 91, + "x": 134, + "y": 280, "w": 22, "h": 23 } @@ -2985,159 +2502,12 @@ "h": 23 }, "frame": { - "x": 290, - "y": 91, + "x": 134, + "y": 303, "w": 22, "h": 23 } }, - { - "filename": "grass_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 312, - "y": 91, - "w": 22, - "h": 23 - } - }, - { - "filename": "full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 4, - "w": 15, - "h": 23 - }, - "frame": { - "x": 334, - "y": 91, - "w": 15, - "h": 23 - } - }, - { - "filename": "sacred_ash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 268, - "y": 114, - "w": 24, - "h": 20 - } - }, - { - "filename": "shadow_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 292, - "y": 114, - "w": 24, - "h": 20 - } - }, - { - "filename": "soft_sand", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 316, - "y": 114, - "w": 24, - "h": 20 - } - }, - { - "filename": "eviolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 73, - "y": 119, - "w": 15, - "h": 15 - } - }, - { - "filename": "max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 76, - "y": 134, - "w": 18, - "h": 24 - } - }, { "filename": "max_repel", "rotated": false, @@ -3153,33 +2523,12 @@ "h": 24 }, "frame": { - "x": 79, - "y": 158, + "x": 148, + "y": 54, "w": 16, "h": 24 } }, - { - "filename": "oval_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 86, - "y": 182, - "w": 21, - "h": 24 - } - }, { "filename": "pp_max", "rotated": false, @@ -3195,8 +2544,8 @@ "h": 24 }, "frame": { - "x": 92, - "y": 206, + "x": 148, + "y": 78, "w": 16, "h": 24 } @@ -3216,14 +2565,14 @@ "h": 24 }, "frame": { - "x": 92, - "y": 230, + "x": 148, + "y": 102, "w": 16, "h": 24 } }, { - "filename": "protein", + "filename": "aerodactylite", "rotated": false, "trimmed": true, "sourceSize": { @@ -3232,19 +2581,19 @@ }, "spriteSourceSize": { "x": 8, - "y": 4, + "y": 8, "w": 16, - "h": 24 + "h": 16 }, "frame": { - "x": 93, - "y": 254, + "x": 148, + "y": 126, "w": 16, - "h": 24 + "h": 16 } }, { - "filename": "repel", + "filename": "full_heal", "rotated": false, "trimmed": true, "sourceSize": { @@ -3252,20 +2601,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, + "x": 9, "y": 4, - "w": 16, - "h": 24 + "w": 15, + "h": 23 }, "frame": { - "x": 94, - "y": 278, - "w": 16, - "h": 24 + "x": 150, + "y": 142, + "w": 15, + "h": 23 } }, { - "filename": "shiny_charm", + "filename": "grass_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3275,18 +2624,18 @@ "spriteSourceSize": { "x": 6, "y": 4, - "w": 21, - "h": 24 + "w": 22, + "h": 23 }, "frame": { - "x": 94, - "y": 302, - "w": 21, - "h": 24 + "x": 152, + "y": 165, + "w": 22, + "h": 23 } }, { - "filename": "dragon_fang", + "filename": "griseous_core", "rotated": false, "trimmed": true, "sourceSize": { @@ -3296,13 +2645,34 @@ "spriteSourceSize": { "x": 5, "y": 5, - "w": 21, + "w": 23, "h": 23 }, "frame": { - "x": 94, - "y": 326, - "w": 21, + "x": 154, + "y": 188, + "w": 23, + "h": 23 + } + }, + { + "filename": "leek", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 154, + "y": 211, + "w": 23, "h": 23 } }, @@ -3321,8 +2691,8 @@ "h": 23 }, "frame": { - "x": 94, - "y": 349, + "x": 156, + "y": 234, "w": 22, "h": 23 } @@ -3342,14 +2712,14 @@ "h": 23 }, "frame": { - "x": 94, - "y": 372, + "x": 156, + "y": 257, "w": 22, "h": 23 } }, { - "filename": "prism_scale", + "filename": "macho_brace", "rotated": false, "trimmed": true, "sourceSize": { @@ -3357,83 +2727,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 9, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 88, - "y": 119, - "w": 15, - "h": 15 - } - }, - { - "filename": "super_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 94, - "y": 134, - "w": 17, - "h": 24 - } - }, - { - "filename": "super_repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 95, - "y": 158, - "w": 16, - "h": 24 - } - }, - { - "filename": "berry_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, + "x": 4, "y": 5, - "w": 18, - "h": 22 + "w": 23, + "h": 23 }, "frame": { - "x": 340, - "y": 114, - "w": 18, - "h": 22 + "x": 156, + "y": 280, + "w": 23, + "h": 23 } }, { - "filename": "unknown", + "filename": "rare_candy", "rotated": false, "trimmed": true, "sourceSize": { @@ -3441,16 +2748,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 + "x": 4, + "y": 5, + "w": 23, + "h": 23 }, "frame": { - "x": 358, - "y": 112, - "w": 16, - "h": 24 + "x": 156, + "y": 303, + "w": 23, + "h": 23 } }, { @@ -3468,14 +2775,14 @@ "h": 23 }, "frame": { - "x": 374, - "y": 109, + "x": 88, + "y": 336, "w": 22, "h": 23 } }, { - "filename": "normal_tera_shard", + "filename": "scope_lens", "rotated": false, "trimmed": true, "sourceSize": { @@ -3483,57 +2790,36 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 396, - "y": 109, - "w": 22, - "h": 23 - } - }, - { - "filename": "zinc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 107, - "y": 182, - "w": 16, - "h": 24 - } - }, - { - "filename": "hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, + "x": 4, "y": 5, - "w": 17, + "w": 24, "h": 23 }, "frame": { - "x": 108, - "y": 206, - "w": 17, + "x": 110, + "y": 331, + "w": 24, + "h": 23 + } + }, + { + "filename": "twisted_spoon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 134, + "y": 326, + "w": 24, "h": 23 } }, @@ -3552,12 +2838,33 @@ "h": 23 }, "frame": { - "x": 108, - "y": 229, + "x": 158, + "y": 326, "w": 21, "h": 23 } }, + { + "filename": "silver_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 11, + "w": 24, + "h": 15 + }, + "frame": { + "x": 88, + "y": 359, + "w": 24, + "h": 15 + } + }, { "filename": "leaf_stone", "rotated": false, @@ -3573,8 +2880,8 @@ "h": 23 }, "frame": { - "x": 109, - "y": 252, + "x": 92, + "y": 374, "w": 21, "h": 23 } @@ -3594,12 +2901,54 @@ "h": 23 }, "frame": { - "x": 110, - "y": 275, + "x": 94, + "y": 397, "w": 20, "h": 23 } }, + { + "filename": "binding_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 23, + "h": 20 + }, + "frame": { + "x": 112, + "y": 354, + "w": 23, + "h": 20 + } + }, + { + "filename": "normal_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 113, + "y": 374, + "w": 22, + "h": 23 + } + }, { "filename": "petaya_berry", "rotated": false, @@ -3615,12 +2964,54 @@ "h": 23 }, "frame": { - "x": 115, - "y": 298, + "x": 114, + "y": 397, "w": 22, "h": 23 } }, + { + "filename": "exp_share", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 135, + "y": 349, + "w": 24, + "h": 22 + } + }, + { + "filename": "peat_block", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 135, + "y": 371, + "w": 24, + "h": 22 + } + }, { "filename": "poison_tera_shard", "rotated": false, @@ -3636,12 +3027,96 @@ "h": 23 }, "frame": { - "x": 115, - "y": 321, + "x": 159, + "y": 349, "w": 22, "h": 23 } }, + { + "filename": "adamant_crystal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 159, + "y": 372, + "w": 23, + "h": 21 + } + }, + { + "filename": "rarer_candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 136, + "y": 393, + "w": 23, + "h": 23 + } + }, + { + "filename": "healing_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 159, + "y": 393, + "w": 23, + "h": 22 + } + }, + { + "filename": "protein", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 159, + "y": 22, + "w": 16, + "h": 24 + } + }, { "filename": "psychic_tera_shard", "rotated": false, @@ -3657,8 +3132,8 @@ "h": 23 }, "frame": { - "x": 116, - "y": 344, + "x": 175, + "y": 21, "w": 22, "h": 23 } @@ -3678,8 +3153,8 @@ "h": 23 }, "frame": { - "x": 116, - "y": 367, + "x": 197, + "y": 21, "w": 22, "h": 23 } @@ -3699,14 +3174,35 @@ "h": 23 }, "frame": { - "x": 111, - "y": 123, + "x": 219, + "y": 21, "w": 22, "h": 23 } }, { - "filename": "steel_tera_shard", + "filename": "rusted_sword", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 241, + "y": 21, + "w": 23, + "h": 22 + } + }, + { + "filename": "amulet_coin", "rotated": false, "trimmed": true, "sourceSize": { @@ -3715,19 +3211,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 4, - "w": 22, - "h": 23 + "y": 5, + "w": 23, + "h": 21 }, "frame": { - "x": 111, - "y": 146, - "w": 22, - "h": 23 + "x": 264, + "y": 21, + "w": 23, + "h": 21 } }, { - "filename": "stellar_tera_shard", + "filename": "auspicious_armor", "rotated": false, "trimmed": true, "sourceSize": { @@ -3735,20 +3231,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 + "x": 4, + "y": 5, + "w": 23, + "h": 21 }, "frame": { - "x": 133, - "y": 124, - "w": 22, - "h": 23 + "x": 287, + "y": 21, + "w": 23, + "h": 21 } }, { - "filename": "water_tera_shard", + "filename": "berry_juice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 24, + "h": 23 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 22, + "h": 21 + }, + "frame": { + "x": 310, + "y": 21, + "w": 22, + "h": 21 + } + }, + { + "filename": "blank_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -3756,16 +3273,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, + "x": 5, + "y": 5, "w": 22, - "h": 23 + "h": 22 }, "frame": { - "x": 155, - "y": 124, + "x": 332, + "y": 20, "w": 22, - "h": 23 + "h": 22 } }, { @@ -3783,8 +3300,8 @@ "h": 22 }, "frame": { - "x": 133, - "y": 147, + "x": 354, + "y": 20, "w": 22, "h": 22 } @@ -3804,12 +3321,159 @@ "h": 22 }, "frame": { - "x": 155, - "y": 147, + "x": 376, + "y": 20, "w": 22, "h": 22 } }, + { + "filename": "dragon_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 398, + "y": 24, + "w": 24, + "h": 18 + } + }, + { + "filename": "repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 164, + "y": 46, + "w": 16, + "h": 24 + } + }, + { + "filename": "steel_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 180, + "y": 44, + "w": 22, + "h": 23 + } + }, + { + "filename": "stellar_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 202, + "y": 44, + "w": 22, + "h": 23 + } + }, + { + "filename": "hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 224, + "y": 44, + "w": 17, + "h": 23 + } + }, + { + "filename": "water_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 241, + "y": 43, + "w": 22, + "h": 23 + } + }, + { + "filename": "super_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 164, + "y": 70, + "w": 17, + "h": 24 + } + }, { "filename": "wide_lens", "rotated": false, @@ -3825,8 +3489,8 @@ "h": 23 }, "frame": { - "x": 177, - "y": 125, + "x": 181, + "y": 67, "w": 22, "h": 23 } @@ -3846,1247 +3510,8 @@ "h": 22 }, "frame": { - "x": 199, - "y": 125, - "w": 22, - "h": 22 - } - }, - { - "filename": "dire_hit", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 221, - "y": 125, - "w": 22, - "h": 22 - } - }, - { - "filename": "deep_sea_tooth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 177, - "y": 148, - "w": 22, - "h": 21 - } - }, - { - "filename": "dna_splicers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 199, - "y": 147, - "w": 22, - "h": 22 - } - }, - { - "filename": "dragon_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 221, - "y": 147, - "w": 22, - "h": 22 - } - }, - { - "filename": "electirizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 243, - "y": 131, - "w": 22, - "h": 22 - } - }, - { - "filename": "moon_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 265, - "y": 134, - "w": 23, - "h": 21 - } - }, - { - "filename": "n_lunarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 288, - "y": 134, - "w": 23, - "h": 21 - } - }, - { - "filename": "n_solarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 311, - "y": 134, - "w": 23, - "h": 21 - } - }, - { - "filename": "deep_sea_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 243, - "y": 153, - "w": 22, - "h": 20 - } - }, - { - "filename": "mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 265, - "y": 155, - "w": 23, - "h": 19 - } - }, - { - "filename": "pair_of_tickets", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 288, - "y": 155, - "w": 23, - "h": 19 - } - }, - { - "filename": "reviver_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 8, - "w": 23, - "h": 20 - }, - "frame": { - "x": 311, - "y": 155, - "w": 23, - "h": 20 - } - }, - { - "filename": "electric_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 334, - "y": 136, - "w": 22, - "h": 22 - } - }, - { - "filename": "enigma_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 356, - "y": 136, - "w": 22, - "h": 22 - } - }, - { - "filename": "burn_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 334, - "y": 158, - "w": 23, - "h": 17 - } - }, - { - "filename": "fairy_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 378, - "y": 132, - "w": 22, - "h": 22 - } - }, - { - "filename": "fighting_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 400, - "y": 132, - "w": 22, - "h": 22 - } - }, - { - "filename": "chill_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 357, - "y": 158, - "w": 23, - "h": 17 - } - }, - { - "filename": "wellspring_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 380, - "y": 154, - "w": 23, - "h": 21 - } - }, - { - "filename": "fire_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 403, - "y": 154, - "w": 22, - "h": 22 - } - }, - { - "filename": "flying_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 123, - "y": 169, - "w": 22, - "h": 22 - } - }, - { - "filename": "ganlon_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 145, - "y": 169, - "w": 22, - "h": 22 - } - }, - { - "filename": "ghost_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 167, - "y": 169, - "w": 22, - "h": 22 - } - }, - { - "filename": "grass_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 189, - "y": 169, - "w": 22, - "h": 22 - } - }, - { - "filename": "ground_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 211, - "y": 169, - "w": 22, - "h": 22 - } - }, - { - "filename": "shell_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 23, - "h": 20 - }, - "frame": { - "x": 233, - "y": 173, - "w": 23, - "h": 20 - } - }, - { - "filename": "dubious_disc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 256, - "y": 174, - "w": 22, - "h": 19 - } - }, - { - "filename": "fairy_feather", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 20 - }, - "frame": { - "x": 278, - "y": 174, - "w": 22, - "h": 20 - } - }, - { - "filename": "guard_spec", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 300, - "y": 175, - "w": 22, - "h": 22 - } - }, - { - "filename": "ice_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 322, - "y": 175, - "w": 22, - "h": 22 - } - }, - { - "filename": "ice_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 344, - "y": 175, - "w": 22, - "h": 22 - } - }, - { - "filename": "magmarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 366, - "y": 175, - "w": 22, - "h": 22 - } - }, - { - "filename": "leftovers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 15, - "h": 22 - }, - "frame": { - "x": 388, - "y": 175, - "w": 15, - "h": 22 - } - }, - { - "filename": "mini_black_hole", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 403, - "y": 176, - "w": 22, - "h": 22 - } - }, - { - "filename": "poison_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 125, - "y": 191, - "w": 22, - "h": 22 - } - }, - { - "filename": "protector", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 147, - "y": 191, - "w": 22, - "h": 22 - } - }, - { - "filename": "psychic_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 169, - "y": 191, - "w": 22, - "h": 22 - } - }, - { - "filename": "rock_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 191, - "y": 191, - "w": 22, - "h": 22 - } - }, - { - "filename": "hard_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 20, - "h": 22 - }, - "frame": { - "x": 213, - "y": 191, - "w": 20, - "h": 22 - } - }, - { - "filename": "liechi_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 233, - "y": 193, - "w": 22, - "h": 21 - } - }, - { - "filename": "scroll_of_darkness", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 255, - "y": 193, - "w": 22, - "h": 22 - } - }, - { - "filename": "douse_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 277, - "y": 194, - "w": 23, - "h": 17 - } - }, - { - "filename": "relic_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 9, - "w": 17, - "h": 16 - }, - "frame": { - "x": 125, - "y": 213, - "w": 17, - "h": 16 - } - }, - { - "filename": "shock_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 142, - "y": 213, - "w": 23, - "h": 17 - } - }, - { - "filename": "wise_glasses", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 165, - "y": 213, - "w": 23, - "h": 17 - } - }, - { - "filename": "malicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 188, - "y": 213, - "w": 22, - "h": 20 - } - }, - { - "filename": "scroll_of_waters", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 213, - "w": 22, - "h": 22 - } - }, - { - "filename": "shed_shell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 232, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "starf_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 254, - "y": 215, - "w": 22, - "h": 22 - } - }, - { - "filename": "steel_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 300, - "y": 197, - "w": 22, - "h": 22 - } - }, - { - "filename": "thick_club", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 322, - "y": 197, - "w": 22, - "h": 22 - } - }, - { - "filename": "thunder_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 344, - "y": 197, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_bug", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 366, - "y": 197, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_dark", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 129, - "y": 230, - "w": 22, - "h": 22 - } - }, - { - "filename": "sharp_beak", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 130, - "y": 252, - "w": 21, - "h": 23 - } - }, - { - "filename": "whipped_dream", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 130, - "y": 275, - "w": 21, - "h": 23 - } - }, - { - "filename": "tm_dragon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 151, - "y": 230, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_electric", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 151, - "y": 252, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_fairy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 151, - "y": 274, + "x": 203, + "y": 67, "w": 22, "h": 22 } @@ -5106,12 +3531,54 @@ "h": 23 }, "frame": { - "x": 137, - "y": 298, + "x": 164, + "y": 94, "w": 17, "h": 23 } }, + { + "filename": "dire_hit", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 181, + "y": 90, + "w": 22, + "h": 22 + } + }, + { + "filename": "dna_splicers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 89, + "w": 22, + "h": 22 + } + }, { "filename": "sachet", "rotated": false, @@ -5127,12 +3594,138 @@ "h": 23 }, "frame": { - "x": 137, - "y": 321, + "x": 164, + "y": 117, "w": 18, "h": 23 } }, + { + "filename": "super_repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 225, + "y": 67, + "w": 16, + "h": 24 + } + }, + { + "filename": "dragon_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 241, + "y": 66, + "w": 22, + "h": 22 + } + }, + { + "filename": "sharp_beak", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 182, + "y": 112, + "w": 21, + "h": 23 + } + }, + { + "filename": "electirizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 111, + "w": 22, + "h": 22 + } + }, + { + "filename": "unknown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 225, + "y": 91, + "w": 16, + "h": 24 + } + }, + { + "filename": "electric_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 241, + "y": 88, + "w": 22, + "h": 22 + } + }, { "filename": "super_potion", "rotated": false, @@ -5148,12 +3741,1188 @@ "h": 23 }, "frame": { - "x": 138, - "y": 344, + "x": 165, + "y": 140, "w": 17, "h": 23 } }, + { + "filename": "whipped_dream", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 182, + "y": 135, + "w": 21, + "h": 23 + } + }, + { + "filename": "enigma_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 133, + "w": 22, + "h": 22 + } + }, + { + "filename": "zinc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 225, + "y": 115, + "w": 16, + "h": 24 + } + }, + { + "filename": "fairy_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 241, + "y": 110, + "w": 22, + "h": 22 + } + }, + { + "filename": "aggronite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 225, + "y": 139, + "w": 16, + "h": 16 + } + }, + { + "filename": "fighting_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 241, + "y": 132, + "w": 22, + "h": 22 + } + }, + { + "filename": "berry_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 18, + "h": 22 + }, + "frame": { + "x": 174, + "y": 163, + "w": 18, + "h": 22 + } + }, + { + "filename": "fire_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 177, + "y": 185, + "w": 22, + "h": 22 + } + }, + { + "filename": "flying_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 177, + "y": 207, + "w": 22, + "h": 22 + } + }, + { + "filename": "ganlon_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 178, + "y": 229, + "w": 22, + "h": 22 + } + }, + { + "filename": "ghost_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 178, + "y": 251, + "w": 22, + "h": 22 + } + }, + { + "filename": "grass_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 179, + "y": 273, + "w": 22, + "h": 22 + } + }, + { + "filename": "ground_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 179, + "y": 295, + "w": 22, + "h": 22 + } + }, + { + "filename": "guard_spec", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 179, + "y": 317, + "w": 22, + "h": 22 + } + }, + { + "filename": "hard_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 181, + "y": 339, + "w": 20, + "h": 22 + } + }, + { + "filename": "ice_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 182, + "y": 361, + "w": 22, + "h": 22 + } + }, + { + "filename": "ice_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 182, + "y": 383, + "w": 22, + "h": 22 + } + }, + { + "filename": "black_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 182, + "y": 405, + "w": 23, + "h": 17 + } + }, + { + "filename": "leftovers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 15, + "h": 22 + }, + "frame": { + "x": 192, + "y": 158, + "w": 15, + "h": 22 + } + }, + { + "filename": "icy_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 207, + "y": 155, + "w": 24, + "h": 20 + } + }, + { + "filename": "apicot_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 231, + "y": 155, + "w": 19, + "h": 20 + } + }, + { + "filename": "dawn_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 21 + }, + "frame": { + "x": 250, + "y": 154, + "w": 20, + "h": 21 + } + }, + { + "filename": "metal_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 207, + "y": 175, + "w": 24, + "h": 20 + } + }, + { + "filename": "quick_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 231, + "y": 175, + "w": 24, + "h": 20 + } + }, + { + "filename": "magmarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 199, + "y": 195, + "w": 22, + "h": 22 + } + }, + { + "filename": "mini_black_hole", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 221, + "y": 195, + "w": 22, + "h": 22 + } + }, + { + "filename": "big_nugget", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 255, + "y": 175, + "w": 20, + "h": 20 + } + }, + { + "filename": "moon_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 243, + "y": 195, + "w": 23, + "h": 21 + } + }, + { + "filename": "n_lunarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 200, + "y": 217, + "w": 23, + "h": 21 + } + }, + { + "filename": "n_solarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 200, + "y": 238, + "w": 23, + "h": 21 + } + }, + { + "filename": "poison_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 217, + "w": 22, + "h": 22 + } + }, + { + "filename": "deep_sea_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 223, + "y": 239, + "w": 22, + "h": 20 + } + }, + { + "filename": "protector", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 245, + "y": 216, + "w": 22, + "h": 22 + } + }, + { + "filename": "deep_sea_tooth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 245, + "y": 238, + "w": 22, + "h": 21 + } + }, + { + "filename": "dusk_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 266, + "y": 195, + "w": 21, + "h": 21 + } + }, + { + "filename": "psychic_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 267, + "y": 216, + "w": 22, + "h": 22 + } + }, + { + "filename": "liechi_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 267, + "y": 238, + "w": 22, + "h": 21 + } + }, + { + "filename": "rock_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 201, + "y": 259, + "w": 22, + "h": 22 + } + }, + { + "filename": "rusted_shield", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 223, + "y": 259, + "w": 24, + "h": 20 + } + }, + { + "filename": "sacred_ash", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 247, + "y": 259, + "w": 24, + "h": 20 + } + }, + { + "filename": "scroll_of_darkness", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 201, + "y": 281, + "w": 22, + "h": 22 + } + }, + { + "filename": "scroll_of_waters", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 279, + "w": 22, + "h": 22 + } + }, + { + "filename": "shadow_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 245, + "y": 279, + "w": 24, + "h": 20 + } + }, + { + "filename": "shed_shell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 201, + "y": 303, + "w": 22, + "h": 22 + } + }, + { + "filename": "starf_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 301, + "w": 22, + "h": 22 + } + }, + { + "filename": "soft_sand", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 245, + "y": 299, + "w": 24, + "h": 20 + } + }, + { + "filename": "steel_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 201, + "y": 325, + "w": 22, + "h": 22 + } + }, + { + "filename": "thick_club", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 323, + "w": 22, + "h": 22 + } + }, + { + "filename": "thunder_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 245, + "y": 319, + "w": 22, + "h": 22 + } + }, + { + "filename": "blue_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 271, + "y": 259, + "w": 20, + "h": 20 + } + }, + { + "filename": "tm_bug", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 269, + "y": 279, + "w": 22, + "h": 22 + } + }, + { + "filename": "black_sludge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 24, + "h": 24 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 22, + "h": 19 + }, + "frame": { + "x": 269, + "y": 301, + "w": 22, + "h": 19 + } + }, + { + "filename": "wellspring_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 267, + "y": 320, + "w": 23, + "h": 21 + } + }, + { + "filename": "burn_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 245, + "y": 341, + "w": 23, + "h": 17 + } + }, + { + "filename": "blunder_policy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 19 + }, + "frame": { + "x": 268, + "y": 341, + "w": 22, + "h": 19 + } + }, + { + "filename": "dubious_disc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 223, + "y": 345, + "w": 22, + "h": 19 + } + }, { "filename": "lock_capsule", "rotated": false, @@ -5169,8 +4938,8 @@ "h": 22 }, "frame": { - "x": 154, - "y": 296, + "x": 204, + "y": 347, "w": 19, "h": 22 } @@ -5190,14 +4959,203 @@ "h": 22 }, "frame": { - "x": 138, - "y": 367, + "x": 204, + "y": 369, "w": 19, "h": 22 } }, { - "filename": "sitrus_berry", + "filename": "tm_dark", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 364, + "w": 22, + "h": 22 + } + }, + { + "filename": "reviver_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 8, + "w": 23, + "h": 20 + }, + "frame": { + "x": 245, + "y": 358, + "w": 23, + "h": 20 + } + }, + { + "filename": "fairy_feather", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 20 + }, + "frame": { + "x": 268, + "y": 360, + "w": 22, + "h": 20 + } + }, + { + "filename": "chill_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 245, + "y": 378, + "w": 23, + "h": 17 + } + }, + { + "filename": "douse_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 268, + "y": 380, + "w": 23, + "h": 17 + } + }, + { + "filename": "malicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 223, + "y": 386, + "w": 22, + "h": 20 + } + }, + { + "filename": "tm_dragon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 205, + "y": 406, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_electric", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 227, + "y": 406, + "w": 22, + "h": 22 + } + }, + { + "filename": "candy_overlay", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 12, + "w": 16, + "h": 15 + }, + "frame": { + "x": 205, + "y": 391, + "w": 16, + "h": 15 + } + }, + { + "filename": "quick_claw", "rotated": false, "trimmed": true, "sourceSize": { @@ -5206,14 +5164,98 @@ }, "spriteSourceSize": { "x": 6, + "y": 6, + "w": 19, + "h": 21 + }, + "frame": { + "x": 249, + "y": 395, + "w": 19, + "h": 21 + } + }, + { + "filename": "golden_mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 268, + "y": 397, + "w": 23, + "h": 19 + } + }, + { + "filename": "relic_gold", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 11, + "w": 15, + "h": 11 + }, + "frame": { + "x": 249, + "y": 416, + "w": 15, + "h": 11 + } + }, + { + "filename": "mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 264, + "y": 42, + "w": 23, + "h": 19 + } + }, + { + "filename": "tm_fairy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, "y": 5, - "w": 20, + "w": 22, "h": 22 }, "frame": { - "x": 155, - "y": 318, - "w": 20, + "x": 263, + "y": 61, + "w": 22, "h": 22 } }, @@ -5232,8 +5274,8 @@ "h": 22 }, "frame": { - "x": 155, - "y": 340, + "x": 263, + "y": 83, "w": 22, "h": 22 } @@ -5253,75 +5295,12 @@ "h": 22 }, "frame": { - "x": 157, - "y": 362, + "x": 263, + "y": 105, "w": 22, "h": 22 } }, - { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 173, - "y": 230, - "w": 15, - "h": 11 - } - }, - { - "filename": "metronome", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 173, - "y": 241, - "w": 17, - "h": 22 - } - }, - { - "filename": "soothe_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 173, - "y": 263, - "w": 17, - "h": 22 - } - }, { "filename": "tm_flying", "rotated": false, @@ -5337,14 +5316,14 @@ "h": 22 }, "frame": { - "x": 173, - "y": 285, + "x": 263, + "y": 127, "w": 22, "h": 22 } }, { - "filename": "dawn_stone", + "filename": "pair_of_tickets", "rotated": false, "trimmed": true, "sourceSize": { @@ -5352,121 +5331,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 21 + "x": 4, + "y": 7, + "w": 23, + "h": 19 }, "frame": { - "x": 190, - "y": 233, - "w": 20, - "h": 21 - } - }, - { - "filename": "sweet_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 210, - "y": 235, - "w": 22, - "h": 21 - } - }, - { - "filename": "syrupy_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 232, - "y": 236, - "w": 22, - "h": 21 - } - }, - { - "filename": "gb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 190, - "y": 254, - "w": 20, - "h": 20 - } - }, - { - "filename": "tart_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 254, - "y": 237, - "w": 22, - "h": 21 - } - }, - { - "filename": "tera_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 210, - "y": 256, - "w": 22, - "h": 20 + "x": 287, + "y": 42, + "w": 23, + "h": 19 } }, { @@ -5484,8 +5358,8 @@ "h": 22 }, "frame": { - "x": 232, - "y": 257, + "x": 285, + "y": 61, "w": 22, "h": 22 } @@ -5505,8 +5379,8 @@ "h": 22 }, "frame": { - "x": 254, - "y": 258, + "x": 285, + "y": 83, "w": 22, "h": 22 } @@ -5526,8 +5400,8 @@ "h": 22 }, "frame": { - "x": 175, - "y": 307, + "x": 285, + "y": 105, "w": 22, "h": 22 } @@ -5547,12 +5421,96 @@ "h": 22 }, "frame": { - "x": 177, - "y": 329, + "x": 285, + "y": 127, "w": 22, "h": 22 } }, + { + "filename": "shell_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 23, + "h": 20 + }, + "frame": { + "x": 310, + "y": 42, + "w": 23, + "h": 20 + } + }, + { + "filename": "sweet_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 333, + "y": 42, + "w": 22, + "h": 21 + } + }, + { + "filename": "syrupy_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 355, + "y": 42, + "w": 22, + "h": 21 + } + }, + { + "filename": "tart_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 377, + "y": 42, + "w": 22, + "h": 21 + } + }, { "filename": "tm_normal", "rotated": false, @@ -5568,8 +5526,8 @@ "h": 22 }, "frame": { - "x": 179, - "y": 351, + "x": 399, + "y": 42, "w": 22, "h": 22 } @@ -5589,8 +5547,8 @@ "h": 22 }, "frame": { - "x": 179, - "y": 373, + "x": 307, + "y": 62, "w": 22, "h": 22 } @@ -5610,138 +5568,12 @@ "h": 22 }, "frame": { - "x": 157, - "y": 384, + "x": 307, + "y": 84, "w": 22, "h": 22 } }, - { - "filename": "upgrade", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 109, - "y": 406, - "w": 22, - "h": 19 - } - }, - { - "filename": "metal_alloy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 21, - "h": 19 - }, - "frame": { - "x": 131, - "y": 406, - "w": 21, - "h": 19 - } - }, - { - "filename": "lum_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 152, - "y": 406, - "w": 20, - "h": 19 - } - }, - { - "filename": "power_herb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 172, - "y": 406, - "w": 20, - "h": 19 - } - }, - { - "filename": "absolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 116, - "y": 390, - "w": 16, - "h": 16 - } - }, - { - "filename": "aerodactylite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 132, - "y": 390, - "w": 16, - "h": 16 - } - }, { "filename": "tm_rock", "rotated": false, @@ -5757,8 +5589,8 @@ "h": 22 }, "frame": { - "x": 388, - "y": 198, + "x": 307, + "y": 106, "w": 22, "h": 22 } @@ -5778,8 +5610,8 @@ "h": 22 }, "frame": { - "x": 277, - "y": 211, + "x": 307, + "y": 128, "w": 22, "h": 22 } @@ -5799,8 +5631,8 @@ "h": 22 }, "frame": { - "x": 276, - "y": 233, + "x": 329, + "y": 63, "w": 22, "h": 22 } @@ -5820,8 +5652,8 @@ "h": 22 }, "frame": { - "x": 276, - "y": 255, + "x": 329, + "y": 85, "w": 22, "h": 22 } @@ -5841,8 +5673,8 @@ "h": 22 }, "frame": { - "x": 299, - "y": 219, + "x": 351, + "y": 63, "w": 22, "h": 22 } @@ -5862,8 +5694,8 @@ "h": 22 }, "frame": { - "x": 321, - "y": 219, + "x": 329, + "y": 107, "w": 22, "h": 22 } @@ -5883,8 +5715,8 @@ "h": 22 }, "frame": { - "x": 343, - "y": 219, + "x": 351, + "y": 85, "w": 22, "h": 22 } @@ -5904,8 +5736,8 @@ "h": 22 }, "frame": { - "x": 365, - "y": 219, + "x": 373, + "y": 63, "w": 22, "h": 22 } @@ -5925,8 +5757,8 @@ "h": 22 }, "frame": { - "x": 298, - "y": 241, + "x": 351, + "y": 107, "w": 22, "h": 22 } @@ -5946,8 +5778,8 @@ "h": 22 }, "frame": { - "x": 320, - "y": 241, + "x": 373, + "y": 85, "w": 22, "h": 22 } @@ -5967,33 +5799,12 @@ "h": 22 }, "frame": { - "x": 342, - "y": 241, + "x": 373, + "y": 107, "w": 22, "h": 22 } }, - { - "filename": "dusk_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 364, - "y": 241, - "w": 21, - "h": 21 - } - }, { "filename": "poison_barb", "rotated": false, @@ -6009,33 +5820,12 @@ "h": 21 }, "frame": { - "x": 387, - "y": 220, + "x": 329, + "y": 129, "w": 21, "h": 21 } }, - { - "filename": "golden_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 408, - "y": 220, - "w": 17, - "h": 20 - } - }, { "filename": "shiny_stone", "rotated": false, @@ -6051,14 +5841,77 @@ "h": 21 }, "frame": { - "x": 385, - "y": 241, + "x": 350, + "y": 129, "w": 21, "h": 21 } }, { - "filename": "quick_claw", + "filename": "tera_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 371, + "y": 129, + "w": 22, + "h": 20 + } + }, + { + "filename": "sitrus_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 395, + "y": 64, + "w": 20, + "h": 22 + } + }, + { + "filename": "zoom_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 395, + "y": 86, + "w": 21, + "h": 21 + } + }, + { + "filename": "gb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6068,14 +5921,140 @@ "spriteSourceSize": { "x": 6, "y": 6, - "w": 19, - "h": 21 + "w": 20, + "h": 20 }, "frame": { - "x": 406, - "y": 241, - "w": 19, - "h": 21 + "x": 395, + "y": 107, + "w": 20, + "h": 20 + } + }, + { + "filename": "relic_crown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 18 + }, + "frame": { + "x": 270, + "y": 149, + "w": 23, + "h": 18 + } + }, + { + "filename": "metronome", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 275, + "y": 167, + "w": 17, + "h": 22 + } + }, + { + "filename": "shock_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 293, + "y": 150, + "w": 23, + "h": 17 + } + }, + { + "filename": "upgrade", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 292, + "y": 167, + "w": 22, + "h": 19 + } + }, + { + "filename": "wise_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 316, + "y": 150, + "w": 23, + "h": 17 + } + }, + { + "filename": "metal_alloy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 21, + "h": 19 + }, + "frame": { + "x": 314, + "y": 167, + "w": 21, + "h": 19 } }, { @@ -6093,12 +6072,54 @@ "h": 18 }, "frame": { - "x": 298, - "y": 263, + "x": 339, + "y": 150, "w": 21, "h": 18 } }, + { + "filename": "old_gateau", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 21, + "h": 18 + }, + "frame": { + "x": 335, + "y": 168, + "w": 21, + "h": 18 + } + }, + { + "filename": "baton", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 360, + "y": 150, + "w": 18, + "h": 18 + } + }, { "filename": "sharp_meteorite", "rotated": false, @@ -6114,117 +6135,12 @@ "h": 18 }, "frame": { - "x": 319, - "y": 263, + "x": 356, + "y": 168, "w": 21, "h": 18 } }, - { - "filename": "unremarkable_teacup", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 21, - "h": 18 - }, - "frame": { - "x": 340, - "y": 263, - "w": 21, - "h": 18 - } - }, - { - "filename": "zoom_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 276, - "y": 277, - "w": 21, - "h": 21 - } - }, - { - "filename": "everstone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 17 - }, - "frame": { - "x": 297, - "y": 281, - "w": 20, - "h": 17 - } - }, - { - "filename": "magnet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 317, - "y": 281, - "w": 20, - "h": 20 - } - }, - { - "filename": "mb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 337, - "y": 281, - "w": 20, - "h": 20 - } - }, { "filename": "candy_jar", "rotated": false, @@ -6240,14 +6156,77 @@ "h": 20 }, "frame": { - "x": 357, - "y": 281, + "x": 378, + "y": 149, "w": 19, "h": 20 } }, { - "filename": "baton", + "filename": "everstone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 17 + }, + "frame": { + "x": 377, + "y": 169, + "w": 20, + "h": 17 + } + }, + { + "filename": "golden_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 393, + "y": 129, + "w": 17, + "h": 20 + } + }, + { + "filename": "razor_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 18, + "h": 20 + }, + "frame": { + "x": 410, + "y": 127, + "w": 18, + "h": 20 + } + }, + { + "filename": "oval_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6258,15 +6237,99 @@ "x": 7, "y": 7, "w": 18, + "h": 19 + }, + "frame": { + "x": 410, + "y": 147, + "w": 18, + "h": 19 + } + }, + { + "filename": "magnet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 397, + "y": 166, + "w": 20, + "h": 20 + } + }, + { + "filename": "unremarkable_teacup", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 21, "h": 18 }, "frame": { - "x": 361, - "y": 263, - "w": 18, + "x": 292, + "y": 186, + "w": 21, "h": 18 } }, + { + "filename": "lum_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 313, + "y": 186, + "w": 20, + "h": 19 + } + }, + { + "filename": "mb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 333, + "y": 186, + "w": 20, + "h": 20 + } + }, { "filename": "pb", "rotated": false, @@ -6282,8 +6345,8 @@ "h": 20 }, "frame": { - "x": 379, - "y": 262, + "x": 353, + "y": 186, "w": 20, "h": 20 } @@ -6303,33 +6366,12 @@ "h": 20 }, "frame": { - "x": 399, - "y": 262, + "x": 373, + "y": 186, "w": 20, "h": 20 } }, - { - "filename": "razor_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 376, - "y": 282, - "w": 20, - "h": 19 - } - }, { "filename": "rb", "rotated": false, @@ -6345,8 +6387,71 @@ "h": 20 }, "frame": { - "x": 396, - "y": 282, + "x": 393, + "y": 186, + "w": 20, + "h": 20 + } + }, + { + "filename": "eviolite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 413, + "y": 186, + "w": 15, + "h": 15 + } + }, + { + "filename": "prism_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 413, + "y": 201, + "w": 15, + "h": 15 + } + }, + { + "filename": "smooth_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 289, + "y": 204, "w": 20, "h": 20 } @@ -6366,14 +6471,14 @@ "h": 21 }, "frame": { - "x": 192, - "y": 395, + "x": 289, + "y": 224, "w": 19, "h": 21 } }, { - "filename": "smooth_meteorite", + "filename": "power_herb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6381,16 +6486,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 6, + "x": 6, + "y": 7, "w": 20, - "h": 20 + "h": 19 }, "frame": { - "x": 211, - "y": 276, + "x": 309, + "y": 205, "w": 20, - "h": 20 + "h": 19 } }, { @@ -6408,12 +6513,33 @@ "h": 20 }, "frame": { - "x": 231, - "y": 279, + "x": 308, + "y": 224, "w": 20, "h": 20 } }, + { + "filename": "razor_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 329, + "y": 206, + "w": 20, + "h": 19 + } + }, { "filename": "ub", "rotated": false, @@ -6429,14 +6555,14 @@ "h": 20 }, "frame": { - "x": 251, - "y": 280, + "x": 349, + "y": 206, "w": 20, "h": 20 } }, { - "filename": "mystery_egg", + "filename": "hard_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6444,16 +6570,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 18 + "x": 6, + "y": 6, + "w": 19, + "h": 20 }, "frame": { - "x": 195, - "y": 276, - "w": 16, - "h": 18 + "x": 369, + "y": 206, + "w": 19, + "h": 20 } }, { @@ -6471,8 +6597,8 @@ "h": 19 }, "frame": { - "x": 211, - "y": 296, + "x": 388, + "y": 206, "w": 20, "h": 19 } @@ -6492,54 +6618,12 @@ "h": 18 }, "frame": { - "x": 231, - "y": 299, + "x": 408, + "y": 216, "w": 20, "h": 18 } }, - { - "filename": "wl_antidote", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 251, - "y": 300, - "w": 20, - "h": 18 - } - }, - { - "filename": "hard_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 271, - "y": 298, - "w": 19, - "h": 20 - } - }, { "filename": "miracle_seed", "rotated": false, @@ -6555,12 +6639,33 @@ "h": 19 }, "frame": { - "x": 290, - "y": 298, + "x": 328, + "y": 225, "w": 19, "h": 19 } }, + { + "filename": "wl_antidote", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 347, + "y": 226, + "w": 20, + "h": 18 + } + }, { "filename": "wl_awakening", "rotated": false, @@ -6576,8 +6681,8 @@ "h": 18 }, "frame": { - "x": 309, - "y": 301, + "x": 367, + "y": 226, "w": 20, "h": 18 } @@ -6597,8 +6702,8 @@ "h": 18 }, "frame": { - "x": 329, - "y": 301, + "x": 388, + "y": 225, "w": 20, "h": 18 } @@ -6618,12 +6723,33 @@ "h": 18 }, "frame": { - "x": 349, - "y": 301, + "x": 408, + "y": 234, "w": 20, "h": 18 } }, + { + "filename": "soothe_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 291, + "y": 245, + "w": 17, + "h": 22 + } + }, { "filename": "wl_custom_thief", "rotated": false, @@ -6639,8 +6765,8 @@ "h": 18 }, "frame": { - "x": 369, - "y": 301, + "x": 308, + "y": 244, "w": 20, "h": 18 } @@ -6660,54 +6786,12 @@ "h": 18 }, "frame": { - "x": 389, - "y": 302, + "x": 328, + "y": 244, "w": 20, "h": 18 } }, - { - "filename": "aggronite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 409, - "y": 302, - "w": 16, - "h": 16 - } - }, - { - "filename": "alakazite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 409, - "y": 318, - "w": 16, - "h": 16 - } - }, { "filename": "wl_ether", "rotated": false, @@ -6723,12 +6807,33 @@ "h": 18 }, "frame": { - "x": 211, - "y": 315, + "x": 348, + "y": 244, "w": 20, "h": 18 } }, + { + "filename": "lucky_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 291, + "y": 267, + "w": 17, + "h": 20 + } + }, { "filename": "wl_full_heal", "rotated": false, @@ -6744,8 +6849,8 @@ "h": 18 }, "frame": { - "x": 231, - "y": 317, + "x": 308, + "y": 262, "w": 20, "h": 18 } @@ -6765,8 +6870,8 @@ "h": 18 }, "frame": { - "x": 251, - "y": 318, + "x": 328, + "y": 262, "w": 20, "h": 18 } @@ -6786,33 +6891,12 @@ "h": 18 }, "frame": { - "x": 271, - "y": 318, + "x": 348, + "y": 262, "w": 20, "h": 18 } }, - { - "filename": "oval_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 19 - }, - "frame": { - "x": 291, - "y": 317, - "w": 18, - "h": 19 - } - }, { "filename": "wl_hyper_potion", "rotated": false, @@ -6828,8 +6912,8 @@ "h": 18 }, "frame": { - "x": 309, - "y": 319, + "x": 368, + "y": 244, "w": 20, "h": 18 } @@ -6849,8 +6933,8 @@ "h": 18 }, "frame": { - "x": 329, - "y": 319, + "x": 388, + "y": 243, "w": 20, "h": 18 } @@ -6870,8 +6954,8 @@ "h": 18 }, "frame": { - "x": 349, - "y": 319, + "x": 408, + "y": 252, "w": 20, "h": 18 } @@ -6891,8 +6975,8 @@ "h": 18 }, "frame": { - "x": 369, - "y": 319, + "x": 368, + "y": 262, "w": 20, "h": 18 } @@ -6912,33 +6996,12 @@ "h": 18 }, "frame": { - "x": 389, - "y": 320, + "x": 388, + "y": 261, "w": 20, "h": 18 } }, - { - "filename": "altarianite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 409, - "y": 334, - "w": 16, - "h": 16 - } - }, { "filename": "wl_max_ether", "rotated": false, @@ -6954,197 +7017,8 @@ "h": 18 }, "frame": { - "x": 199, - "y": 333, - "w": 20, - "h": 18 - } - }, - { - "filename": "razor_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 18, - "h": 20 - }, - "frame": { - "x": 201, - "y": 351, - "w": 18, - "h": 20 - } - }, - { - "filename": "lucky_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 201, - "y": 371, - "w": 17, - "h": 20 - } - }, - { - "filename": "wl_max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 219, - "y": 335, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 219, - "y": 353, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_paralyze_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 218, - "y": 371, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 239, - "y": 336, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_reset_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 259, - "y": 336, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 279, - "y": 336, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 239, - "y": 354, + "x": 408, + "y": 270, "w": 20, "h": 18 } @@ -7164,8 +7038,8 @@ "h": 18 }, "frame": { - "x": 259, - "y": 354, + "x": 291, + "y": 287, "w": 18, "h": 18 } @@ -7185,12 +7059,159 @@ "h": 18 }, "frame": { - "x": 277, - "y": 354, + "x": 291, + "y": 305, "w": 18, "h": 18 } }, + { + "filename": "wl_max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 290, + "y": 323, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 290, + "y": 341, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_paralyze_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 290, + "y": 359, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 291, + "y": 377, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_reset_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 291, + "y": 395, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 309, + "y": 280, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 309, + "y": 298, + "w": 20, + "h": 18 + } + }, { "filename": "flame_orb", "rotated": false, @@ -7206,8 +7227,8 @@ "h": 18 }, "frame": { - "x": 238, - "y": 372, + "x": 329, + "y": 280, "w": 18, "h": 18 } @@ -7227,8 +7248,8 @@ "h": 18 }, "frame": { - "x": 256, - "y": 372, + "x": 329, + "y": 298, "w": 18, "h": 18 } @@ -7248,8 +7269,8 @@ "h": 18 }, "frame": { - "x": 274, - "y": 372, + "x": 347, + "y": 280, "w": 18, "h": 18 } @@ -7269,12 +7290,75 @@ "h": 18 }, "frame": { - "x": 299, - "y": 337, + "x": 347, + "y": 298, "w": 18, "h": 18 } }, + { + "filename": "mystery_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 18 + }, + "frame": { + "x": 365, + "y": 280, + "w": 16, + "h": 18 + } + }, + { + "filename": "alakazite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 365, + "y": 298, + "w": 16, + "h": 16 + } + }, + { + "filename": "altarianite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 310, + "y": 316, + "w": 16, + "h": 16 + } + }, { "filename": "ampharosite", "rotated": false, @@ -7290,8 +7374,8 @@ "h": 16 }, "frame": { - "x": 317, - "y": 337, + "x": 310, + "y": 332, "w": 16, "h": 16 } @@ -7311,8 +7395,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 337, + "x": 326, + "y": 316, "w": 16, "h": 16 } @@ -7332,8 +7416,8 @@ "h": 16 }, "frame": { - "x": 349, - "y": 337, + "x": 310, + "y": 348, "w": 16, "h": 16 } @@ -7353,8 +7437,8 @@ "h": 16 }, "frame": { - "x": 365, - "y": 337, + "x": 326, + "y": 332, "w": 16, "h": 16 } @@ -7374,8 +7458,8 @@ "h": 16 }, "frame": { - "x": 295, - "y": 355, + "x": 342, + "y": 316, "w": 16, "h": 16 } @@ -7395,8 +7479,8 @@ "h": 16 }, "frame": { - "x": 381, - "y": 338, + "x": 326, + "y": 348, "w": 16, "h": 16 } @@ -7416,8 +7500,8 @@ "h": 16 }, "frame": { - "x": 311, - "y": 355, + "x": 342, + "y": 332, "w": 16, "h": 16 } @@ -7437,8 +7521,8 @@ "h": 16 }, "frame": { - "x": 327, - "y": 353, + "x": 342, + "y": 348, "w": 16, "h": 16 } @@ -7458,8 +7542,8 @@ "h": 16 }, "frame": { - "x": 343, - "y": 353, + "x": 381, + "y": 280, "w": 16, "h": 16 } @@ -7479,8 +7563,8 @@ "h": 16 }, "frame": { - "x": 359, - "y": 353, + "x": 381, + "y": 296, "w": 16, "h": 16 } @@ -7500,8 +7584,8 @@ "h": 16 }, "frame": { - "x": 375, - "y": 354, + "x": 358, + "y": 316, "w": 16, "h": 16 } @@ -7521,8 +7605,8 @@ "h": 16 }, "frame": { - "x": 391, - "y": 354, + "x": 358, + "y": 332, "w": 16, "h": 16 } @@ -7542,8 +7626,8 @@ "h": 16 }, "frame": { - "x": 407, - "y": 350, + "x": 358, + "y": 348, "w": 16, "h": 16 } @@ -7563,8 +7647,8 @@ "h": 16 }, "frame": { - "x": 407, - "y": 366, + "x": 397, + "y": 288, "w": 16, "h": 16 } @@ -7584,8 +7668,8 @@ "h": 16 }, "frame": { - "x": 211, - "y": 391, + "x": 397, + "y": 304, "w": 16, "h": 16 } @@ -7605,8 +7689,8 @@ "h": 16 }, "frame": { - "x": 211, - "y": 407, + "x": 381, + "y": 312, "w": 16, "h": 16 } @@ -7626,8 +7710,8 @@ "h": 16 }, "frame": { - "x": 227, - "y": 390, + "x": 374, + "y": 328, "w": 16, "h": 16 } @@ -7647,8 +7731,8 @@ "h": 16 }, "frame": { - "x": 227, - "y": 406, + "x": 374, + "y": 344, "w": 16, "h": 16 } @@ -7668,8 +7752,8 @@ "h": 16 }, "frame": { - "x": 243, - "y": 390, + "x": 397, + "y": 320, "w": 16, "h": 16 } @@ -7689,8 +7773,8 @@ "h": 16 }, "frame": { - "x": 243, - "y": 406, + "x": 390, + "y": 336, "w": 16, "h": 16 } @@ -7710,8 +7794,8 @@ "h": 16 }, "frame": { - "x": 259, - "y": 390, + "x": 390, + "y": 352, "w": 16, "h": 16 } @@ -7731,8 +7815,8 @@ "h": 16 }, "frame": { - "x": 259, - "y": 406, + "x": 374, + "y": 360, "w": 16, "h": 16 } @@ -7752,8 +7836,8 @@ "h": 16 }, "frame": { - "x": 275, - "y": 390, + "x": 390, + "y": 368, "w": 16, "h": 16 } @@ -7773,8 +7857,8 @@ "h": 16 }, "frame": { - "x": 275, - "y": 406, + "x": 406, + "y": 336, "w": 16, "h": 16 } @@ -7794,8 +7878,8 @@ "h": 16 }, "frame": { - "x": 292, - "y": 372, + "x": 406, + "y": 352, "w": 16, "h": 16 } @@ -7815,8 +7899,8 @@ "h": 16 }, "frame": { - "x": 308, - "y": 371, + "x": 406, + "y": 368, "w": 16, "h": 16 } @@ -7836,8 +7920,8 @@ "h": 16 }, "frame": { - "x": 324, - "y": 371, + "x": 311, + "y": 364, "w": 16, "h": 16 } @@ -7857,8 +7941,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 369, + "x": 327, + "y": 364, "w": 16, "h": 16 } @@ -7878,8 +7962,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 369, + "x": 311, + "y": 380, "w": 16, "h": 16 } @@ -7899,8 +7983,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 370, + "x": 343, + "y": 364, "w": 16, "h": 16 } @@ -7920,8 +8004,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 370, + "x": 311, + "y": 396, "w": 16, "h": 16 } @@ -7941,8 +8025,8 @@ "h": 16 }, "frame": { - "x": 292, - "y": 388, + "x": 311, + "y": 412, "w": 16, "h": 16 } @@ -7962,8 +8046,8 @@ "h": 16 }, "frame": { - "x": 308, - "y": 387, + "x": 327, + "y": 380, "w": 16, "h": 16 } @@ -7983,8 +8067,8 @@ "h": 16 }, "frame": { - "x": 324, - "y": 387, + "x": 327, + "y": 396, "w": 16, "h": 16 } @@ -8004,8 +8088,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 385, + "x": 327, + "y": 412, "w": 16, "h": 16 } @@ -8025,8 +8109,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 385, + "x": 343, + "y": 380, "w": 16, "h": 16 } @@ -8046,8 +8130,8 @@ "h": 16 }, "frame": { - "x": 291, - "y": 404, + "x": 343, + "y": 396, "w": 16, "h": 16 } @@ -8067,8 +8151,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 386, + "x": 343, + "y": 412, "w": 16, "h": 16 } @@ -8088,8 +8172,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 386, + "x": 359, + "y": 376, "w": 16, "h": 16 } @@ -8109,8 +8193,8 @@ "h": 16 }, "frame": { - "x": 404, - "y": 382, + "x": 359, + "y": 392, "w": 16, "h": 16 } @@ -8130,8 +8214,8 @@ "h": 16 }, "frame": { - "x": 404, - "y": 398, + "x": 359, + "y": 408, "w": 16, "h": 16 } @@ -8151,8 +8235,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 401, + "x": 375, + "y": 384, "w": 16, "h": 16 } @@ -8172,8 +8256,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 401, + "x": 375, + "y": 400, "w": 16, "h": 16 } @@ -8193,8 +8277,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 402, + "x": 391, + "y": 384, "w": 16, "h": 16 } @@ -8214,8 +8298,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 402, + "x": 391, + "y": 400, "w": 16, "h": 16 } @@ -8226,6 +8310,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:4669e332ee400e355936594c14e7221c:1a1f5a801c94e8eb8589e13bc50105a1:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:ae06b70c6800597c7ac11beefc1d8aad:b9f30512e12737247c8cb2691252baac:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 9de02d9e0e9..a031b00ceb0 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d1a324a43a6..44b0d1ba773 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2474,34 +2474,33 @@ export default class BattleScene extends SceneBase { modifier.stackCount = stackCount; // TODO: set isTransferable // modifier.setIsTransferable(isTransferable); - this.addEnemyModifier(modifier, false, true); + this.addEnemyModifier(modifier, true); }); - } - - const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss); - let upgradeChance = 32; - if (isBoss) { - upgradeChance /= 2; - } - if (isFinalBoss) { - upgradeChance /= 8; - } - const modifierChance = this.gameMode.getEnemyModifierChance(isBoss); - let pokemonModifierChance = modifierChance; - if (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer) - pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line - let count = 0; - for (let c = 0; c < chances; c++) { - if (!Utils.randSeedInt(modifierChance)) { - count++; + } else { + const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && !!this.currentBattle.trainer?.config.isBoss); + let upgradeChance = 32; + if (isBoss) { + upgradeChance /= 2; } + if (isFinalBoss) { + upgradeChance /= 8; + } + const modifierChance = this.gameMode.getEnemyModifierChance(isBoss); + let pokemonModifierChance = modifierChance; + if (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer) + pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line + let count = 0; + for (let c = 0; c < chances; c++) { + if (!Utils.randSeedInt(modifierChance)) { + count++; + } + } + if (isBoss) { + 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)); } - if (isBoss) { - 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)); - return true; }); this.updateModifiers(false).then(() => resolve()); @@ -2786,7 +2785,7 @@ export default class BattleScene extends SceneBase { } // Check for queued encounters first - if (!encounter && this.mysteryEncounterData?.nextEncounterQueue?.length > 0) { + if (!encounter && this.mysteryEncounterData?.nextEncounterQueue && this.mysteryEncounterData.nextEncounterQueue.length > 0) { let i = 0; while (i < this.mysteryEncounterData.nextEncounterQueue.length && !!encounter) { const candidate = this.mysteryEncounterData.nextEncounterQueue[i]; @@ -2801,7 +2800,7 @@ export default class BattleScene extends SceneBase { if (encounter) { encounter = new MysteryEncounter(encounter); - encounter.populateDialogueTokensFromRequirements!(this); + encounter.populateDialogueTokensFromRequirements(this); return encounter; } diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index 4dbab6666f0..9f5b85801fe 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -440,7 +440,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent { scene.field.add(moveAnim.bgSprite); const fieldPokemon = scene.getEnemyPokemon() || scene.getPlayerPokemon(); if (!isNullOrUndefined(priority)) { - scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority); + scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority!); } else if (fieldPokemon?.isOnField()) { scene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon); } @@ -540,7 +540,7 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise { export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise { const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim]; const encounterAnimNames = Utils.getEnumKeys(EncounterAnim); - const encounterAnimFetches = []; + const encounterAnimFetches: Promise>[] = []; for (const anim of anims) { if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) { continue; @@ -806,7 +806,7 @@ export abstract class BattleAnim { play(scene: BattleScene, 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; + const target = !isOppAnim ? this.target! : this.user!; if (!target?.isOnField() && !this.playOnEmptyField) { if (callback) { @@ -1052,7 +1052,7 @@ export abstract class BattleAnim { y += targetInitialY; const angle = -frame.angle; const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++; - ret.get(frame.target).set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); + ret.get(frame.target)?.set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); } return ret; @@ -1102,17 +1102,17 @@ export abstract class BattleAnim { this.srcLine = [ userFocusX, userFocusY, targetFocusX, targetFocusY ]; this.dstLine = [ 150, 75, targetInitialX, targetInitialY ]; - let r = anim.frames.length; + let r = anim!.frames.length; let f = 0; const existingFieldSprites = [...scene.field.getAll()]; scene.tweens.addCounter({ duration: Utils.getFrameMs(3) * frameTimeMult, - repeat: anim.frames.length, + repeat: anim!.frames.length, onRepeat: () => { - const spriteFrames = anim.frames[f]; - const frameData = this.getGraphicFrameDataWithoutTarget(anim.frames[f], targetInitialX, targetInitialY); + const spriteFrames = anim!.frames[f]; + const frameData = this.getGraphicFrameDataWithoutTarget(anim!.frames[f], targetInitialX, targetInitialY); const u = 0; const t = 0; let g = 0; @@ -1124,7 +1124,7 @@ export abstract class BattleAnim { const sprites = spriteCache[AnimFrameTarget.GRAPHIC]; if (g === sprites.length) { - const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim.graphic, 1); + const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim!.graphic, 1); sprites.push(newSprite); scene.field.add(newSprite); spritePriorities.push(1); @@ -1147,17 +1147,19 @@ export abstract class BattleAnim { } moveSprite.setFrame(frame.graphicFrame); - const graphicFrameData = frameData.get(frame.target).get(graphicIndex); - moveSprite.setPosition(graphicFrameData.x, graphicFrameData.y); - moveSprite.setAngle(graphicFrameData.angle); - moveSprite.setScale(graphicFrameData.scaleX, graphicFrameData.scaleY); + const graphicFrameData = frameData.get(frame.target)?.get(graphicIndex); + if (graphicFrameData) { + moveSprite.setPosition(graphicFrameData.x, graphicFrameData.y); + moveSprite.setAngle(graphicFrameData.angle); + moveSprite.setScale(graphicFrameData.scaleX, graphicFrameData.scaleY); - moveSprite.setAlpha(frame.opacity / 255); - moveSprite.setVisible(frame.visible); - moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE); + moveSprite.setAlpha(frame.opacity / 255); + moveSprite.setVisible(frame.visible); + moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE); + } } - if (anim.frameTimedEvents.has(f)) { - for (const event of anim.frameTimedEvents.get(f)) { + if (anim?.frameTimedEvents.get(f)) { + for (const event of anim.frameTimedEvents.get(f)!) { r = Math.max((anim.frames.length - f) + event.execute(scene, this, frameTimedEventPriority), r); } } @@ -1277,8 +1279,8 @@ export class EncounterBattleAnim extends BattleAnim { this.oppAnim = oppAnim ?? false; } - getAnim(): AnimConfig { - return encounterAnims.get(this.encounterAnim); + getAnim(): AnimConfig | null { + return encounterAnims.get(this.encounterAnim) ?? null; } isOppAnim(): boolean { diff --git a/src/data/egg.ts b/src/data/egg.ts index 9f5e8cb1edf..1406ff9d869 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -86,7 +86,7 @@ export class Egg { private _overrideHiddenAbility: boolean; - private _eventEggTypeDescriptor: string; + private _eventEggTypeDescriptor?: string; //// // #endregion @@ -186,7 +186,7 @@ export class Egg { this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct? } - this._eventEggTypeDescriptor = eggOptions.eventEggTypeDescriptor ?? null; + this._eventEggTypeDescriptor = eggOptions?.eventEggTypeDescriptor; } //// diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts index d42d4051aa6..6cd0e8fe0ea 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -76,13 +76,13 @@ export const ATrainersTestEncounter: MysteryEncounter = text: `${namespace}.${trainerNameKey}.intro_dialogue` } ]; - encounter.options[0].dialogue.selected = [ + encounter.options[0].dialogue!.selected = [ { speaker: `trainerNames:${trainerNameKey}`, text: `${namespace}.${trainerNameKey}.accept` } ]; - encounter.options[1].dialogue.selected = [ + encounter.options[1].dialogue!.selected = [ { speaker: `trainerNames:${trainerNameKey}`, text: `${namespace}.${trainerNameKey}.decline` diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index 4cc3648beae..c8706d18d31 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -22,6 +22,7 @@ import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPo import { TrainerSlot } from "#app/data/trainer-config"; import { PokeballType } from "#app/data/pokeball"; import HeldModifierConfig from "#app/interfaces/held-modifier-config"; +import { BerryType } from "#enums/berry-type"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounter:absoluteAvarice"; @@ -39,8 +40,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = .withIntroSpriteConfigs([ { // This sprite has the shadow - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.GREEDENT, hasShadow: true, alpha: 0.001, @@ -48,8 +49,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = x: -5 }, { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.GREEDENT, hasShadow: false, repeat: true, @@ -254,7 +255,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = queueEncounterMessage(scene, `${namespace}.option.1.food_stash`); }; - setEncounterRewards(scene, { fillRemaining: true }, null, givePartyPokemonReviverSeeds); + setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds); encounter.startOfBattleEffects.push({ sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.ENEMY], @@ -287,7 +288,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = const party = scene.getParty(); party.forEach(pokemon => { const stolenBerries: BerryModifier[] = berryMap.get(pokemon.id); - const berryTypesAsArray = []; + const berryTypesAsArray: BerryType[] = []; stolenBerries?.forEach(bMod => berryTypesAsArray.push(...new Array(bMod.stackCount).fill(bMod.berryType))); const returnedBerryCount = Math.floor((berryTypesAsArray.length ?? 0) * 2 / 5); @@ -330,7 +331,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = // Let it have the food // Greedent joins the team, level equal to 2 below highest party member const level = getHighestLevelPlayerPokemon(scene).level - 2; - const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false, null); + const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false); greedent.moveset = [new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF)]; greedent.passive = true; @@ -346,7 +347,7 @@ function doGreedentSpriteSteal(scene: BattleScene) { const shakeDelay = 50; const slideDelay = 500; - const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals.getSpriteAtIndex(1); + const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals?.getSpriteAtIndex(1); scene.playSound("Follow Me"); scene.tweens.chain({ @@ -420,7 +421,7 @@ function doGreedentSpriteSteal(scene: BattleScene) { } function doGreedentEatBerries(scene: BattleScene) { - const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals.getSpriteAtIndex(1); + const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals?.getSpriteAtIndex(1); let index = 1; scene.tweens.add({ targets: greedentSprites, @@ -455,7 +456,12 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) { const encounter = scene.currentBattle.mysteryEncounter; animationOrder.forEach((berry, i) => { const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry)); - const [ sprite, tintSprite ] = encounter.introVisuals.getSpriteAtIndex(introVisualsIndex); + let sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite; + const sprites = encounter.introVisuals?.getSpriteAtIndex(introVisualsIndex); + if (sprites) { + sprite = sprites[0]; + tintSprite = sprites[1]; + } scene.time.delayedCall(berryAddDelay * i + 400, () => { if (sprite) { sprite.setVisible(!isEat); diff --git a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts index 4e96b9f52d4..1ee1704c8b4 100644 --- a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts +++ b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts @@ -136,7 +136,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = // Update money and remove pokemon from party updatePlayerMoney(scene, encounter.misc.price); - setEncounterExp(scene, encounter.options[1].primaryPokemon.id, getPokemonSpecies(Species.LIEPARD).baseExp, true); + setEncounterExp(scene, encounter.options[1].primaryPokemon!.id, getPokemonSpecies(Species.LIEPARD).baseExp, true); leaveEncounterWithoutBattle(scene, true); }) diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index 6e75526076a..7e8279f383b 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -146,7 +146,7 @@ export const BerriesAboundEncounter: MysteryEncounter = // Calculate boss mon const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true); - const bossPokemon = new EnemyPokemon(scene, bossSpecies, scene.currentBattle.waveIndex, TrainerSlot.NONE, true, null); + const bossPokemon = new EnemyPokemon(scene, bossSpecies, scene.currentBattle.waveIndex, TrainerSlot.NONE, true); encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon)); const config: EnemyPartyConfig = { levelAdditiveMultiplier: 1, @@ -222,7 +222,7 @@ export const BerriesAboundEncounter: MysteryEncounter = shopOptions.push(generateModifierTypeOption(scene, modifierTypes.BERRY)); } - setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, null, doBerryRewards); + setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards); await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); } ) @@ -262,12 +262,12 @@ export const BerriesAboundEncounter: MysteryEncounter = }; const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; - config.pokemonConfigs[0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { + 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 StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1)); }; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, null, doBerryRewards); + setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards); await showEncounterText(scene, `${namespace}.option.2.selected_bad`); await initBattleWithEnemyConfig(scene, config); return; @@ -287,8 +287,8 @@ export const BerriesAboundEncounter: MysteryEncounter = } }; - setEncounterExp(scene, fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs[0].species.baseExp); - setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, null, doFasterBerryRewards); + 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); } diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index 85fbc2d2f18..c9c1f0dd335 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -1,4 +1,4 @@ -import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, } from "#app/data/trainer-config"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; @@ -28,7 +28,6 @@ import { BattlerIndex } from "#app/battle"; import { Moves } from "#enums/moves"; import { EncounterAnim, EncounterBattleAnim } from "#app/data/battle-anims"; import { MoveCategory } from "#app/data/move"; -import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:clowningAround"; @@ -129,7 +128,7 @@ export const ClowningAroundEncounter: MysteryEncounter = }, { // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter species: getPokemonSpecies(Species.BLACEPHALON), - mysteryEncounterData: new MysteryEncounterPokemonData(null, ability, null, [randSeedInt(18), randSeedInt(18)]), + mysteryEncounterData: new MysteryEncounterPokemonData(undefined, ability, undefined, [randSeedInt(18), randSeedInt(18)]), isBoss: true, moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] }, @@ -206,7 +205,7 @@ export const ClowningAroundEncounter: MysteryEncounter = ease: "Sine.easeInOut", duration: 250 }); - const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon()); + const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon()); background.playWithoutTargets(scene, 230, 40, 2); return true; }) @@ -292,7 +291,7 @@ export const ClowningAroundEncounter: MysteryEncounter = }) .withPostOptionPhase(async (scene: BattleScene) => { // Play animations - const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon()); + const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon()); background.playWithoutTargets(scene, 230, 40, 2); await transitionMysteryEncounterIntroVisuals(scene); }) @@ -327,8 +326,8 @@ export const ClowningAroundEncounter: MysteryEncounter = // If the Pokemon has non-status moves that don't match the Pokemon's type, prioritizes those as the new type // Makes the "randomness" of the shuffle slightly less punishing let priorityTypes = pokemon.moveset - .filter(move => !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS) - .map(move => move.getMove().type); + .filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS) + .map(move => move!.getMove().type); if (priorityTypes?.length > 0) { priorityTypes = [...new Set(priorityTypes)]; randSeedShuffle(priorityTypes); @@ -350,7 +349,7 @@ export const ClowningAroundEncounter: MysteryEncounter = } if (!pokemon.mysteryEncounterData) { - pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(null, null, null, newTypes); + pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(undefined, undefined, undefined, newTypes); } else { pokemon.mysteryEncounterData.types = newTypes; } @@ -361,7 +360,7 @@ export const ClowningAroundEncounter: MysteryEncounter = }) .withPostOptionPhase(async (scene: BattleScene) => { // Play animations - const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon()); + const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon()!, scene.getPlayerPokemon()); background.playWithoutTargets(scene, 230, 40, 2); await transitionMysteryEncounterIntroVisuals(scene); }) @@ -441,8 +440,7 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem [modifierTypes.GOLDEN_PUNCH, 5], [modifierTypes.ATTACK_TYPE_BOOSTER, 99], [modifierTypes.QUICK_CLAW, 3], - [modifierTypes.WIDE_LENS, 3], - [modifierTypes.WHITE_HERB, 2] + [modifierTypes.WIDE_LENS, 3] ]; const roguePool = [ @@ -450,7 +448,7 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem [modifierTypes.SHELL_BELL, 4], [modifierTypes.SOUL_DEW, 10], [modifierTypes.SOOTHE_BELL, 3], - [modifierTypes.SCOPE_LENS, 5], + [modifierTypes.SCOPE_LENS, 1], [modifierTypes.BATON, 1], [modifierTypes.FOCUS_BAND, 5], [modifierTypes.KINGS_ROCK, 3], diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index ede6ecf5462..35b52c15c5a 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -87,7 +87,7 @@ export const DancingLessonsEncounter: MysteryEncounter = .withAutoHideIntroVisuals(false) .withCatchAllowed(true) .withOnVisualsStart((scene: BattleScene) => { - const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon(), scene.getPlayerPokemon()); + const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getPlayerPokemon()); danceAnim.play(scene); return true; @@ -104,8 +104,8 @@ export const DancingLessonsEncounter: MysteryEncounter = const encounter = scene.currentBattle.mysteryEncounter; const species = getPokemonSpecies(Species.ORICORIO); - const enemyPokemon = scene.addEnemyPokemon(species, scene.currentBattle.enemyLevels[0], TrainerSlot.NONE, false); - if (!enemyPokemon.moveset.some(m => m.getMove().id === Moves.REVELATION_DANCE)) { + const enemyPokemon = scene.addEnemyPokemon(species, scene.currentBattle.enemyLevels![0], 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)); } else { @@ -206,7 +206,7 @@ export const DancingLessonsEncounter: MysteryEncounter = scene.unshiftPhase(new LearnMovePhase(scene, scene.getParty().indexOf(pokemon), Moves.REVELATION_DANCE)); // Play animation again to "learn" the dance - const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon(), scene.getPlayerPokemon()); + const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getPlayerPokemon()); danceAnim.play(scene); }; @@ -239,7 +239,7 @@ export const DancingLessonsEncounter: MysteryEncounter = const onPokemonSelected = (pokemon: PlayerPokemon) => { // Return the options for nature selection return pokemon.moveset - .filter(move => DANCING_MOVES.includes(move.getMove().id)) + .filter(move => move && DANCING_MOVES.includes(move.getMove().id)) .map((move: PokemonMove) => { const option: OptionSelectItem = { label: move.getName(), @@ -261,13 +261,13 @@ export const DancingLessonsEncounter: MysteryEncounter = // If pokemon meets primary pokemon reqs, it can be selected const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { // Show the Oricorio a dance, and recruit it diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 336d95bd156..bcb742f01d0 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -47,8 +47,8 @@ export const DelibirdyEncounter: MysteryEncounter = )) .withIntroSpriteConfigs([ { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.DELIBIRD, hasShadow: true, repeat: true, @@ -56,16 +56,16 @@ export const DelibirdyEncounter: MysteryEncounter = scale: 0.94 }, { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.DELIBIRD, hasShadow: true, repeat: true, scale: 1.06 }, { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.DELIBIRD, hasShadow: true, repeat: true, @@ -116,7 +116,7 @@ export const DelibirdyEncounter: MysteryEncounter = const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType; await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell); scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true); } else { scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM)); } @@ -169,13 +169,13 @@ export const DelibirdyEncounter: MysteryEncounter = // If pokemon meets primary pokemon reqs, it can be selected const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(scene, pokemon); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; @@ -191,7 +191,7 @@ export const DelibirdyEncounter: MysteryEncounter = const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType; await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell); scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true); } else { scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR)); } @@ -204,7 +204,7 @@ export const DelibirdyEncounter: MysteryEncounter = const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType; await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell); scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true); } else { scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM)); } @@ -264,13 +264,13 @@ export const DelibirdyEncounter: MysteryEncounter = // If pokemon meets primary pokemon reqs, it can be selected const meetsReqs = encounter.options[2].pokemonMeetsPrimaryRequirements(scene, pokemon); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; @@ -284,7 +284,7 @@ export const DelibirdyEncounter: MysteryEncounter = const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType; await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell); scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true); } else { scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH)); } diff --git a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts index 9a11a2e8888..09c991ee4a3 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts @@ -2,7 +2,7 @@ import { leaveEncounterWithoutBattle, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { modifierTypes } from "#app/modifier/modifier-type"; +import { ModifierTypeFunc, modifierTypes } from "#app/modifier/modifier-type"; import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; @@ -32,8 +32,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = x: -20, }, { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.FURFROU, hasShadow: true, repeat: true, @@ -60,7 +60,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = }, async (scene: BattleScene) => { // Choose TMs - const modifiers = []; + const modifiers: ModifierTypeFunc[] = []; let i = 0; while (i < 4) { // 2/2/1 weight on TM rarity @@ -86,7 +86,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = }, async (scene: BattleScene) => { // Choose Vitamins - const modifiers = []; + const modifiers: ModifierTypeFunc[] = []; let i = 0; while (i < 3) { // 2/1 weight on base stat booster vs PP Up @@ -110,7 +110,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = }, async (scene: BattleScene) => { // Choose X Items - const modifiers = []; + const modifiers: ModifierTypeFunc[] = []; let i = 0; while (i < 5) { // 4/1 weight on base stat booster vs Dire Hit @@ -134,7 +134,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = }, async (scene: BattleScene) => { // Choose Pokeballs - const modifiers = []; + const modifiers: ModifierTypeFunc[] = []; let i = 0; while (i < 4) { // 10/30/20/5 weight on pokeballs diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 5024ba3c361..ca6f7424dc8 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -78,7 +78,7 @@ export const FieldTripEncounter: MysteryEncounter = const correctMove = move.getMove().category === MoveCategory.PHYSICAL; encounter.setDialogueToken("moveCategory", "Physical"); if (!correctMove) { - encounter.options[0].dialogue.selected = [ + encounter.options[0].dialogue!.selected = [ { text: `${namespace}.option.incorrect`, speaker: `${namespace}.speaker`, @@ -97,7 +97,7 @@ export const FieldTripEncounter: MysteryEncounter = } else { encounter.setDialogueToken("pokeName", pokemon.getNameToRender()); encounter.setDialogueToken("move", move.getName()); - encounter.options[0].dialogue.selected = [ + encounter.options[0].dialogue!.selected = [ { text: `${namespace}.option.selected`, }, @@ -164,7 +164,7 @@ export const FieldTripEncounter: MysteryEncounter = const correctMove = move.getMove().category === MoveCategory.SPECIAL; encounter.setDialogueToken("moveCategory", "Special"); if (!correctMove) { - encounter.options[1].dialogue.selected = [ + encounter.options[1].dialogue!.selected = [ { text: `${namespace}.option.incorrect`, speaker: `${namespace}.speaker`, @@ -189,7 +189,7 @@ export const FieldTripEncounter: MysteryEncounter = } else { encounter.setDialogueToken("pokeName", pokemon.getNameToRender()); encounter.setDialogueToken("move", move.getName()); - encounter.options[1].dialogue.selected = [ + encounter.options[1].dialogue!.selected = [ { text: `${namespace}.option.selected`, }, @@ -256,7 +256,7 @@ export const FieldTripEncounter: MysteryEncounter = const correctMove = move.getMove().category === MoveCategory.STATUS; encounter.setDialogueToken("moveCategory", "Status"); if (!correctMove) { - encounter.options[2].dialogue.selected = [ + encounter.options[2].dialogue!.selected = [ { text: `${namespace}.option.incorrect`, speaker: `${namespace}.speaker`, @@ -275,7 +275,7 @@ export const FieldTripEncounter: MysteryEncounter = } else { encounter.setDialogueToken("pokeName", pokemon.getNameToRender()); encounter.setDialogueToken("move", move.getName()); - encounter.options[2].dialogue.selected = [ + encounter.options[2].dialogue!.selected = [ { text: `${namespace}.option.selected`, }, diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index 99919b09e3c..1eea328927b 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -75,8 +75,8 @@ export const FieryFalloutEncounter: MysteryEncounter = // Load hidden Volcarona sprites encounter.spriteConfigs = [ { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.VOLCARONA, repeat: true, hidden: true, @@ -85,8 +85,8 @@ export const FieryFalloutEncounter: MysteryEncounter = startFrame: 20 }, { - spriteKey: null, - fileRoot: null, + spriteKey: "", + fileRoot: "", species: Species.VOLCARONA, repeat: true, hidden: true, @@ -104,9 +104,9 @@ export const FieryFalloutEncounter: MysteryEncounter = }) .withOnVisualsStart((scene: BattleScene) => { // Play animations - const background = new EncounterBattleAnim(EncounterAnim.MAGMA_BG, scene.getPlayerPokemon(), scene.getPlayerPokemon()); + 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()); + 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); @@ -133,7 +133,7 @@ export const FieryFalloutEncounter: MysteryEncounter = async (scene: BattleScene) => { // Pick battle const encounter = scene.currentBattle.mysteryEncounter; - setEncounterRewards(scene, { fillRemaining: true }, null, () => giveLeadPokemonCharcoal(scene)); + setEncounterRewards(scene, { fillRemaining: true }, undefined, () => giveLeadPokemonCharcoal(scene)); encounter.startOfBattleEffects.push( { @@ -185,7 +185,7 @@ export const FieryFalloutEncounter: MysteryEncounter = } // Burn random member - const burnable = nonFireTypes.filter(p => isNullOrUndefined(p.status) || isNullOrUndefined(p.status.effect) || p.status?.effect === StatusEffect.BURN); + const burnable = nonFireTypes.filter(p => isNullOrUndefined(p.status) || isNullOrUndefined(p.status!.effect) || p.status?.effect === StatusEffect.BURN); if (burnable?.length > 0) { const roll = randSeedInt(burnable.length); const chosenPokemon = burnable[roll]; @@ -224,13 +224,13 @@ export const FieryFalloutEncounter: MysteryEncounter = transitionMysteryEncounterIntroVisuals(scene); setEncounterRewards(scene, { fillRemaining: true }, - null, + undefined, () => { giveLeadPokemonCharcoal(scene); }); - const primary = encounter.options[2].primaryPokemon; - const secondary = encounter.options[2].secondaryPokemon[0]; + const primary = encounter.options[2].primaryPokemon!; + const secondary = encounter.options[2].secondaryPokemon![0]; setEncounterExp(scene, [primary.id, secondary.id], getPokemonSpecies(Species.VOLCARONA).baseExp * 2); leaveEncounterWithoutBattle(scene); diff --git a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts index 10d9f21e8bb..616c81880df 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts @@ -50,7 +50,7 @@ export const FightOrFlightEncounter: MysteryEncounter = // Calculate boss mon const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true); - const bossPokemon = new EnemyPokemon(scene, bossSpecies, scene.currentBattle.waveIndex, TrainerSlot.NONE, true, null); + const bossPokemon = new EnemyPokemon(scene, bossSpecies, scene.currentBattle.waveIndex, TrainerSlot.NONE, true); const config: EnemyPartyConfig = { levelAdditiveMultiplier: 1, pokemonConfigs: [{ @@ -72,7 +72,7 @@ export const FightOrFlightEncounter: MysteryEncounter = ? ModifierTier.ULTRA : ModifierTier.GREAT; regenerateModifierPoolThresholds(scene.getParty(), ModifierPoolType.PLAYER, 0); - let item: ModifierTypeOption; + let item: ModifierTypeOption | null = null; // TMs excluded from possible rewards as they're too swingy in value for a singular item reward while (!item || item.type.id.includes("TM_")) { item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier], allowLuckUpgrades: false })[0]; @@ -147,8 +147,8 @@ export const FightOrFlightEncounter: MysteryEncounter = setEncounterRewards(scene, { 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); + const primaryPokemon = encounter.options[1].primaryPokemon!; + setEncounterExp(scene, primaryPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp); leaveEncounterWithoutBattle(scene); }) .build() diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index f3738059b0b..1695466c1cd 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -87,6 +87,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = const e4Template = trainerPartyTemplates.ELITE_FOUR; const brutalConfig = trainerConfigs[brutalTrainerType].copy(); brutalConfig.setPartyTemplates(e4Template); + // @ts-ignore brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func female = false; if (brutalConfig.hasGenders) { diff --git a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts index e4616c6f169..303beb57aae 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts @@ -57,7 +57,7 @@ export const MysteriousChestEncounter: MysteryEncounter = .withPreOptionPhase(async (scene: BattleScene) => { // Play animation const introVisuals = - scene.currentBattle.mysteryEncounter.introVisuals; + scene.currentBattle.mysteryEncounter.introVisuals!; introVisuals.spriteConfigs[0].disableAnimation = false; introVisuals.playAnim(); }) diff --git a/src/data/mystery-encounters/encounters/part-timer-encounter.ts b/src/data/mystery-encounters/encounters/part-timer-encounter.ts index 861e0bc0e8f..a17a47f23fe 100644 --- a/src/data/mystery-encounters/encounters/part-timer-encounter.ts +++ b/src/data/mystery-encounters/encounters/part-timer-encounter.ts @@ -100,8 +100,10 @@ export const PartTimerEncounter: MysteryEncounter = // Reduce all PP to 2 (if they started at greater than 2) pokemon.moveset.forEach(move => { - const newPpUsed = move.getMovePp() - 2; - move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + if (move) { + const newPpUsed = move.getMovePp() - 2; + move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + } }); setEncounterExp(scene, pokemon.id, 100); @@ -115,13 +117,13 @@ export const PartTimerEncounter: MysteryEncounter = // Only Pokemon non-KOd pokemon can be selected const selectableFilter = (pokemon: Pokemon) => { if (!pokemon.isAllowedInBattle()) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { // Pick Deliveries @@ -179,8 +181,10 @@ export const PartTimerEncounter: MysteryEncounter = // Reduce all PP to 2 (if they started at greater than 2) pokemon.moveset.forEach(move => { - const newPpUsed = move.getMovePp() - 2; - move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + if (move) { + const newPpUsed = move.getMovePp() - 2; + move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + } }); setEncounterExp(scene, pokemon.id, 100); @@ -194,13 +198,13 @@ export const PartTimerEncounter: MysteryEncounter = // Only Pokemon non-KOd pokemon can be selected const selectableFilter = (pokemon: Pokemon) => { if (!pokemon.isAllowedInBattle()) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { // Pick Move Warehouse items @@ -241,13 +245,15 @@ export const PartTimerEncounter: MysteryEncounter = }) .withPreOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; - const selectedPokemon = encounter.selectedOption.primaryPokemon; + const selectedPokemon = encounter.selectedOption?.primaryPokemon!; encounter.setDialogueToken("selectedPokemon", selectedPokemon.getNameToRender()); // Reduce all PP to 2 (if they started at greater than 2) selectedPokemon.moveset.forEach(move => { - const newPpUsed = move.getMovePp() - 2; - move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + if (move) { + const newPpUsed = move.getMovePp() - 2; + move.ppUsed = move.ppUsed < newPpUsed ? newPpUsed : move.ppUsed; + } }); setEncounterExp(scene, selectedPokemon.id, 100); diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index 66f286653b9..a83d76a7cfa 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -172,9 +172,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [ // 80% chance to increase flee stage +1 const fleeChangeResult = tryChangeFleeStage(scene, 1, 8); if (!fleeChangeResult) { - await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.busy_eating`), 1000, false ); + await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.busy_eating`) ?? "", 1000, false ); } else { - await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.eating`), 1000, false); + await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.eating`) ?? "", 1000, false); } await doEndTurn(scene, 1); @@ -201,9 +201,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [ // 80% chance to decrease catch stage -1 const catchChangeResult = tryChangeCatchStage(scene, -1, 8); if (!catchChangeResult) { - await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.beside_itself_angry`), 1000, false ); + await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.beside_itself_angry`) ?? "", 1000, false ); } else { - await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.angry`), 1000, false ); + await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.angry`) ?? "", 1000, false ); } await doEndTurn(scene, 2); @@ -239,7 +239,7 @@ async function summonSafariPokemon(scene: BattleScene) { const encounter = scene.currentBattle.mysteryEncounter; // Message pokemon remaining encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining); - scene.queueMessage(getEncounterText(scene, `${namespace}.safari.remaining_count`), null, true); + scene.queueMessage(getEncounterText(scene, `${namespace}.safari.remaining_count`) ?? "", null, true); // Generate pokemon using safariPokemonRemaining so they are always the same pokemon no matter how many turns are taken // Safari pokemon roll twice on shiny and HA chances, but are otherwise normal @@ -288,7 +288,7 @@ async function summonSafariPokemon(scene: BattleScene) { scene.unshiftPhase(new SummonPhase(scene, 0, false)); encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon)); - showEncounterText(scene, getEncounterText(scene, "battle:singleWildAppeared"), 1500, false) + showEncounterText(scene, getEncounterText(scene, "battle:singleWildAppeared") ?? "", 1500, false) .then(() => { const ivScannerModifier = scene.findModifier(m => m instanceof IvScannerModifier); if (ivScannerModifier) { @@ -494,7 +494,7 @@ async function doEndTurn(scene: BattleScene, cursorIndex: number) { leaveEncounterWithoutBattle(scene, true); } } else { - scene.queueMessage(getEncounterText(scene, `${namespace}.safari.watching`), 0, null, 1000); + scene.queueMessage(getEncounterText(scene, `${namespace}.safari.watching`) ?? "", 0, null, 1000); initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true }); } } diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts index 3e4fe49da43..2876ce64c8f 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -95,13 +95,13 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = // If pokemon meets primary pokemon reqs, it can be selected const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { // Choose Cheap Option @@ -178,13 +178,13 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = // If pokemon meets primary pokemon reqs, it can be selected const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { // Choose Expensive Option diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index 35ba52cdce7..f56823a3445 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -140,7 +140,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = const instance = scene.currentBattle.mysteryEncounter; setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false }); // Snorlax exp to Pokemon that did the stealing - setEncounterExp(scene, instance.primaryPokemon.id, getPokemonSpecies(Species.SNORLAX).baseExp); + setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp); leaveEncounterWithoutBattle(scene); }) .build() diff --git a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts index e44d03da8f5..9604783d3ff 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -29,7 +29,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_POKEMON_SALESMAN) .withEncounterTier(MysteryEncounterTier.ULTRA) .withSceneWaveRangeRequirement(10, 180) - .withSceneRequirement(new MoneyRequirement(null, MAX_POKEMON_PRICE_MULTIPLIER)) // Some costs may not be as significant, this is the max you'd pay + .withSceneRequirement(new MoneyRequirement(undefined, MAX_POKEMON_PRICE_MULTIPLIER)) // Some costs may not be as significant, this is the max you'd pay .withAutoHideIntroVisuals(false) .withIntroSpriteConfigs([ { @@ -66,10 +66,10 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = // If no HA mon found or you roll 1%, give shiny Magikarp species = getPokemonSpecies(Species.MAGIKARP); const hiddenIndex = species.ability2 ? 2 : 1; - pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex, null, true, null, null, null, null); + pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex, undefined, true); } else { const hiddenIndex = species.ability2 ? 2 : 1; - pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex, null, null, null, null, null, null); + pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex); } const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon); @@ -88,8 +88,8 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = // Always max price for shiny (flip HA back to normal), and add special messaging priceMultiplier = MAX_POKEMON_PRICE_MULTIPLIER; pokemon.abilityIndex = 0; - encounter.dialogue.encounterOptionsDialogue.description = `${namespace}.description_shiny`; - encounter.options[0].dialogue.buttonTooltip = `${namespace}.option.1.tooltip_shiny`; + encounter.dialogue.encounterOptionsDialogue!.description = `${namespace}.description_shiny`; + encounter.options[0].dialogue!.buttonTooltip = `${namespace}.option.1.tooltip_shiny`; } const price = scene.getWaveMoneyAmount(priceMultiplier); encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender()); @@ -107,7 +107,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .withHasDexProgress(true) - .withSceneMoneyRequirement(null, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2 + .withSceneMoneyRequirement(undefined, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2 .withDialogue({ buttonLabel: `${namespace}.option.1.label`, buttonTooltip: `${namespace}.option.1.tooltip`, diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index fd67d2a0234..4eaec2fdca2 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -127,7 +127,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = // -20 to all base stats of highest BST, +10 to all base stats of rest of party // Get highest BST mon const party = scene.getParty(); - let highestBst: PlayerPokemon = null; + let highestBst: PlayerPokemon | null = null; let statTotal = 0; for (const pokemon of party) { if (!highestBst) { @@ -157,7 +157,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = } encounter.setDialogueToken("highBstPokemon", highestBst.getNameToRender()); - await showEncounterText(scene, `${namespace}.option.1.selected_2`, null, true); + await showEncounterText(scene, `${namespace}.option.1.selected_2`, undefined, true); setEncounterRewards(scene, { fillRemaining: true }); leaveEncounterWithoutBattle(scene, true); diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index c0886ed9f6b..5ae6d86ecdb 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -140,7 +140,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) { await transitionMysteryEncounterIntroVisuals(scene, false, false); await showEncounterDialogue(scene, `${namespace}.victory`, `${namespace}.speaker`); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE], fillRemaining: false }); - encounter.doContinueEncounter = null; + encounter.doContinueEncounter = undefined; leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.TRAINER_BATTLE); } else { await initBattleWithEnemyConfig(scene, nextConfig); @@ -151,17 +151,21 @@ function endTrainerBattleAndShowDialogue(scene: BattleScene): Promise { return new Promise(async resolve => { if (scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length === 0) { // Battle is over - scene.tweens.add({ - targets: scene.currentBattle.trainer, - x: "+=16", - y: "-=16", - alpha: 0, - ease: "Sine.easeInOut", - duration: 750, - onComplete: () => { - scene.field.remove(scene.currentBattle.trainer, true); - } - }); + const trainer = scene.currentBattle.trainer; + if (trainer) { + scene.tweens.add({ + targets: trainer, + x: "+=16", + y: "-=16", + alpha: 0, + ease: "Sine.easeInOut", + duration: 750, + onComplete: () => { + scene.field.remove(trainer, true); + } + }); + } + await spawnNextTrainerOrEndEncounter(scene); resolve(); // Wait for all dialogue/post battle stuff to complete before resolving } else { @@ -186,18 +190,20 @@ function endTrainerBattleAndShowDialogue(scene: BattleScene): Promise { // Unassign previous trainer from battle so it isn't destroyed before animation completes scene.currentBattle.trainer = null; await spawnNextTrainerOrEndEncounter(scene); - scene.tweens.add({ - targets: trainer, - x: "+=16", - y: "-=16", - alpha: 0, - ease: "Sine.easeInOut", - duration: 750, - onComplete: () => { - scene.field.remove(trainer, true); - resolve(); - } - }); + if (trainer) { + scene.tweens.add({ + targets: trainer, + x: "+=16", + y: "-=16", + alpha: 0, + ease: "Sine.easeInOut", + duration: 750, + onComplete: () => { + scene.field.remove(trainer, true); + resolve(); + } + }); + } } }); } diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index e680268bc8f..54d48d4dcc5 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -6,11 +6,10 @@ import { Stat } from "#app/data/pokemon-stat"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import { pokemonInfo } from "#app/locales/en/pokemon-info"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; -import { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { AbilityAttr } from "#app/system/game-data"; import PokemonData from "#app/system/pokemon-data"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { randSeedShuffle } from "#app/utils"; +import { isNullOrUndefined, randSeedShuffle } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; @@ -19,6 +18,7 @@ import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import HeldModifierConfig from "#app/interfaces/held-modifier-config"; /** The i18n namespace for the encounter */ const namespace = "mysteryEncounter:trainingSession"; @@ -77,13 +77,13 @@ export const TrainingSessionEncounter: MysteryEncounter = const selectableFilter = (pokemon: Pokemon) => { const meetsReqs = pokemon.isAllowedInBattle(); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; @@ -125,7 +125,7 @@ export const TrainingSessionEncounter: MysteryEncounter = encounter.setDialogueToken("stat1", "-"); encounter.setDialogueToken("stat2", "-"); // Add the pokemon back to party with IV boost - const ivIndexes = []; + const ivIndexes: any[] = []; playerPokemon.ivs.forEach((iv, index) => { if (iv < 31) { ivIndexes.push({ iv: iv, index: index }); @@ -147,12 +147,12 @@ export const TrainingSessionEncounter: MysteryEncounter = if (improvedCount === 0) { encounter.setDialogueToken( "stat1", - getIvName(ivToChange.index) + getIvName(ivToChange.index) ?? "" ); } else { encounter.setDialogueToken( "stat2", - getIvName(ivToChange.index) + getIvName(ivToChange.index) ?? "" ); } @@ -185,12 +185,7 @@ export const TrainingSessionEncounter: MysteryEncounter = queueEncounterMessage(scene, `${namespace}.option.1.finished`); }; - setEncounterRewards( - scene, - { fillRemaining: true }, - null, - onBeforeRewardsPhase - ); + setEncounterRewards(scene, { fillRemaining: true }, undefined, onBeforeRewardsPhase); return initBattleWithEnemyConfig(scene, config); }) @@ -237,13 +232,13 @@ export const TrainingSessionEncounter: MysteryEncounter = const selectableFilter = (pokemon: Pokemon) => { const meetsReqs = pokemon.isAllowedInBattle(); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; @@ -278,12 +273,7 @@ export const TrainingSessionEncounter: MysteryEncounter = scene.updateModifiers(true); }; - setEncounterRewards( - scene, - { fillRemaining: true }, - null, - onBeforeRewardsPhase - ); + setEncounterRewards(scene, { fillRemaining: true }, undefined, onBeforeRewardsPhase); return initBattleWithEnemyConfig(scene, config); }) @@ -339,13 +329,13 @@ export const TrainingSessionEncounter: MysteryEncounter = const selectableFilter = (pokemon: Pokemon) => { const meetsReqs = pokemon.isAllowedInBattle(); if (!meetsReqs) { - return getEncounterText(scene, `${namespace}.invalid_selection`); + return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null; } return null; }; - return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); + return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter); }) .withOptionPhase(async (scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter; @@ -354,18 +344,10 @@ export const TrainingSessionEncounter: MysteryEncounter = // Spawn hard training session with chosen pokemon // Every 30 waves, add +1 boss segment, capping at 6 // Also starts with +1 to all stats - const segments = Math.min( - 2 + Math.floor(scene.currentBattle.waveIndex / 30), - 6 - ); + const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 30), 6); const modifiers = new ModifiersHolder(); - const config = getEnemyConfig( - scene, - playerPokemon, - segments, - modifiers - ); - config.pokemonConfigs[0].tags = [ + const config = getEnemyConfig(scene, playerPokemon, segments, modifiers); + config.pokemonConfigs![0].tags = [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON, ]; scene.removePokemonFromPlayerParty(playerPokemon, false); @@ -376,15 +358,10 @@ export const TrainingSessionEncounter: MysteryEncounter = const abilityIndex = encounter.misc.abilityIndex; if (!!playerPokemon.getFusionSpeciesForm()) { playerPokemon.fusionAbilityIndex = abilityIndex; - if ( - speciesStarters.hasOwnProperty( - playerPokemon.fusionSpecies.speciesId - ) - ) { - scene.gameData.starterData[ - playerPokemon.fusionSpecies.speciesId - ].abilityAttr |= - abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2 + if (!isNullOrUndefined(playerPokemon.fusionSpecies?.speciesId) && speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies!.speciesId)) { + scene.gameData.starterData[playerPokemon.fusionSpecies!.speciesId] + .abilityAttr |= + abilityIndex !== 1 || playerPokemon.fusionSpecies!.ability2 ? Math.pow(2, playerPokemon.fusionAbilityIndex) : AbilityAttr.ABILITY_HIDDEN; } @@ -414,12 +391,7 @@ export const TrainingSessionEncounter: MysteryEncounter = scene.updateModifiers(true); }; - setEncounterRewards( - scene, - { fillRemaining: true }, - null, - onBeforeRewardsPhase - ); + setEncounterRewards(scene, { fillRemaining: true }, undefined, onBeforeRewardsPhase); return initBattleWithEnemyConfig(scene, config); }) @@ -432,7 +404,11 @@ function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon,segment // Passes modifiers by reference modifiers.value = scene.findModifiers((m) => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === playerPokemon.id) as PokemonHeldItemModifier[]; - const modifierTypes = modifiers.value.map((mod) => mod.type) as PokemonHeldItemModifierType[]; + const modifierConfigs = modifiers.value.map((mod) => { + return { + modifierType: mod.type + }; + }) as HeldModifierConfig[]; const data = new PokemonData(playerPokemon); return { @@ -444,7 +420,7 @@ function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon,segment formIndex: playerPokemon.formIndex, level: playerPokemon.level, dataSource: data, - modifierConfigs: modifierTypes, + modifierConfigs: modifierConfigs, }, ], }; diff --git a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts index 50de002e053..d8c95761952 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -178,7 +178,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) { } scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), undefined, true); // First Shell bell for (const pokemon of party) { @@ -205,7 +205,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) { } scene.playSound("item_fanfare"); - await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), null, true); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), undefined, true); } async function doGarbageDig(scene: BattleScene) { diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 99d732f3107..d4ec3ab3c04 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -8,7 +8,7 @@ import { leaveEncounterWithoutBattle, setEncounterRewards, } from "../utils/enco import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; -import { IntegerHolder, randSeedInt, randSeedShuffle } from "#app/utils"; +import { IntegerHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { HiddenAbilityRateBoosterModifier, PokemonBaseStatTotalModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { achvs } from "#app/system/achv"; @@ -362,7 +362,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon } newTypes.push(newType); if (!newPokemon.mysteryEncounterData) { - newPokemon.mysteryEncounterData = new MysteryEncounterPokemonData(null, null, null, newTypes); + newPokemon.mysteryEncounterData = new MysteryEncounterPokemonData(undefined, undefined, undefined, newTypes); } else { newPokemon.mysteryEncounterData.types = newTypes; } @@ -381,9 +381,11 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon // Def or SpDef stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF); // const mod = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU().newModifier(newPokemon, 20, stats); - const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU().generateType(null, [20, stats]); - const modifier = modType.newModifier(newPokemon); - scene.addModifier(modifier); + const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU().generateType(scene.getParty(), [20, stats]); + const modifier = modType?.newModifier(newPokemon); + if (modifier) { + scene.addModifier(modifier); + } } // Enable passive if previous had it @@ -422,8 +424,8 @@ function getOriginalBst(scene: BattleScene, pokemon: Pokemon) { } function getTransformedSpecies(originalBst: number, bstSearchRange: [number, number], hasPokemonBstHigherThan600: boolean, hasPokemonBstBetween570And600: boolean, alreadyUsedSpecies: PokemonSpecies[]): PokemonSpecies { - let newSpecies: PokemonSpecies; - while (!newSpecies) { + let newSpecies: PokemonSpecies | undefined; + while (isNullOrUndefined(newSpecies)) { const bstCap = originalBst + bstSearchRange[1]; const bstMin = Math.max(originalBst + bstSearchRange[0], 0); @@ -442,7 +444,7 @@ function getTransformedSpecies(originalBst: number, bstSearchRange: [number, num if (validSpecies?.length > 20) { validSpecies = randSeedShuffle(validSpecies); newSpecies = validSpecies.pop(); - while (alreadyUsedSpecies.includes(newSpecies)) { + while (isNullOrUndefined(newSpecies) || alreadyUsedSpecies.includes(newSpecies!)) { newSpecies = validSpecies.pop(); } } else { @@ -452,7 +454,7 @@ function getTransformedSpecies(originalBst: number, bstSearchRange: [number, num } } - return newSpecies; + return newSpecies!; } function doShowDreamBackground(scene: BattleScene) { @@ -503,7 +505,7 @@ function doHideDreamBackground(scene: BattleScene) { function doSideBySideTransformations(scene: BattleScene, transformations: PokemonTransformation[]) { return new Promise(resolve => { - const allTransformationPromises = []; + const allTransformationPromises: Promise[] = []; for (let i = 0; i < 3; i++) { const delay = i * 4000; scene.time.delayedCall(delay, () => { diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index d4cf56ae17c..086706075e7 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -8,16 +8,32 @@ import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequiremen import { CanLearnMoveRequirement, CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; import { isNullOrUndefined } from "#app/utils"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; export type OptionPhaseCallback = (scene: BattleScene) => Promise; -// export default interface MysteryEncounterOption { -// -// } +/** + * Used by {@link MysteryEncounterOptionBuilder} class to define required/optional properties on the {@link MysteryEncounterOption} class when building. + * + * Should ONLY contain properties that are necessary for {@link MysteryEncounterOption} construction. + * Post-construct and flag data properties are defined in the {@link MysteryEncounterOption} class itself. + */ +export interface IMysteryEncounterOption { + optionMode: MysteryEncounterOptionMode; + hasDexProgress: boolean; + requirements: EncounterSceneRequirement[]; + primaryPokemonRequirements: EncounterPokemonRequirement[]; + secondaryPokemonRequirements: EncounterPokemonRequirement[]; + excludePrimaryFromSecondaryRequirements: boolean; -export default class MysteryEncounterOption { + dialogue?: OptionTextDisplay; + + onPreOptionPhase?: OptionPhaseCallback; + onOptionPhase: OptionPhaseCallback; + onPostOptionPhase?: OptionPhaseCallback; +} + +export default class MysteryEncounterOption implements IMysteryEncounterOption { optionMode: MysteryEncounterOptionMode; hasDexProgress: boolean; requirements: EncounterSceneRequirement[]; @@ -40,12 +56,14 @@ export default class MysteryEncounterOption { /** Executes after the encounter is over. Usually this will be for calculating dialogueTokens or performing data updates */ onPostOptionPhase?: OptionPhaseCallback; - constructor(option: MysteryEncounterOption | null) { - Object.assign(this, option); - this.hasDexProgress = !isNullOrUndefined(this.hasDexProgress) ? this.hasDexProgress : false; - this.requirements = this.requirements ? this.requirements : []; - this.primaryPokemonRequirements = this.primaryPokemonRequirements ? this.primaryPokemonRequirements : []; - this.secondaryPokemonRequirements = this.secondaryPokemonRequirements ? this.secondaryPokemonRequirements : []; + constructor(option: IMysteryEncounterOption | null) { + if (!isNullOrUndefined(option)) { + Object.assign(this, option); + } + this.hasDexProgress = this.hasDexProgress ?? false; + this.requirements = this.requirements ?? []; + this.primaryPokemonRequirements = this.primaryPokemonRequirements ?? []; + this.secondaryPokemonRequirements = this.secondaryPokemonRequirements ?? []; } hasRequirements() { @@ -70,7 +88,8 @@ export default class MysteryEncounterOption { for (const req of this.primaryPokemonRequirements) { if (req.meetsRequirement(scene)) { if (req instanceof EncounterPokemonRequirement) { - qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn)); + const queryParty = req.queryParty(scene.getParty()); + qualified = qualified.filter(pkmn => queryParty.includes(pkmn)); } } else { this.primaryPokemon = undefined; @@ -125,8 +144,8 @@ export default class MysteryEncounterOption { for (const req of this.secondaryPokemonRequirements) { if (req.meetsRequirement(scene)) { if (req instanceof EncounterPokemonRequirement) { - qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn)); - + const queryParty = req.queryParty(scene.getParty()); + qualified = qualified.filter(pkmn => queryParty.includes(pkmn)); } } else { this.secondaryPokemon = []; @@ -138,7 +157,7 @@ export default class MysteryEncounterOption { } } -export class MysteryEncounterOptionBuilder implements Partial { +export class MysteryEncounterOptionBuilder implements Partial { optionMode: MysteryEncounterOptionMode = MysteryEncounterOptionMode.DEFAULT; requirements: EncounterSceneRequirement[] = []; primaryPokemonRequirements: EncounterPokemonRequirement[] = []; @@ -146,26 +165,17 @@ export class MysteryEncounterOptionBuilder implements Partial { + static newOptionWithMode(optionMode: MysteryEncounterOptionMode): MysteryEncounterOptionBuilder & Pick { return Object.assign(new MysteryEncounterOptionBuilder(), { optionMode }); } - withHasDexProgress(hasDexProgress: boolean): this & Required> { + withHasDexProgress(hasDexProgress: boolean): this & Required> { return Object.assign(this, { hasDexProgress: hasDexProgress }); } - withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { + withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { if (requirement instanceof EncounterPokemonRequirement) { Error("Incorrectly added pokemon requirement as scene requirement."); } @@ -174,23 +184,23 @@ export class MysteryEncounterOptionBuilder implements Partial> { + withPreOptionPhase(onPreOptionPhase: OptionPhaseCallback): this & Required> { return Object.assign(this, { onPreOptionPhase: onPreOptionPhase }); } - withOptionPhase(onOptionPhase: OptionPhaseCallback): this & Required> { + withOptionPhase(onOptionPhase: OptionPhaseCallback): this & Required> { return Object.assign(this, { onOptionPhase: onOptionPhase }); } - withPostOptionPhase(onPostOptionPhase: OptionPhaseCallback): this & Required> { + withPostOptionPhase(onPostOptionPhase: OptionPhaseCallback): this & Required> { return Object.assign(this, { onPostOptionPhase: onPostOptionPhase }); } - withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { + withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { if (requirement instanceof EncounterSceneRequirement) { Error("Incorrectly added scene requirement as pokemon requirement."); } @@ -223,7 +233,7 @@ export class MysteryEncounterOptionBuilder implements Partial> { + withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = true): this & Required> { if (requirement instanceof EncounterSceneRequirement) { Error("Incorrectly added scene requirement as pokemon requirement."); } @@ -244,7 +254,7 @@ export class MysteryEncounterOptionBuilder implements Partial 0) { + if (this.scalingMultiplier > 0) { this.requiredMoney = scene.getWaveMoneyAmount(this.scalingMultiplier); } - return !(this?.requiredMoney > 0 && this.requiredMoney > money); + return !(this.requiredMoney > 0 && this.requiredMoney > money); } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - const value = this?.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString(); + const value = this.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString(); return ["money", value]; } } @@ -367,10 +367,10 @@ export class NatureRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - if (this.requiredNature.includes(pokemon.nature)) { - return ["nature", Nature[pokemon.nature]]; + if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon!.nature)) { + return ["nature", Nature[pokemon!.nature]]; } - return null; + return ["nature", ""]; } } @@ -537,9 +537,9 @@ export class EvolutionTargetSpeciesRequirement extends EncounterPokemonRequireme getMatchingDialogueToken(str:string, pokemon: PlayerPokemon): [RegExp, string] { const evos = this.requiredEvolutionTargetSpecies.filter((evolutionTargetSpecies) => pokemon.getEvolution().speciesId === evolutionTargetSpecies); if (evos.length > 0) { - return ["Evolution", Species[evos[0]]]; + return ["evolution", Species[evos[0]]]; } - return null; + return ["evolution", ""]; } }*/ @@ -622,7 +622,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement { return !this.requiredStatusEffect.some((statusEffect) => { if (statusEffect === StatusEffect.NONE) { // StatusEffect.NONE also checks for null or undefined status - return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status?.effect === statusEffect; + return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status!.effect) || pokemon.status?.effect === statusEffect; } else { return pokemon.status?.effect === statusEffect; } @@ -634,9 +634,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement { getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { const reqStatus = this.requiredStatusEffect.filter((a) => { if (a === StatusEffect.NONE) { - return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status?.effect === a; + return isNullOrUndefined(pokemon?.status) || isNullOrUndefined(pokemon!.status!.effect) || pokemon!.status!.effect === a; } - return pokemon.status?.effect === a; + return pokemon!.status?.effect === a; }); if (reqStatus.length > 0) { return ["status", StatusEffect[reqStatus[0]]]; @@ -698,7 +698,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen if (requiredItems.length > 0) { return ["formChangeItem", FormChangeItem[requiredItems[0]]]; } - return null; + return ["formChangeItem", ""]; } } @@ -748,7 +748,7 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement { if (requiredItems.length > 0) { return ["evolutionItem", EvolutionItem[requiredItems[0]]]; } - return null; + return ["evolutionItem", ""]; } } @@ -789,18 +789,18 @@ export class HeldItemRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - const requiredItems = pokemon.getHeldItems().filter((it) => { + const requiredItems = pokemon?.getHeldItems().filter((it) => { return this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem); }); - if (requiredItems.length > 0) { + if (requiredItems && requiredItems.length > 0) { return ["heldItem", requiredItems[0].type.name]; } - return null; + return ["heldItem", ""]; } } export class LevelRequirement extends EncounterPokemonRequirement { - requiredLevelRange?: [number, number]; + requiredLevelRange: [number, number]; minNumberOfPokemon: number; invertQuery: boolean; @@ -809,12 +809,11 @@ export class LevelRequirement extends EncounterPokemonRequirement { this.minNumberOfPokemon = minNumberOfPokemon; this.invertQuery = invertQuery; this.requiredLevelRange = requiredLevelRange; - } meetsRequirement(scene: BattleScene): boolean { // Party Pokemon inside required level range - if (!isNullOrUndefined(this?.requiredLevelRange) && this.requiredLevelRange?.[0] <= this.requiredLevelRange?.[1]) { + if (!isNullOrUndefined(this.requiredLevelRange) && this.requiredLevelRange[0] <= this.requiredLevelRange[1]) { const partyPokemon = scene.getParty(); const pokemonInRange = this.queryParty(partyPokemon); if (pokemonInRange.length < this.minNumberOfPokemon) { @@ -834,12 +833,12 @@ export class LevelRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["level", pokemon.level.toString()]; + return ["level", pokemon?.level.toString() ?? ""]; } } export class FriendshipRequirement extends EncounterPokemonRequirement { - requiredFriendshipRange?: [number, number]; + requiredFriendshipRange: [number, number]; minNumberOfPokemon: number; invertQuery: boolean; @@ -852,7 +851,7 @@ export class FriendshipRequirement extends EncounterPokemonRequirement { meetsRequirement(scene: BattleScene): boolean { // Party Pokemon inside required friendship range - if (!isNullOrUndefined(this?.requiredFriendshipRange) && this.requiredFriendshipRange?.[0] <= this.requiredFriendshipRange?.[1]) { + if (!isNullOrUndefined(this.requiredFriendshipRange) && this.requiredFriendshipRange[0] <= this.requiredFriendshipRange[1]) { const partyPokemon = scene.getParty(); const pokemonInRange = this.queryParty(partyPokemon); if (pokemonInRange.length < this.minNumberOfPokemon) { @@ -872,7 +871,7 @@ export class FriendshipRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["friendship", pokemon.friendship.toString()]; + return ["friendship", pokemon?.friendship.toString() ?? ""]; } } @@ -882,7 +881,7 @@ export class FriendshipRequirement extends EncounterPokemonRequirement { * 1 -> 100% hp */ export class HealthRatioRequirement extends EncounterPokemonRequirement { - requiredHealthRange?: [number, number]; + requiredHealthRange: [number, number]; minNumberOfPokemon: number; invertQuery: boolean; @@ -895,7 +894,7 @@ export class HealthRatioRequirement extends EncounterPokemonRequirement { meetsRequirement(scene: BattleScene): boolean { // Party Pokemon inside required level range - if (!isNullOrUndefined(this?.requiredHealthRange) && this.requiredHealthRange?.[0] <= this.requiredHealthRange?.[1]) { + if (!isNullOrUndefined(this.requiredHealthRange) && this.requiredHealthRange[0] <= this.requiredHealthRange[1]) { const partyPokemon = scene.getParty(); const pokemonInRange = this.queryParty(partyPokemon); if (pokemonInRange.length < this.minNumberOfPokemon) { @@ -917,12 +916,15 @@ export class HealthRatioRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["healthRatio", Math.floor(pokemon.getHpRatio() * 100).toString() + "%"]; + if (!isNullOrUndefined(pokemon?.getHpRatio())) { + return ["healthRatio", Math.floor(pokemon!.getHpRatio() * 100).toString() + "%"]; + } + return ["healthRatio", ""]; } } export class WeightRequirement extends EncounterPokemonRequirement { - requiredWeightRange?: [number, number]; + requiredWeightRange: [number, number]; minNumberOfPokemon: number; invertQuery: boolean; @@ -935,7 +937,7 @@ export class WeightRequirement extends EncounterPokemonRequirement { meetsRequirement(scene: BattleScene): boolean { // Party Pokemon inside required friendship range - if (!isNullOrUndefined(this?.requiredWeightRange) && this.requiredWeightRange?.[0] <= this.requiredWeightRange?.[1]) { + if (!isNullOrUndefined(this.requiredWeightRange) && this.requiredWeightRange[0] <= this.requiredWeightRange[1]) { const partyPokemon = scene.getParty(); const pokemonInRange = this.queryParty(partyPokemon); if (pokemonInRange.length < this.minNumberOfPokemon) { @@ -955,7 +957,7 @@ export class WeightRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["weight", pokemon.getWeight().toString()]; + return ["weight", pokemon?.getWeight().toString() ?? ""]; } } diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index cae68150255..3db97bf1f98 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -24,14 +24,41 @@ export interface EncounterStartOfBattleEffect { followUp?: boolean; } -interface IMysteryEncounter { - meetsRequirements(scene: BattleScene): boolean; - pokemonMeetsPrimaryRequirements(scene: BattleScene, pokemon: Pokemon): boolean; - initIntroVisuals(scene: BattleScene): void; - populateDialogueTokensFromRequirements(scene: BattleScene): void; - setDialogueToken(key: string, value: string): void; - getSeedOffset(): number; - updateSeedOffset(scene: BattleScene): void; +/** + * Used by {@link MysteryEncounterBuilder} class to define required/optional properties on the {@link MysteryEncounter} class when building. + * + * Should ONLY contain properties that are necessary for {@link MysteryEncounter} construction. + * Post-construct and flag data properties are defined in the {@link MysteryEncounter} class itself. + */ +export interface IMysteryEncounter { + encounterType: MysteryEncounterType; + options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]]; + spriteConfigs: MysteryEncounterSpriteConfig[]; + encounterTier: MysteryEncounterTier; + encounterAnimations?: EncounterAnim[]; + hideBattleIntroMessage: boolean; + autoHideIntroVisuals: boolean; + enterIntroVisualsFromRight: boolean; + catchAllowed: boolean; + continuousEncounter: boolean; + maxAllowedEncounters: number; + + onInit?: (scene: BattleScene) => boolean; + onVisualsStart?: (scene: BattleScene) => boolean; + doEncounterExp?: (scene: BattleScene) => boolean; + doEncounterRewards?: (scene: BattleScene) => boolean; + doContinueEncounter?: (scene: BattleScene) => Promise; + + requirements: EncounterSceneRequirement[]; + primaryPokemonRequirements: EncounterPokemonRequirement[]; + secondaryPokemonRequirements: EncounterPokemonRequirement[]; + excludePrimaryFromSupportRequirements: boolean; + + dialogue: MysteryEncounterDialogue; + enemyPartyConfigs: EnemyPartyConfig[]; + + dialogueTokens: Record; + expMultiplier: number; } /** @@ -147,7 +174,7 @@ export default class MysteryEncounter implements IMysteryEncounter { * Can be set for uses programatic dialogue during an encounter (storing the name of one of the party's pokemon, etc.) * Example use: see MYSTERIOUS_CHEST */ - dialogueTokens: Map; + dialogueTokens: Record; /** * Should be set depending upon option selected as part of an encounter * For example, if there is no battle as part of the encounter/selected option, should be set to NO_BATTLE @@ -171,7 +198,7 @@ export default class MysteryEncounter implements IMysteryEncounter { /** * Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases */ - startOfBattleEffects?: EncounterStartOfBattleEffect[]; + startOfBattleEffects: EncounterStartOfBattleEffect[] = []; /** * Can be set higher or lower based on the type of battle or exp gained for an option/encounter * Defaults to 1 @@ -188,7 +215,7 @@ export default class MysteryEncounter implements IMysteryEncounter { */ private seedOffset?: any; - constructor(encounter: MysteryEncounter | null) { + constructor(encounter: IMysteryEncounter | null) { if (!isNullOrUndefined(encounter)) { Object.assign(this, encounter); } @@ -207,9 +234,9 @@ export default class MysteryEncounter implements IMysteryEncounter { // Reset any dirty flags or encounter data this.startOfBattleEffectsComplete = false; this.lockEncounterRewardTiers = true; - this.dialogueTokens = new Map(); + this.dialogueTokens = {}; this.enemyPartyConfigs = []; - this.startOfBattleEffects = []; + // this.startOfBattleEffects = []; this.introVisuals = undefined; this.misc = null; this.expMultiplier = 1; @@ -361,7 +388,7 @@ export default class MysteryEncounter implements IMysteryEncounter { const opt = this.options[i]; opt.meetsRequirements(scene); const j = i + 1; - if (opt.requirements?.length > 0) { + if (opt.requirements.length > 0) { for (const req of opt.requirements) { const dialogueToken = req.getDialogueToken(scene); if (dialogueToken?.length === 2) { @@ -369,7 +396,7 @@ export default class MysteryEncounter implements IMysteryEncounter { } } } - if (opt.primaryPokemonRequirements?.length > 0 && opt.primaryPokemon && opt.primaryPokemon.length > 0) { + if (opt.primaryPokemonRequirements.length > 0 && opt.primaryPokemon) { this.setDialogueToken("option" + j + "PrimaryName", opt.primaryPokemon.getNameToRender()); for (const req of opt.primaryPokemonRequirements) { if (!req.invertQuery) { @@ -424,26 +451,16 @@ export default class MysteryEncounter implements IMysteryEncounter { * Builder class for creating a MysteryEncounter * must call `build()` at the end after specifying all params for the MysteryEncounter */ -export class MysteryEncounterBuilder implements Partial { - encounterType: MysteryEncounterType; - encounterMode: MysteryEncounterMode; - options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [new MysteryEncounterOption(null), new MysteryEncounterOption(null)]; - spriteConfigs: MysteryEncounterSpriteConfig[]; +export class MysteryEncounterBuilder implements Partial { + options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]]; enemyPartyConfigs: EnemyPartyConfig[] = []; dialogue: MysteryEncounterDialogue = {}; - encounterTier: MysteryEncounterTier; - encounterAnimations: EncounterAnim[]; requirements: EncounterSceneRequirement[] = []; primaryPokemonRequirements: EncounterPokemonRequirement[] = []; secondaryPokemonRequirements: EncounterPokemonRequirement[] = []; - excludePrimaryFromSupportRequirements: boolean; - dialogueTokens: Map = new Map(); - - doEncounterExp?: (scene: BattleScene) => boolean; - doEncounterRewards?: (scene: BattleScene) => boolean; - onInit?: (scene: BattleScene) => boolean; - onVisualsStart?: (scene: BattleScene) => boolean; + excludePrimaryFromSupportRequirements: boolean = true; + dialogueTokens: Record = {}; hideBattleIntroMessage: boolean = false; autoHideIntroVisuals: boolean = true; @@ -455,21 +472,6 @@ export class MysteryEncounterBuilder implements Partial { maxAllowedEncounters: number = 3; expMultiplier: number = 1; - /** - * Builder class has to re-declare the {@link MysteryEncounter} class functions so - * the compiler does not yell about user not defining a non-optional property - */ - - meetsRequirements = MysteryEncounter.prototype["meetsRequirements"]; - pokemonMeetsPrimaryRequirements = MysteryEncounter.prototype["pokemonMeetsPrimaryRequirements"]; - initIntroVisuals = MysteryEncounter.prototype["initIntroVisuals"]; - populateDialogueTokensFromRequirements = MysteryEncounter.prototype["populateDialogueTokensFromRequirements"]; - setDialogueToken = MysteryEncounter.prototype["setDialogueToken"]; - getSeedOffset = MysteryEncounter.prototype["getSeedOffset"]; - updateSeedOffset = MysteryEncounter.prototype["updateSeedOffset"]; - meetsPrimaryRequirementAndPrimaryPokemonSelected = MysteryEncounter.prototype["meetsPrimaryRequirementAndPrimaryPokemonSelected"]; - meetsSecondaryRequirementAndSecondaryPokemonSelected = MysteryEncounter.prototype["meetsSecondaryRequirementAndSecondaryPokemonSelected"]; - /** * REQUIRED */ @@ -480,7 +482,7 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterType * @returns this */ - static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick { + static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick { return Object.assign(new MysteryEncounterBuilder(), { encounterType }); } @@ -492,14 +494,13 @@ export class MysteryEncounterBuilder implements Partial { * @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance * @returns */ - withOption(option: MysteryEncounterOption): this & Pick { - if (this.options[0] === null) { - return Object.assign(this, { options: [option, this.options[0]] }); - } else if (this.options[1] === null) { - return Object.assign(this, { options: [this.options[0], option] }); + withOption(option: MysteryEncounterOption): this & Pick { + if (!this.options) { + const options = [option]; + return Object.assign(this, { options }); } else { this.options.push(option); - return Object.assign(this, { options: this.options }); + return this; } } @@ -514,7 +515,7 @@ export class MysteryEncounterBuilder implements Partial { * @param callback - {@linkcode OptionPhaseCallback} * @returns */ - withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick { + withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick { return this.withOption(MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build()); } @@ -528,7 +529,7 @@ export class MysteryEncounterBuilder implements Partial { * @param callback - {@linkcode OptionPhaseCallback} * @returns */ - withSimpleDexProgressOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick { + withSimpleDexProgressOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick { return this.withOption(MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .withHasDexProgress(true) @@ -542,7 +543,7 @@ export class MysteryEncounterBuilder implements Partial { * @param spriteConfigs * @returns */ - withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { + withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick { return Object.assign(this, { spriteConfigs: spriteConfigs }); } @@ -571,7 +572,7 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterTier * @returns */ - withEncounterTier(encounterTier: MysteryEncounterTier): this & Pick { + withEncounterTier(encounterTier: MysteryEncounterTier): this & Pick { return Object.assign(this, { encounterTier: encounterTier }); } @@ -582,7 +583,7 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterAnimations * @returns */ - withAnimations(...encounterAnimations: EncounterAnim[]): this & Required> { + withAnimations(...encounterAnimations: EncounterAnim[]): this & Required> { const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [encounterAnimations]; return Object.assign(this, { encounterAnimations: animations }); } @@ -593,7 +594,7 @@ export class MysteryEncounterBuilder implements Partial { * Default false * @param continuousEncounter */ - withContinuousEncounter(continuousEncounter: boolean): this & Required> { + withContinuousEncounter(continuousEncounter: boolean): this & Required> { return Object.assign(this, { continuousEncounter: continuousEncounter }); } @@ -602,7 +603,7 @@ export class MysteryEncounterBuilder implements Partial { * @param maxAllowedEncounters * @returns */ - withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required> { + withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required> { return Object.assign(this, { maxAllowedEncounters: maxAllowedEncounters }); } @@ -613,12 +614,12 @@ export class MysteryEncounterBuilder implements Partial { * @param requirement * @returns */ - withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { + withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> { if (requirement instanceof EncounterPokemonRequirement) { Error("Incorrectly added pokemon requirement as scene requirement."); } this.requirements.push(requirement); - return Object.assign(this, { requirements: this.requirements }); + return this; } /** @@ -628,7 +629,7 @@ export class MysteryEncounterBuilder implements Partial { * @param max optional max wave. If not given, defaults to min => exact wave * @returns */ - withSceneWaveRangeRequirement(min: number, max?: number): this & Required> { + withSceneWaveRangeRequirement(min: number, max?: number): this & Required> { return this.withSceneRequirement(new WaveRangeRequirement([min, max ?? min])); } @@ -640,7 +641,7 @@ export class MysteryEncounterBuilder implements Partial { * @param excludeFainted - if true, only counts unfainted mons * @returns */ - withScenePartySizeRequirement(min: number, max?: number, excludeFainted: boolean = false): this & Required> { + withScenePartySizeRequirement(min: number, max?: number, excludeFainted: boolean = false): this & Required> { return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min], excludeFainted)); } @@ -650,7 +651,7 @@ export class MysteryEncounterBuilder implements Partial { * @param requirement {@linkcode EncounterPokemonRequirement} * @returns */ - withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { + withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> { if (requirement instanceof EncounterSceneRequirement) { Error("Incorrectly added scene requirement as pokemon requirement."); } @@ -667,7 +668,7 @@ export class MysteryEncounterBuilder implements Partial { * @param invertQuery if true will invert the query * @returns */ - withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { + withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new StatusEffectRequirement(statusEffect, minNumberOfPokemon, invertQuery)); } @@ -679,14 +680,14 @@ export class MysteryEncounterBuilder implements Partial { * @param invertQuery if true will invert the query * @returns */ - withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { + withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required> { return this.withPrimaryPokemonRequirement(new HealthRatioRequirement(requiredHealthRange, minNumberOfPokemon, invertQuery)); } // TODO: Maybe add an optional parameter for excluding primary pokemon from the support cast? // ex. if your only grass type pokemon, a snivy, is chosen as primary, if the support pokemon requires a grass type, the event won't trigger because // it's already been - withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required> { + withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required> { if (requirement instanceof EncounterSceneRequirement) { Error("Incorrectly added scene requirement as pokemon requirement."); } @@ -706,7 +707,7 @@ export class MysteryEncounterBuilder implements Partial { * @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter * @returns */ - withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required> { + withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { doEncounterRewards: doEncounterRewards }); } @@ -720,7 +721,7 @@ export class MysteryEncounterBuilder implements Partial { * @param doEncounterExp - synchronous callback function to perform during rewards phase of the encounter * @returns */ - withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required> { + withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { doEncounterExp: doEncounterExp }); } @@ -731,8 +732,8 @@ export class MysteryEncounterBuilder implements Partial { * @param onInit - synchronous callback function to perform as soon as the encounter is selected for the next phase * @returns */ - withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> { - return Object.assign(this, { onInit: onInit }); + withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> { + return Object.assign(this, { onInit }); } /** @@ -741,7 +742,7 @@ export class MysteryEncounterBuilder implements Partial { * @param onVisualsStart - synchronous callback function to perform as soon as the enemy field finishes sliding in * @returns */ - withOnVisualsStart(onVisualsStart: (scene: BattleScene) => boolean): this & Required> { + withOnVisualsStart(onVisualsStart: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { onVisualsStart: onVisualsStart }); } @@ -751,7 +752,7 @@ export class MysteryEncounterBuilder implements Partial { * @param catchAllowed - if true, allows enemy pokemon to be caught during the encounter * @returns */ - withCatchAllowed(catchAllowed: boolean): this & Required> { + withCatchAllowed(catchAllowed: boolean): this & Required> { return Object.assign(this, { catchAllowed: catchAllowed }); } @@ -759,7 +760,7 @@ export class MysteryEncounterBuilder implements Partial { * @param hideBattleIntroMessage - if true, will not show the trainerAppeared/wildAppeared/bossAppeared message for an encounter * @returns */ - withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required> { + withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required> { return Object.assign(this, { hideBattleIntroMessage: hideBattleIntroMessage }); } @@ -767,7 +768,7 @@ export class MysteryEncounterBuilder implements Partial { * @param autoHideIntroVisuals - if false, will not hide the intro visuals that are displayed at the beginning of encounter * @returns */ - withAutoHideIntroVisuals(autoHideIntroVisuals: boolean): this & Required> { + withAutoHideIntroVisuals(autoHideIntroVisuals: boolean): this & Required> { return Object.assign(this, { autoHideIntroVisuals: autoHideIntroVisuals }); } @@ -776,7 +777,7 @@ export class MysteryEncounterBuilder implements Partial { * Default false * @returns */ - withEnterIntroVisualsFromRight(enterIntroVisualsFromRight: boolean): this & Required> { + withEnterIntroVisualsFromRight(enterIntroVisualsFromRight: boolean): this & Required> { return Object.assign(this, { enterIntroVisualsFromRight: enterIntroVisualsFromRight }); } @@ -856,7 +857,7 @@ export class MysteryEncounterBuilder implements Partial { * * @returns */ - build(this: MysteryEncounter): MysteryEncounter { + build(this: IMysteryEncounter): MysteryEncounter { return new MysteryEncounter(this); } } diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index 44f4ecf2420..b9e15302fe4 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -278,7 +278,7 @@ export function initMysteryEncounters() { extremeBiomeEncounters.forEach(encounter => { EXTREME_ENCOUNTER_BIOMES.forEach(biome => { const encountersForBiome = mysteryEncountersByBiome.get(biome); - if (!encountersForBiome.includes(encounter)) { + if (encountersForBiome && !encountersForBiome.includes(encounter)) { encountersForBiome.push(encounter); } }); @@ -287,7 +287,7 @@ export function initMysteryEncounters() { nonExtremeBiomeEncounters.forEach(encounter => { NON_EXTREME_ENCOUNTER_BIOMES.forEach(biome => { const encountersForBiome = mysteryEncountersByBiome.get(biome); - if (!encountersForBiome.includes(encounter)) { + if (encountersForBiome && !encountersForBiome.includes(encounter)) { encountersForBiome.push(encounter); } }); @@ -296,7 +296,7 @@ export function initMysteryEncounters() { humanTransitableBiomeEncounters.forEach(encounter => { HUMAN_TRANSITABLE_BIOMES.forEach(biome => { const encountersForBiome = mysteryEncountersByBiome.get(biome); - if (!encountersForBiome.includes(encounter)) { + if (encountersForBiome && !encountersForBiome.includes(encounter)) { encountersForBiome.push(encounter); } }); @@ -305,7 +305,7 @@ export function initMysteryEncounters() { civilizationBiomeEncounters.forEach(encounter => { CIVILIZATION_ENCOUNTER_BIOMES.forEach(biome => { const encountersForBiome = mysteryEncountersByBiome.get(biome); - if (!encountersForBiome.includes(encounter)) { + if (encountersForBiome && !encountersForBiome.includes(encounter)) { encountersForBiome.push(encounter); } }); diff --git a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts index fb1d65342c1..9a0447d816d 100644 --- a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts +++ b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts @@ -1,6 +1,6 @@ import BattleScene from "#app/battle-scene"; import { Moves } from "#app/enums/moves"; -import { PlayerPokemon } from "#app/field/pokemon"; +import { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { isNullOrUndefined } from "#app/utils"; import { EncounterPokemonRequirement } from "../mystery-encounter-requirements"; @@ -37,7 +37,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { this.excludeEggMoves = excludeEggMoves ?? false; this.includeFainted = includeFainted ?? false; this.minNumberOfPokemon = minNumberOfPokemon ?? 1; - this.invertQuery = invertQuery; + this.invertQuery = invertQuery ?? false; } override meetsRequirement(scene: BattleScene): boolean { @@ -66,7 +66,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { } override getDialogueToken(_scene: BattleScene, _pokemon?: PlayerPokemon): [string, string] { - return ["requiredMoves", this.requiredMoves.join(", ")]; + return ["requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ")]; } private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] { diff --git a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts index 382b2c7dde8..2ed2696182b 100644 --- a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts @@ -4,34 +4,37 @@ import { UiTheme } from "#enums/ui-theme"; import { isNullOrUndefined } from "#app/utils"; import i18next from "i18next"; -export function getEncounterText(scene: BattleScene, keyOrString: string, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string { +export function getEncounterText(scene: BattleScene, keyOrString?: string, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string | null { if (isNullOrUndefined(keyOrString)) { return null; } - let textString: string = getTextWithDialogueTokens(scene, keyOrString); + let textString: string | null = getTextWithDialogueTokens(scene, keyOrString); // Can only color the text if a Primary Style is defined // primaryStyle is applied to all text that does not have its own specified style - if (primaryStyle) { + if (primaryStyle && textString) { textString = getTextWithColors(textString, primaryStyle, uiTheme); } return textString; } -function getTextWithDialogueTokens(scene: BattleScene, keyOrString: string): string { +function getTextWithDialogueTokens(scene: BattleScene, keyOrString?: string): string | null { if (isNullOrUndefined(keyOrString)) { return null; } - if (i18next.exists(keyOrString, scene.currentBattle?.mysteryEncounter?.dialogueTokens)) { + const tokens = scene.currentBattle?.mysteryEncounter?.dialogueTokens; + // @ts-ignore + if (i18next.exists(keyOrString, tokens)) { const stringArray = [`${keyOrString}`] as any; stringArray.raw = [`${keyOrString}`]; - return i18next.t(stringArray, scene.currentBattle?.mysteryEncounter?.dialogueTokens); + // @ts-ignore + return i18next.t(stringArray, tokens) as string; } - return keyOrString; + return keyOrString ?? null; } /** @@ -40,8 +43,8 @@ function getTextWithDialogueTokens(scene: BattleScene, keyOrString: string): str * @param contentKey */ export function queueEncounterMessage(scene: BattleScene, contentKey: string): void { - const text: string = getEncounterText(scene, contentKey); - scene.queueMessage(text, null, true); + const text: string | null = getEncounterText(scene, contentKey); + scene.queueMessage(text ?? "", null, true); } /** @@ -53,8 +56,8 @@ export function queueEncounterMessage(scene: BattleScene, contentKey: string): v */ export function showEncounterText(scene: BattleScene, contentKey: string, callbackDelay: number = 0, prompt: boolean = true): Promise { return new Promise(resolve => { - const text: string = getEncounterText(scene, contentKey); - scene.ui.showText(text, null, () => resolve(), callbackDelay, prompt); + const text: string | null = getEncounterText(scene, contentKey); + scene.ui.showText(text ?? "", null, () => resolve(), callbackDelay, prompt); }); } @@ -67,8 +70,8 @@ export function showEncounterText(scene: BattleScene, contentKey: string, callba */ export function showEncounterDialogue(scene: BattleScene, textContentKey: string, speakerContentKey: string, callbackDelay: number = 0): Promise { return new Promise(resolve => { - const text: string = getEncounterText(scene, textContentKey); - const speaker: string = getEncounterText(scene, speakerContentKey); - scene.ui.showDialogue(text, speaker, null, () => resolve(), callbackDelay); + const text: string | null = getEncounterText(scene, textContentKey); + const speaker: string | null = getEncounterText(scene, speakerContentKey); + scene.ui.showDialogue(text ?? "", speaker ?? "", null, () => resolve(), callbackDelay); }); } diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index c58e0fbad1f..9d74fa79ff0 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -1,4 +1,4 @@ -import { BattlerIndex, BattleType } from "#app/battle"; +import Battle, { BattlerIndex, BattleType } from "#app/battle"; import { biomeLinks, BiomePoolTier } from "#app/data/biomes"; import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import { WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters"; @@ -10,7 +10,7 @@ import { BattleEndPhase, EggLapsePhase, ExpPhase, GameOverPhase, MovePhase, Sele import { MysteryEncounterBattlePhase, MysteryEncounterBattleStartCleanupPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; import PokemonData from "#app/system/pokemon-data"; import { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler"; +import { PartyOption, PartyUiMode, PokemonSelectFilter } from "#app/ui/party-ui-handler"; import { Mode } from "#app/ui/ui"; import * as Utils from "#app/utils"; import { isNullOrUndefined } from "#app/utils"; @@ -101,29 +101,30 @@ export interface EnemyPartyConfig { * @param partyConfig - Can pass various customizable attributes for the enemy party, see EnemyPartyConfig */ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: EnemyPartyConfig): Promise { - const loaded = false; - const loadEnemyAssets = []; + const loaded: boolean = false; + const loadEnemyAssets: Promise[] = []; - const battle = scene.currentBattle; + const battle: Battle = scene.currentBattle; - let doubleBattle = partyConfig?.doubleBattle; + let doubleBattle: boolean = partyConfig?.doubleBattle ?? false; // Trainer const trainerType = partyConfig?.trainerType; - let trainerConfig = partyConfig?.trainerConfig; - if (trainerType || trainerConfig) { + const partyTrainerConfig = partyConfig?.trainerConfig; + let trainerConfig: TrainerConfig; + if (!isNullOrUndefined(trainerType) || partyTrainerConfig) { scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.TRAINER_BATTLE; if (scene.currentBattle.trainer) { scene.currentBattle.trainer.setVisible(false); scene.currentBattle.trainer.destroy(); } - trainerConfig = partyConfig?.trainerConfig ? partyConfig?.trainerConfig : trainerConfigs[trainerType]; + trainerConfig = partyConfig?.trainerConfig ? partyConfig?.trainerConfig : trainerConfigs[trainerType!]; - const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && partyConfig.doubleBattle); + const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && !!partyConfig.doubleBattle); doubleBattle = doubleTrainer; const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!(Utils.randSeedInt(2)) : partyConfig.female; - const newTrainer = new Trainer(scene, trainerConfig.trainerType, doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT, null, null, null, trainerConfig); + const newTrainer = new Trainer(scene, trainerConfig.trainerType, doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT, undefined, undefined, undefined, trainerConfig); newTrainer.x += 300; newTrainer.setVisible(false); scene.field.add(newTrainer); @@ -134,7 +135,8 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: } else { // Wild scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.WILD_BATTLE; - battle.enemyLevels = new Array(partyConfig?.pokemonConfigs?.length > 0 ? partyConfig?.pokemonConfigs?.length : doubleBattle ? 2 : 1).fill(null).map(() => scene.currentBattle.getLevelForWave()); + const numEnemies = partyConfig?.pokemonConfigs && partyConfig.pokemonConfigs.length > 0 ? partyConfig?.pokemonConfigs?.length : doubleBattle ? 2 : 1; + battle.enemyLevels = new Array(numEnemies).fill(null).map(() => scene.currentBattle.getLevelForWave()); } scene.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy()); @@ -146,7 +148,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: // This can be amplified or counteracted by setting levelAdditiveMultiplier in config // levelAdditiveMultiplier value of 0.5 will halve the modifier scaling, 2 will double it, etc. // Leaving null/undefined will disable level scaling - const mult = !isNullOrUndefined(partyConfig.levelAdditiveMultiplier) ? partyConfig.levelAdditiveMultiplier : 0; + const mult: number = !isNullOrUndefined(partyConfig.levelAdditiveMultiplier) ? partyConfig.levelAdditiveMultiplier! : 0; const additive = Math.max(Math.round((scene.currentBattle.waveIndex / 10) * mult), 0); battle.enemyLevels = battle.enemyLevels.map(level => level + additive); @@ -155,10 +157,10 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: let dataSource; let isBoss = false; if (!loaded) { - if (trainerType || trainerConfig) { + if ((!isNullOrUndefined(trainerType) || trainerConfig) && battle.trainer) { // Allows overriding a trainer's pokemon to use specific species/data - if (e < partyConfig?.pokemonConfigs?.length) { - const config = partyConfig?.pokemonConfigs?.[e]; + if (partyConfig?.pokemonConfigs && e < partyConfig.pokemonConfigs.length) { + const config = partyConfig.pokemonConfigs[e]; level = config.level ? config.level : level; dataSource = config.dataSource; enemySpecies = config.species; @@ -168,8 +170,8 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: battle.enemyParty[e] = battle.trainer.genPartyMember(e); } } else { - if (e < partyConfig?.pokemonConfigs?.length) { - const config = partyConfig?.pokemonConfigs?.[e]; + if (partyConfig?.pokemonConfigs && e < partyConfig.pokemonConfigs.length) { + const config = partyConfig.pokemonConfigs[e]; level = config.level ? config.level : level; dataSource = config.dataSource; enemySpecies = config.species; @@ -201,8 +203,8 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: scene.gameData.setPokemonSeen(enemyPokemon, true, !!(trainerType || trainerConfig)); } - if (e < partyConfig?.pokemonConfigs?.length) { - const config = partyConfig?.pokemonConfigs?.[e]; + if (partyConfig?.pokemonConfigs && e < partyConfig.pokemonConfigs.length) { + const config = partyConfig.pokemonConfigs[e]; // Generate new id, reset status and HP in case using data source if (config.dataSource) { @@ -211,24 +213,24 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: // Set form if (!isNullOrUndefined(config.formIndex)) { - enemyPokemon.formIndex = config.formIndex; + enemyPokemon.formIndex = config.formIndex!; } // Set shiny if (!isNullOrUndefined(config.shiny)) { - enemyPokemon.shiny = config.shiny; + enemyPokemon.shiny = config.shiny!; } // Set custom mystery encounter data fields (such as sprite scale, custom abilities, types, etc.) if (!isNullOrUndefined(config.mysteryEncounterData)) { - enemyPokemon.mysteryEncounterData = config.mysteryEncounterData; + enemyPokemon.mysteryEncounterData = config.mysteryEncounterData!; } // Set Boss if (config.isBoss) { - let segments = !isNullOrUndefined(config.bossSegments) ? config.bossSegments : scene.getEncounterBossSegments(scene.currentBattle.waveIndex, level, enemySpecies, true); + let segments = !isNullOrUndefined(config.bossSegments) ? config.bossSegments! : scene.getEncounterBossSegments(scene.currentBattle.waveIndex, level, enemySpecies, true); if (!isNullOrUndefined(config.bossSegmentModifier)) { - segments += config.bossSegmentModifier; + segments += config.bossSegmentModifier!; } enemyPokemon.setBoss(true, segments); } @@ -253,7 +255,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: if (statusEffects) { // Default to cureturn 3 for sleep const status = Array.isArray(statusEffects) ? statusEffects[0] : statusEffects; - const cureTurn = Array.isArray(statusEffects) ? statusEffects[1] : statusEffects === StatusEffect.SLEEP ? 3 : null; + const cureTurn = Array.isArray(statusEffects) ? statusEffects[1] : statusEffects === StatusEffect.SLEEP ? 3 : undefined; enemyPokemon.status = new Status(status, 0, cureTurn); } @@ -264,24 +266,24 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: // Set ability if (!isNullOrUndefined(config.abilityIndex)) { - enemyPokemon.abilityIndex = config.abilityIndex; + enemyPokemon.abilityIndex = config.abilityIndex!; } // Set gender if (!isNullOrUndefined(config.gender)) { - enemyPokemon.gender = config.gender; - enemyPokemon.summonData.gender = config.gender; + enemyPokemon.gender = config.gender!; + enemyPokemon.summonData.gender = config.gender!; } // Set moves - if (config?.moveSet?.length > 0) { + if (config?.moveSet && config.moveSet.length > 0) { const moves = config.moveSet.map(m => new PokemonMove(m)); enemyPokemon.moveset = moves; enemyPokemon.summonData.moveset = moves; } // Set tags - if (config.tags?.length > 0) { + if (config.tags && config.tags.length > 0) { const tags = config.tags; tags.forEach(tag => enemyPokemon.addTag(tag)); } @@ -319,8 +321,12 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: }); if (!loaded) { regenerateModifierPoolThresholds(scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); - const customModifierTypes = partyConfig?.pokemonConfigs?.map(config => config?.modifierConfigs); - scene.generateEnemyModifiers(customModifierTypes); + const customModifierTypes = partyConfig?.pokemonConfigs + ?.filter(config => config?.modifierConfigs) + .map(config => config.modifierConfigs!); + if (customModifierTypes) { + scene.generateEnemyModifiers(customModifierTypes); + } } } @@ -368,7 +374,7 @@ export function updatePlayerMoney(scene: BattleScene, changeValue: number, playS * @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc. */ export function generateModifierType(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierType { - const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier); + const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier)!; let result: ModifierType = modifierTypes[modifierId]?.(); // Populates item id and tier (order matters) @@ -376,8 +382,8 @@ export function generateModifierType(scene: BattleScene, modifier: () => Modifie .withIdFromFunc(modifierTypes[modifierId]) .withTierFromPool(); - result = result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result; - return result; + const generatedResult = result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result; + return generatedResult ?? result; } /** @@ -399,7 +405,7 @@ export function generateModifierTypeOption(scene: BattleScene, modifier: () => M * @param onPokemonNotSelected - Any logic that needs to be performed if no Pokemon is chosen * @param selectablePokemonFilter */ -export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (pokemon: PlayerPokemon) => void | OptionSelectItem[], onPokemonNotSelected?: () => void, selectablePokemonFilter?: (pokemon: PlayerPokemon) => string): Promise { +export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (pokemon: PlayerPokemon) => void | OptionSelectItem[], onPokemonNotSelected?: () => void, selectablePokemonFilter?: PokemonSelectFilter): Promise { return new Promise(resolve => { const modeToSetOnExit = scene.ui.getMode(); @@ -451,7 +457,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p scene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true); }; - const textPromptKey = scene.currentBattle.mysteryEncounter.selectedOption.dialogue.secondOptionPrompt; + const textPromptKey = scene.currentBattle.mysteryEncounter?.selectedOption?.dialogue?.secondOptionPrompt; if (!textPromptKey) { displayOptions(); } else { @@ -486,7 +492,7 @@ export function setEncounterRewards(scene: BattleScene, customShopRewards?: Cust } if (customShopRewards) { - scene.unshiftPhase(new SelectModifierPhase(scene, 0, null, customShopRewards)); + scene.unshiftPhase(new SelectModifierPhase(scene, 0, undefined, customShopRewards)); } else { scene.tryRemovePhase(p => p instanceof SelectModifierPhase); } @@ -530,7 +536,7 @@ export function setEncounterExp(scene: BattleScene, participantId: integer | int const multipleParticipantExpBonusModifier = scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier; const nonFaintedPartyMembers = party.filter(p => p.hp); const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < scene.getMaxExpLevel()); - const partyMemberExp = []; + const partyMemberExp: number[] = []; // EXP value calculation is based off Pokemon.getExpValue let expValue = Math.floor(baseExpValue * (useWaveIndex ? scene.currentBattle.waveIndex : 1) / 5 + 1); @@ -581,7 +587,7 @@ export function setEncounterExp(scene: BattleScene, participantId: integer | int const medianLevel = Math.floor(totalLevel / expPartyMembers.length); - const recipientExpPartyMemberIndexes = []; + const recipientExpPartyMemberIndexes: number[] = []; expPartyMembers.forEach((expPartyMember, epm) => { if (expPartyMember.level <= medianLevel) { recipientExpPartyMemberIndexes.push(epm); @@ -720,7 +726,7 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide: scene.field.remove(pokemon, true); }); - scene.currentBattle.mysteryEncounter.introVisuals = null; + scene.currentBattle.mysteryEncounter.introVisuals = undefined; } resolve(true); } @@ -808,11 +814,13 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n }) .map(b => !Array.isArray(b) ? b : b[0]); }, i * 100); - const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b)); - if (specialBiomes.length > 0) { - currentBiome = specialBiomes[Utils.randSeedInt(specialBiomes.length)]; - } else { - currentBiome = biomes[Utils.randSeedInt(biomes.length)]; + if (biomes! && biomes.length > 0) { + const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b)); + if (specialBiomes.length > 0) { + currentBiome = specialBiomes[Utils.randSeedInt(specialBiomes.length)]; + } else { + currentBiome = biomes[Utils.randSeedInt(biomes.length)]; + } } } else if (biomeLinks.hasOwnProperty(currentBiome)) { currentBiome = (biomeLinks[currentBiome] as Biome); @@ -840,7 +848,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n // Otherwise, roll encounter const roll = Utils.randSeedInt(256); - validMEfloorsByBiome.set(Biome[currentBiome], validMEfloorsByBiome.get(Biome[currentBiome]) + 1); + validMEfloorsByBiome.set(Biome[currentBiome], (validMEfloorsByBiome.get(Biome[currentBiome]) ?? 0) + 1); // If total number of encounters is lower than expected for the run, slightly favor a new encounter // Do the reverse as well @@ -866,7 +874,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; // 64 - 32 - 16 - 10 = 6 tierValue > commonThreshold ? ++numEncounters[0] : tierValue > uncommonThreshold ? ++numEncounters[1] : tierValue > rareThreshold ? ++numEncounters[2] : ++numEncounters[3]; - encountersByBiome.set(Biome[currentBiome], encountersByBiome.get(Biome[currentBiome]) + 1); + encountersByBiome.set(Biome[currentBiome], (encountersByBiome.get(Biome[currentBiome]) ?? 0) + 1); } else { encounterRate += WEIGHT_INCREMENT_ON_SPAWN_MISS; } @@ -899,7 +907,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n const encountersPerRunPerBiome = encountersByBiomeRuns.reduce((a, b) => { for (const biome of a.keys()) { - a.set(biome, a.get(biome) + b.get(biome)); + a.set(biome, a.get(biome)! + b.get(biome)!); } return a; }); @@ -910,7 +918,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n const validMEFloorsPerRunPerBiome = validFloorsByBiome.reduce((a, b) => { for (const biome of a.keys()) { - a.set(biome, a.get(biome) + b.get(biome)); + a.set(biome, a.get(biome)! + b.get(biome)!); } return a; }); diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index 307e0a095ff..81dff39da74 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -52,13 +52,13 @@ export function getRandomPlayerPokemon(scene: BattleScene, isAllowedInBattle: bo if (doNotReturnLastAbleMon && unfaintedMons.length === 1) { chosenIndex = randSeedInt(faintedMons.length); - chosenPokemon = faintedMons.at(chosenIndex); + chosenPokemon = faintedMons[chosenIndex]; } else if (isAllowedInBattle) { chosenIndex = randSeedInt(unfaintedMons.length); - chosenPokemon = unfaintedMons.at(chosenIndex); + chosenPokemon = unfaintedMons[chosenIndex]; } else { chosenIndex = randSeedInt(party.length); - chosenPokemon = party.at(chosenIndex); + chosenPokemon = party[chosenIndex]; } return chosenPokemon; @@ -72,17 +72,17 @@ export function getRandomPlayerPokemon(scene: BattleScene, isAllowedInBattle: bo */ export function getHighestLevelPlayerPokemon(scene: BattleScene, unfainted: boolean = false): PlayerPokemon { const party = scene.getParty(); - let pokemon: PlayerPokemon; - party.every(p => { + let pokemon: PlayerPokemon | null = null; + + for (const p of party) { if (unfainted && p.isFainted()) { - return true; + continue; } pokemon = pokemon ? pokemon?.level < p?.level ? p : pokemon : p; - return true; - }); + } - return pokemon; + return pokemon!; } /** @@ -94,17 +94,17 @@ export function getHighestLevelPlayerPokemon(scene: BattleScene, unfainted: bool */ export function getHighestStatPlayerPokemon(scene: BattleScene, stat: Stat, unfainted: boolean = false): PlayerPokemon { const party = scene.getParty(); - let pokemon: PlayerPokemon; - party.every(p => { + let pokemon: PlayerPokemon | null = null; + + for (const p of party) { if (unfainted && p.isFainted()) { - return true; + continue; } pokemon = pokemon ? pokemon.getStat(stat) < p?.getStat(stat) ? p : pokemon : p; - return true; - }); + } - return pokemon; + return pokemon!; } /** @@ -115,17 +115,17 @@ export function getHighestStatPlayerPokemon(scene: BattleScene, stat: Stat, unfa */ export function getLowestLevelPlayerPokemon(scene: BattleScene, unfainted: boolean = false): PlayerPokemon { const party = scene.getParty(); - let pokemon: PlayerPokemon; - party.every(p => { + let pokemon: PlayerPokemon | null = null; + + for (const p of party) { if (unfainted && p.isFainted()) { - return true; + continue; } pokemon = pokemon ? pokemon?.level > p?.level ? p : pokemon : p; - return true; - }); + } - return pokemon; + return pokemon!; } /** @@ -136,17 +136,17 @@ export function getLowestLevelPlayerPokemon(scene: BattleScene, unfainted: boole */ export function getHighestStatTotalPlayerPokemon(scene: BattleScene, unfainted: boolean = false): PlayerPokemon { const party = scene.getParty(); - let pokemon: PlayerPokemon; - party.every(p => { + let pokemon: PlayerPokemon | null = null; + + for (const p of party) { if (unfainted && p.isFainted()) { - return true; + continue; } pokemon = pokemon ? pokemon?.stats.reduce((a, b) => a + b) < p?.stats.reduce((a, b) => a + b) ? p : pokemon : p; - return true; - }); + } - return pokemon; + return pokemon!; } /** @@ -166,8 +166,8 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu .filter(s => getPokemonSpecies(s[0]) && (!excludedSpecies || !excludedSpecies.includes(s[0]))) .map(s => [getPokemonSpecies(s[0]), s[1]]); - if (!isNullOrUndefined(types) && types.length > 0) { - filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || types.includes(s[0].type2)); + if (types && types.length > 0) { + filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2!))); } // If no filtered mons exist at specified starter tiers, will expand starter search range until there are @@ -260,10 +260,12 @@ export function applyHealToPokemon(scene: BattleScene, pokemon: PlayerPokemon, h * @param value */ export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) { - const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE().generateType(null, [value]); - const modifier = modType.newModifier(pokemon); - await pokemon.scene.addModifier(modifier, false, false, false, true); - pokemon.calculateStats(); + const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE().generateType(pokemon.scene.getParty(), [value]); + const modifier = modType?.newModifier(pokemon); + if (modifier) { + await pokemon.scene.addModifier(modifier, false, false, false, true); + pokemon.calculateStats(); + } } /** @@ -479,7 +481,7 @@ function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number, * @param showCatchObtainMessage * @param isObtain */ -export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType, showCatchObtainMessage: boolean = true, isObtain: boolean = false): Promise { +export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, pokeball: Phaser.GameObjects.Sprite | null, pokeballType: PokeballType, showCatchObtainMessage: boolean = true, isObtain: boolean = false): Promise { scene.unshiftPhase(new VictoryPhase(scene, BattlerIndex.ENEMY, true)); const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm(); @@ -508,7 +510,9 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po const doPokemonCatchMenu = () => { const end = () => { scene.pokemonInfoContainer.hide(); - removePb(scene, pokeball); + if (pokeball) { + removePb(scene, pokeball); + } resolve(); }; const removePokemon = () => { diff --git a/src/field/arena.ts b/src/field/arena.ts index cf4e919abf5..da35f3f3281 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -146,7 +146,7 @@ export class Arena { return this.randomSpecies(waveIndex, level, (attempt || 0) + 1); } - const newSpeciesId = ret.getWildSpeciesForLevel(level, true, isBoss, this.scene.gameMode); + const newSpeciesId = ret.getWildSpeciesForLevel(level, true, !!isBoss, this.scene.gameMode); if (newSpeciesId !== ret.speciesId) { console.log("Replaced", Species[ret.speciesId], "with", Species[newSpeciesId]); ret = getPokemonSpecies(newSpeciesId); diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts index 1192e1b5369..2adf26bb2b3 100644 --- a/src/field/mystery-encounter-intro.ts +++ b/src/field/mystery-encounter-intro.ts @@ -4,6 +4,7 @@ import MysteryEncounter from "../data/mystery-encounters/mystery-encounter"; import { Species } from "#enums/species"; import { isNullOrUndefined } from "#app/utils"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import PlayAnimationConfig = Phaser.Types.Animations.PlayAnimationConfig; type KnownFileRoot = | "arenas" @@ -85,7 +86,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con }; if (!isNullOrUndefined(result.species)) { - const keys = getSpriteKeysFromSpecies(result.species); + const keys = getSpriteKeysFromSpecies(result.species!); result.spriteKey = keys.spriteKey; result.fileRoot = keys.fileRoot; result.isPokemon = true; @@ -164,7 +165,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con } } - if (!isNaN(alpha)) { + if (!isNullOrUndefined(alpha)) { sprite.setAlpha(alpha); tintSprite.setAlpha(alpha); } @@ -290,7 +291,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con const tintSprites = this.getTintSprites(); this.spriteConfigs.forEach((config, i) => { if (!config.disableAnimation) { - const trainerAnimConfig = { + const trainerAnimConfig: PlayAnimationConfig = { key: config.spriteKey, repeat: config?.repeat ? -1 : 0, startFrame: config?.startFrame ?? 0 @@ -307,7 +308,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con */ getSpriteAtIndex(index: number): Phaser.GameObjects.Sprite[] { if (!this.spriteConfigs) { - return; + return []; } const ret: Phaser.GameObjects.Sprite[] = []; @@ -319,7 +320,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con getSprites(): Phaser.GameObjects.Sprite[] { if (!this.spriteConfigs) { - return; + return []; } const ret: Phaser.GameObjects.Sprite[] = []; @@ -331,7 +332,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con getTintSprites(): Phaser.GameObjects.Sprite[] { if (!this.spriteConfigs) { - return; + return []; } const ret: Phaser.GameObjects.Sprite[] = []; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7a6b26fcd3c..46b4fba06af 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -108,7 +108,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public mysteryEncounterData: MysteryEncounterPokemonData; /** Used by Mystery Encounters to execute pokemon-specific logic (such as stat boosts) at start of battle */ - public mysteryEncounterBattleEffects: (pokemon: Pokemon) => void = null; + public mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void; public fieldPosition: FieldPosition; diff --git a/src/locales/en/mystery-encounters/delibirdy-dialogue.ts b/src/locales/en/mystery-encounters/delibirdy-dialogue.ts index a77261573a3..2cca9416382 100644 --- a/src/locales/en/mystery-encounters/delibirdy-dialogue.ts +++ b/src/locales/en/mystery-encounters/delibirdy-dialogue.ts @@ -1,6 +1,6 @@ export const delibirdyDialogue = { intro: "A pack of Delibird have appeared!", - title: "Delibird-y", + title: "Delibir-dy", description: "The Delibirds are looking at you expectantly, as if they want something. Perhaps giving them an item or some money would satisfy them?", query: "What will you give them?", invalid_selection: "Pokémon doesn't have that kind of item.", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 8da6d701a9a..6a70b4c7737 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -28,7 +28,6 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; -import { isNullOrUndefined } from "../utils"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -120,26 +119,6 @@ export class ModifierType { return this; } - /** - * Populates the tier field by performing a reverse lookup on the modifier pool specified by {@linkcode poolType} using the - * {@linkcode ModifierType}'s id. - * @param poolType the {@linkcode ModifierPoolType} to look into to derive the item's tier; defaults to {@linkcode ModifierPoolType.PLAYER} - */ - withTierFromPool(poolType: ModifierPoolType = ModifierPoolType.PLAYER): ModifierType { - for (const tier of Object.values(getModifierPoolForType(poolType))) { - for (const modifier of tier) { - if (this.id === modifier.modifierType.id) { - this.tier = modifier.modifierType.tier; - break; - } - } - if (this.tier) { - break; - } - } - return this; - } - /** * Populates item tier for ModifierType instance * Tier is a necessary field for items that appear in player shop (determines the Pokeball visual they use) @@ -2113,10 +2092,10 @@ function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], r allowLuckUpgrades = allowLuckUpgrades ?? true; let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier, undefined, 0, allowLuckUpgrades); let r = 0; - while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) { - candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount, 0, allowLuckUpgrades); + while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group).length) { + candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate?.type.tier ?? tier, candidate?.upgradeCount, 0, allowLuckUpgrades); } - return candidate; + return candidate!; } /** diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index c1d379b97ea..538f34aded7 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -826,7 +826,7 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { args[1].forEach((v, i) => { const isHp = i === 0; let mult = 1; - if (this.stackCount === this.getMaxHeldItemCount(null)) { + if (this.stackCount === this.getMaxHeldItemCount()) { mult = isHp ? 1.05 : 1.1; } const newVal = Math.floor((v + this.stackCount * (isHp ? 1 : 2)) * mult); @@ -840,7 +840,7 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { return 1.2; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon?: Pokemon): integer { return 50; } } diff --git a/src/phases.ts b/src/phases.ts index fff69caac7b..d525cd8f95b 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -5,7 +5,7 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMov import { Mode } from "./ui/ui"; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; -import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier, PokemonResetNegativeStatStageModifier } from "./modifier/modifier"; +import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier, PokemonResetNegativeStatStageModifier, PokemonIncrementingStatModifier } from "./modifier/modifier"; import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler"; import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball"; import { CommonAnim, CommonBattleAnim, initEncounterAnims, initMoveAnim, loadEncounterAnimAssets, loadMoveAnimAssets, MoveAnim } from "./data/battle-anims"; @@ -19,7 +19,7 @@ import { biomeLinks, getBiomeName } from "./data/biomes"; import { ModifierTier } from "./modifier/modifier-tier"; import { CustomModifierSettings, FusePokemonModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, modifierTypes, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, regenerateModifierPoolThresholds, RememberMoveModifierType, TmModifierType } from "./modifier/modifier-type"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import { BattlerTagLapseType, CenterOfAttentionTag, EncoreTag, ProtectedTag, SemiInvulnerableTag, TrappedTag } from "./data/battler-tags"; +import { BattlerTagLapseType, CenterOfAttentionTag, EncoreTag, MysteryEncounterPostSummonTag, ProtectedTag, SemiInvulnerableTag, TrappedTag } from "./data/battler-tags"; import { getPokemonNameWithAffix } from "./messages"; import { Starter } from "./ui/starter-select-ui-handler"; import { Gender } from "./data/gender"; @@ -70,6 +70,7 @@ import { doTrainerExclamation, handleMysteryEncounterBattleStartEffects, handleM import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; +import { isNullOrUndefined } from "./utils"; const { t } = i18next; @@ -865,7 +866,7 @@ export class EncounterPhase extends BattlePhase { // Add intro visuals for mystery encounter mysteryEncounter.initIntroVisuals(this.scene); - this.scene.field.add(mysteryEncounter.introVisuals); + this.scene.field.add(mysteryEncounter.introVisuals!); } let totalBst = 0; @@ -930,7 +931,7 @@ export class EncounterPhase extends BattlePhase { const newEncounter = this.scene.getMysteryEncounter(mysteryEncounter); battle.mysteryEncounter = newEncounter; } - loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter.introVisuals.initSprite())); + loadEnemyAssets.push(battle.mysteryEncounter.introVisuals!.loadAssets().then(() => battle.mysteryEncounter.introVisuals!.initSprite())); // Load Mystery Encounter Exclamation bubble and sfx loadEnemyAssets.push(new Promise(resolve => { this.scene.loadSe("GEN8- Exclaim", "battle_anims", "GEN8- Exclaim.wav"); @@ -1130,7 +1131,7 @@ export class EncounterPhase extends BattlePhase { } } } else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) { - const introVisuals = this.scene.currentBattle.mysteryEncounter.introVisuals; + const introVisuals = this.scene.currentBattle.mysteryEncounter.introVisuals!; introVisuals.playAnim(); if (this.scene.currentBattle.mysteryEncounter.onVisualsStart) { @@ -1148,23 +1149,27 @@ export class EncounterPhase extends BattlePhase { if (showEncounterMessage) { const introDialogue = this.scene.currentBattle.mysteryEncounter.dialogue.intro; - const FIRST_DIALOGUE_PROMPT_DELAY = 750; - let i = 0; - const showNextDialogue = () => { - const nextAction = i === introDialogue.length - 1 ? doShowEncounterOptions : showNextDialogue; - const dialogue = introDialogue[i]; - const title = getEncounterText(this.scene, dialogue.speaker); - const text = getEncounterText(this.scene, dialogue.text); - i++; - if (title) { - this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 1 ? FIRST_DIALOGUE_PROMPT_DELAY : 0); - } else { - this.scene.ui.showText(text, null, nextAction, i === 1 ? FIRST_DIALOGUE_PROMPT_DELAY : 0, true); - } - }; + if (!introDialogue) { + doShowEncounterOptions(); + } else { + const FIRST_DIALOGUE_PROMPT_DELAY = 750; + let i = 0; + const showNextDialogue = () => { + const nextAction = i === introDialogue.length - 1 ? doShowEncounterOptions : showNextDialogue; + const dialogue = introDialogue[i]; + const title = getEncounterText(this.scene, dialogue?.speaker); + const text = getEncounterText(this.scene, dialogue.text)!; + i++; + if (title) { + this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 1 ? FIRST_DIALOGUE_PROMPT_DELAY : 0); + } else { + this.scene.ui.showText(text, null, nextAction, i === 1 ? FIRST_DIALOGUE_PROMPT_DELAY : 0, true); + } + }; - if (introDialogue.length > 0) { - showNextDialogue(); + if (introDialogue.length > 0) { + showNextDialogue(); + } } } else { doShowEncounterOptions(); @@ -1330,7 +1335,7 @@ export class NextEncounterPhase extends EncounterPhase { } if (lastEncounterVisuals) { this.scene.field.remove(lastEncounterVisuals, true); - this.scene.lastMysteryEncounter.introVisuals = null; + this.scene.lastMysteryEncounter.introVisuals = undefined; } if (!this.tryOverrideForBattleSpec()) { @@ -4378,7 +4383,7 @@ export class VictoryPhase extends PokemonPhase { if (participated) { partyMember.addFriendship(2); const machoBraceModifier = partyMember.getHeldItems().find(m => m instanceof PokemonIncrementingStatModifier); - if (!isNullOrUndefined(machoBraceModifier) && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount(this.scene)) { + if (machoBraceModifier && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount(this.scene)) { machoBraceModifier.stackCount++; this.scene.updateModifiers(true, true); partyMember.updateInfo(); @@ -5857,7 +5862,7 @@ export class SelectModifierPhase extends BattlePhase { } else { baseValue = 250; } - const multiplier = !isNullOrUndefined(this.customModifierSettings?.rerollMultiplier) ? this.customModifierSettings.rerollMultiplier : 1; + const multiplier = !isNullOrUndefined(this.customModifierSettings?.rerollMultiplier) ? this.customModifierSettings!.rerollMultiplier! : 1; return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount) * multiplier, Number.MAX_SAFE_INTEGER); } diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index 160a081fda1..bb31ca999f8 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -27,7 +27,7 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; */ export class MysteryEncounterPhase extends Phase { private readonly FIRST_DIALOGUE_PROMPT_DELAY = 300; - optionSelectSettings: OptionSelectSettings; + optionSelectSettings?: OptionSelectSettings; /** * @@ -72,7 +72,7 @@ export class MysteryEncounterPhase extends Phase { if (option.onPreOptionPhase) { this.scene.executeWithSeedOffset(async () => { - return await option.onPreOptionPhase(this.scene) + return await option.onPreOptionPhase!(this.scene) .then((result) => { if (isNullOrUndefined(result) || result) { this.continueEncounter(); @@ -93,7 +93,7 @@ export class MysteryEncounterPhase extends Phase { }; const optionSelectDialogue = this.scene.currentBattle?.mysteryEncounter?.selectedOption?.dialogue; - if (optionSelectDialogue?.selected?.length > 0) { + if (optionSelectDialogue?.selected && optionSelectDialogue.selected.length > 0) { // Handle intermediate dialogue (between player selection event and the onOptionSelect logic) this.scene.ui.setMode(Mode.MESSAGE); const selectedDialogue = optionSelectDialogue.selected; @@ -101,17 +101,17 @@ export class MysteryEncounterPhase extends Phase { const showNextDialogue = () => { const nextAction = i === selectedDialogue.length - 1 ? endDialogueAndContinueEncounter : showNextDialogue; const dialogue = selectedDialogue[i]; - let title: string = null; - const text: string = getEncounterText(this.scene, dialogue.text); + let title: string | null = null; + const text: string | null = getEncounterText(this.scene, dialogue.text); if (dialogue.speaker) { title = getEncounterText(this.scene, dialogue.speaker); } i++; if (title) { - this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0); + this.scene.ui.showDialogue(text ?? "", title, null, nextAction, 0, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0); } else { - this.scene.ui.showText(text, null, nextAction, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0, true); + this.scene.ui.showText(text ?? "", null, nextAction, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0, true); } }; @@ -142,7 +142,7 @@ export class MysteryEncounterOptionSelectedPhase extends Phase { constructor(scene: BattleScene) { super(scene); - this.onOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption.onOptionPhase; + this.onOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption!.onOptionPhase; } start() { @@ -223,10 +223,10 @@ export class MysteryEncounterBattlePhase extends Phase { if (encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { if (scene.currentBattle.double) { - return i18next.t("battle:trainerAppearedDouble", { trainerName: scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }); + return i18next.t("battle:trainerAppearedDouble", { trainerName: scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); } else { - return i18next.t("battle:trainerAppeared", { trainerName: scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }); + return i18next.t("battle:trainerAppeared", { trainerName: scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); } } @@ -276,22 +276,22 @@ export class MysteryEncounterBattlePhase extends Phase { } }; - const encounterMessages = scene.currentBattle.trainer.getEncounterMessages(); + const encounterMessages = scene.currentBattle.trainer?.getEncounterMessages(); - if (!encounterMessages?.length) { + if (!encounterMessages || !encounterMessages.length) { doSummon(); } else { const trainer = this.scene.currentBattle.trainer; let message: string; scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.mysteryEncounter.getSeedOffset()); - + message = message!; // tell TS compiler it's defined now const showDialogueAndSummon = () => { - scene.ui.showDialogue(message, trainer.getName(TrainerSlot.NONE, true), null, () => { + scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => { scene.charSprite.hide().then(() => scene.hideFieldOverlay(250).then(() => doSummon())); }); }; - if (scene.currentBattle.trainer.config.hasCharSprite && !scene.ui.shouldSkipDialogue(message)) { - scene.showFieldOverlay(500).then(() => scene.charSprite.showCharacter(trainer.getKey(), getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); + if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { + this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer?.getKey()!, getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); // TODO: is this bang correct? } else { showDialogueAndSummon(); } @@ -349,6 +349,9 @@ export class MysteryEncounterBattlePhase extends Phase { showEnemyTrainer(): void { // Show enemy trainer const trainer = this.scene.currentBattle.trainer; + if (!trainer) { + return; + } trainer.alpha = 0; trainer.x += 16; trainer.y -= 16; @@ -416,7 +419,7 @@ export class MysteryEncounterRewardsPhase extends Phase { this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene); } else if (this.addHealPhase) { this.scene.tryRemovePhase(p => p instanceof SelectModifierPhase); - this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, null, { fillRemaining: false, rerollMultiplier: 0 })); + this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, undefined, { fillRemaining: false, rerollMultiplier: 0 })); } // Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave) }, this.scene.currentBattle.waveIndex * 1000); @@ -436,11 +439,11 @@ export class MysteryEncounterRewardsPhase extends Phase { */ export class PostMysteryEncounterPhase extends Phase { private readonly FIRST_DIALOGUE_PROMPT_DELAY = 750; - onPostOptionSelect: OptionPhaseCallback; + onPostOptionSelect?: OptionPhaseCallback; constructor(scene: BattleScene) { super(scene); - this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption.onPostOptionPhase; + this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption?.onPostOptionPhase; } start() { @@ -448,7 +451,7 @@ export class PostMysteryEncounterPhase extends Phase { if (this.onPostOptionSelect) { this.scene.executeWithSeedOffset(async () => { - return await this.onPostOptionSelect(this.scene) + return await this.onPostOptionSelect!(this.scene) .then((result) => { if (isNullOrUndefined(result) || result) { this.continueEncounter(); @@ -467,13 +470,13 @@ export class PostMysteryEncounterPhase extends Phase { }; const outroDialogue = this.scene.currentBattle?.mysteryEncounter?.dialogue?.outro; - if (outroDialogue?.length > 0) { + if (outroDialogue && outroDialogue.length > 0) { let i = 0; const showNextDialogue = () => { const nextAction = i === outroDialogue.length - 1 ? endPhase : showNextDialogue; const dialogue = outroDialogue[i]; - let title: string = null; - const text: string = getEncounterText(this.scene, dialogue.text); + let title: string | null = null; + const text: string | null = getEncounterText(this.scene, dialogue.text); if (dialogue.speaker) { title = getEncounterText(this.scene, dialogue.speaker); } @@ -481,9 +484,9 @@ export class PostMysteryEncounterPhase extends Phase { i++; this.scene.ui.setMode(Mode.MESSAGE); if (title) { - this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0); + this.scene.ui.showDialogue(text ?? "", title, null, nextAction, 0, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0); } else { - this.scene.ui.showText(text, null, nextAction, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0, true); + this.scene.ui.showText(text ?? "", null, nextAction, i === 1 ? this.FIRST_DIALOGUE_PROMPT_DELAY : 0, true); } }; diff --git a/src/test/mystery-encounter/encounterTestUtils.ts b/src/test/mystery-encounter/encounterTestUtils.ts index 791c96b3437..3756d24df24 100644 --- a/src/test/mystery-encounter/encounterTestUtils.ts +++ b/src/test/mystery-encounter/encounterTestUtils.ts @@ -10,6 +10,7 @@ import { expect, vi } from "vitest"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import PartyUiHandler from "#app/ui/party-ui-handler"; import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; +import { isNullOrUndefined } from "#app/utils"; /** * Runs a MysteryEncounter to either the start of a battle, or to the MysteryEncounterRewardsPhase, depending on the option selected @@ -18,7 +19,7 @@ import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; * @param secondaryOptionSelect - * @param isBattle - if selecting option should lead to battle, set to true */ -export async function runMysteryEncounterToEnd(game: GameManager, optionNo: number, secondaryOptionSelect: { pokemonNo: number, optionNo?: number } = null, isBattle: boolean = false) { +export async function runMysteryEncounterToEnd(game: GameManager, optionNo: number, secondaryOptionSelect?: { pokemonNo: number, optionNo?: number }, isBattle: boolean = false) { vi.spyOn(EncounterPhaseUtils, "selectPokemonForOption"); await runSelectMysteryEncounterOption(game, optionNo, secondaryOptionSelect); @@ -65,7 +66,7 @@ export async function runMysteryEncounterToEnd(game: GameManager, optionNo: numb } } -export async function runSelectMysteryEncounterOption(game: GameManager, optionNo: number, secondaryOptionSelect: { pokemonNo: number, optionNo?: number } = null) { +export async function runSelectMysteryEncounterOption(game: GameManager, optionNo: number, secondaryOptionSelect?: { pokemonNo: number, optionNo?: number }) { // Handle any eventual queued messages (e.g. weather phase, etc.) game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); @@ -107,8 +108,8 @@ export async function runSelectMysteryEncounterOption(game: GameManager, optionN uiHandler.processInput(Button.ACTION); - if (!isNaN(secondaryOptionSelect?.pokemonNo)) { - await handleSecondaryOptionSelect(game, secondaryOptionSelect.pokemonNo, secondaryOptionSelect.optionNo); + if (!isNullOrUndefined(secondaryOptionSelect?.pokemonNo)) { + await handleSecondaryOptionSelect(game, secondaryOptionSelect!.pokemonNo, secondaryOptionSelect!.optionNo); } } @@ -128,14 +129,14 @@ async function handleSecondaryOptionSelect(game: GameManager, pokemonNo: number, partyUiHandler.processInput(Button.ACTION); // If there is a second choice to make after selecting a Pokemon - if (!isNaN(optionNo)) { + if (!isNullOrUndefined(optionNo)) { // Wait for Summary menu to close and second options to spawn const secondOptionUiHandler = game.scene.ui.handlers[Mode.OPTION_SELECT] as OptionSelectUiHandler; vi.spyOn(secondOptionUiHandler, "show"); await vi.waitFor(() => expect(secondOptionUiHandler.show).toHaveBeenCalled()); // Navigate down to the correct option - for (let i = 1; i < optionNo; i++) { + for (let i = 1; i < optionNo!; i++) { secondOptionUiHandler.processInput(Button.DOWN); } diff --git a/src/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts b/src/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts index 74effa3b29d..fc8460f1325 100644 --- a/src/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts @@ -35,7 +35,7 @@ describe("A Trainer's Test - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], @@ -59,11 +59,11 @@ describe("A Trainer's Test - Mystery Encounter", () => { expect(ATrainersTestEncounter.encounterTier).toBe(MysteryEncounterTier.ROGUE); expect(ATrainersTestEncounter.dialogue).toBeDefined(); expect(ATrainersTestEncounter.dialogue.intro).toBeDefined(); - expect(ATrainersTestEncounter.dialogue.intro[0].speaker).toBeDefined(); - expect(ATrainersTestEncounter.dialogue.intro[0].text).toBeDefined(); - expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(ATrainersTestEncounter.dialogue.intro?.[0].speaker).toBeDefined(); + expect(ATrainersTestEncounter.dialogue.intro?.[0].text).toBeDefined(); + expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(ATrainersTestEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(ATrainersTestEncounter.options.length).toBe(2); }); @@ -92,14 +92,14 @@ describe("A Trainer's Test - Mystery Encounter", () => { expect(ATrainersTestEncounter.onInit).toBeDefined(); ATrainersTestEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(ATrainersTestEncounter.dialogueTokens?.statTrainerName).toBeDefined(); expect(ATrainersTestEncounter.misc.trainerType).toBeDefined(); expect(ATrainersTestEncounter.misc.trainerNameKey).toBeDefined(); expect(ATrainersTestEncounter.misc.trainerEggDescription).toBeDefined(); expect(ATrainersTestEncounter.dialogue.intro).toBeDefined(); - expect(ATrainersTestEncounter.options[1].dialogue.selected).toBeDefined(); + expect(ATrainersTestEncounter.options[1].dialogue?.selected).toBeDefined(); expect(onInitResult).toBe(true); }); @@ -108,19 +108,19 @@ describe("A Trainer's Test - Mystery Encounter", () => { const option = ATrainersTestEncounter.options[0]; expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); expect(option.dialogue).toBeDefined(); - expect(option.dialogue.buttonLabel).toStrictEqual(`${namespace}.option.1.label`); - expect(option.dialogue.buttonTooltip).toStrictEqual(`${namespace}.option.1.tooltip`); + expect(option.dialogue!.buttonLabel).toStrictEqual(`${namespace}.option.1.label`); + expect(option.dialogue!.buttonTooltip).toStrictEqual(`${namespace}.option.1.tooltip`); }); it("Should start battle against the trainer", async () => { await game.runToMysteryEncounter(MysteryEncounterType.A_TRAINERS_TEST, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(scene.currentBattle.trainer).toBeDefined(); - expect(["buck", "cheryl", "marley", "mira", "riley"].includes(scene.currentBattle.trainer.config.name.toLowerCase())).toBeTruthy(); + expect(["buck", "cheryl", "marley", "mira", "riley"].includes(scene.currentBattle.trainer!.config.name.toLowerCase())).toBeTruthy(); expect(enemyField[0]).toBeDefined(); }); @@ -131,10 +131,10 @@ describe("A Trainer's Test - Mystery Encounter", () => { expect(eggsBefore).toBeDefined(); const eggsBeforeLength = eggsBefore.length; - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const eggsAfter = scene.gameData.eggs; expect(eggsAfter).toBeDefined(); @@ -151,7 +151,7 @@ describe("A Trainer's Test - Mystery Encounter", () => { return { totalDuration: 1, destroy: () => null - } as Phaser.Sound.NoAudioSound; + } as any; }); }); @@ -159,8 +159,8 @@ describe("A Trainer's Test - Mystery Encounter", () => { const option = ATrainersTestEncounter.options[1]; expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); expect(option.dialogue).toBeDefined(); - expect(option.dialogue.buttonLabel).toStrictEqual(`${namespace}.option.2.label`); - expect(option.dialogue.buttonTooltip).toStrictEqual(`${namespace}.option.2.tooltip`); + expect(option.dialogue?.buttonLabel).toStrictEqual(`${namespace}.option.2.label`); + expect(option.dialogue?.buttonTooltip).toStrictEqual(`${namespace}.option.2.tooltip`); }); it("Should fully heal the party", async () => { @@ -182,7 +182,7 @@ describe("A Trainer's Test - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const eggsAfter = scene.gameData.eggs; expect(eggsAfter).toBeDefined(); diff --git a/src/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts b/src/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts index d21421cde2b..0c5495ba924 100644 --- a/src/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts @@ -35,7 +35,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -58,9 +58,9 @@ describe("Absolute Avarice - Mystery Encounter", () => { expect(AbsoluteAvariceEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT); expect(AbsoluteAvariceEncounter.dialogue).toBeDefined(); expect(AbsoluteAvariceEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(AbsoluteAvariceEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(AbsoluteAvariceEncounter.options.length).toBe(3); }); @@ -98,7 +98,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { it("should spawn if player has enough berries", async () => { game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT); - game.override.starterHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}]); + game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}]); await game.runToMysteryEncounter(); @@ -106,7 +106,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { }); it("should remove all player's berries at the start of the encounter", async () => { - game.override.starterHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}]); + game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}]); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); @@ -134,13 +134,13 @@ describe("Absolute Avarice - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(Species.GREEDENT); - const moveset = enemyField[0].moveset.map(m => m.moveId); + const moveset = enemyField[0].moveset.map(m => m?.moveId); expect(moveset?.length).toBe(4); expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF]); @@ -151,10 +151,10 @@ describe("Absolute Avarice - Mystery Encounter", () => { it("should give reviver seed to each pokemon after battle", async () => { await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); for (const partyPokemon of scene.getParty()) { const pokemonId = partyPokemon.id; @@ -162,7 +162,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { && (m as PokemonHeldItemModifier).pokemonId === pokemonId, true) as PokemonHeldItemModifier[]; const revSeed = pokemonItems.find(i => i.type.name === "Reviver Seed"); expect(revSeed).toBeDefined; - expect(revSeed.stackCount).toBe(1); + expect(revSeed?.stackCount).toBe(1); } }); }); @@ -184,7 +184,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { }); it("Should return 3 (2/5ths floored) berries if 8 were stolen", async () => { - game.override.starterHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}, {name: "BERRY", count: 3, type: BerryType.APICOT}]); + game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}, {name: "BERRY", count: 3, type: BerryType.APICOT}]); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); @@ -200,7 +200,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { }); it("Should return 2 (2/5ths floored) berries if 7 were stolen", async () => { - game.override.starterHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}, {name: "BERRY", count: 2, type: BerryType.APICOT}]); + game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}, {name: "BERRY", count: 2, type: BerryType.APICOT}]); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); @@ -251,7 +251,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { expect(partyCountBefore + 1).toBe(partyCountAfter); const greedent = scene.getParty()[scene.getParty().length - 1]; expect(greedent.species.speciesId).toBe(Species.GREEDENT); - const moveset = greedent.moveset.map(m => m.moveId); + const moveset = greedent.moveset.map(m => m?.moveId); expect(moveset?.length).toBe(4); expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF]); }); diff --git a/src/test/mystery-encounter/encounters/an-offer-you-cant-refuse-encounter.test.ts b/src/test/mystery-encounter/encounters/an-offer-you-cant-refuse-encounter.test.ts index 128a4c109dc..bbc1a968b5c 100644 --- a/src/test/mystery-encounter/encounters/an-offer-you-cant-refuse-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/an-offer-you-cant-refuse-encounter.test.ts @@ -38,7 +38,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], @@ -65,9 +65,9 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { { text: `${namespace}.intro` }, { speaker: `${namespace}.speaker`, text: `${namespace}.intro_dialogue` } ]); - expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(AnOfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(AnOfferYouCantRefuseEncounter.options.length).toBe(3); }); @@ -104,7 +104,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { expect(AnOfferYouCantRefuseEncounter.onInit).toBeDefined(); AnOfferYouCantRefuseEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(AnOfferYouCantRefuseEncounter.dialogueTokens?.strongestPokemon).toBeDefined(); expect(AnOfferYouCantRefuseEncounter.dialogueTokens?.price).toBeDefined(); @@ -153,7 +153,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { const itemModifier = scene.findModifier(m => m instanceof ShinyRateBoosterModifier) as ShinyRateBoosterModifier; expect(itemModifier).toBeDefined(); - expect(itemModifier.stackCount).toBe(1); + expect(itemModifier?.stackCount).toBe(1); }); it("Should remove the Pokemon from the party", async () => { @@ -199,7 +199,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { it("should award EXP to a pokemon with an ability in EXTORTION_ABILITIES", async () => { await game.runToMysteryEncounter(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, defaultParty); const party = scene.getParty(); - const gyarados = party.find((pkm) => pkm.species.speciesId === Species.GYARADOS); + const gyarados = party.find((pkm) => pkm.species.speciesId === Species.GYARADOS)!; const expBefore = gyarados.exp; await runMysteryEncounterToEnd(game, 2); @@ -210,7 +210,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => { it("should award EXP to a pokemon with a move in EXTORTION_MOVES", async () => { await game.runToMysteryEncounter(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, [Species.ABRA]); const party = scene.getParty(); - const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA); + const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA)!; abra.moveset = [new PokemonMove(Moves.BEAT_UP)]; const expBefore = abra.exp; diff --git a/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts b/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts index 435f890b857..0086cc869ef 100644 --- a/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts @@ -37,7 +37,7 @@ describe("Berries Abound - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -59,9 +59,9 @@ describe("Berries Abound - Mystery Encounter", () => { expect(BerriesAboundEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(BerriesAboundEncounter.dialogue).toBeDefined(); expect(BerriesAboundEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(BerriesAboundEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(BerriesAboundEncounter.options.length).toBe(3); }); @@ -90,12 +90,12 @@ describe("Berries Abound - Mystery Encounter", () => { expect(BerriesAboundEncounter.onInit).toBeDefined(); BerriesAboundEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); const config = BerriesAboundEncounter.enemyPartyConfigs[0]; expect(config).toBeDefined(); expect(config.levelAdditiveMultiplier).toBe(1); - expect(config.pokemonConfigs[0].isBoss).toBe(true); + expect(config.pokemonConfigs?.[0].isBoss).toBe(true); expect(onInitResult).toBe(true); }); @@ -119,12 +119,12 @@ describe("Berries Abound - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - const speciesToSpawn = config.pokemonConfigs[0].species.speciesId; + const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId; - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(speciesToSpawn); }); @@ -133,11 +133,12 @@ describe("Berries Abound - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); const numBerries = game.scene.currentBattle.mysteryEncounter.misc.numBerries; + scene.modifiers = []; - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const berriesAfter = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; const berriesAfterCount = berriesAfter.reduce((a, b) => a + b.stackCount, 0); @@ -147,10 +148,10 @@ describe("Berries Abound - Mystery Encounter", () => { it("should spawn a shop with 5 berries", async () => { await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -178,14 +179,14 @@ describe("Berries Abound - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - const speciesToSpawn = config.pokemonConfigs[0].species.speciesId; + const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId; // Setting enemy's level arbitrarily high to outspeed - config.pokemonConfigs[0].dataSource.level = 1000; + config.pokemonConfigs![0].dataSource!.level = 1000; - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(speciesToSpawn); @@ -207,7 +208,7 @@ describe("Berries Abound - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts b/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts index 80f022a3e3e..136ba5b3d32 100644 --- a/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts @@ -50,7 +50,7 @@ describe("Clowning Around - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -78,9 +78,9 @@ describe("Clowning Around - Mystery Encounter", () => { text: `${namespace}.intro_dialogue`, }, ]); - expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(ClowningAroundEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(ClowningAroundEncounter.options.length).toBe(3); }); @@ -111,23 +111,23 @@ describe("Clowning Around - Mystery Encounter", () => { expect(ClowningAroundEncounter.onInit).toBeDefined(); ClowningAroundEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); const config = ClowningAroundEncounter.enemyPartyConfigs[0]; expect(config.doubleBattle).toBe(true); - expect(config.trainerConfig.trainerType).toBe(TrainerType.HARLEQUIN); - expect(config.pokemonConfigs[0]).toEqual({ + expect(config.trainerConfig?.trainerType).toBe(TrainerType.HARLEQUIN); + expect(config.pokemonConfigs?.[0]).toEqual({ species: getPokemonSpecies(Species.MR_MIME), isBoss: true, moveSet: [Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC] }); - expect(config.pokemonConfigs[1]).toEqual({ + expect(config.pokemonConfigs?.[1]).toEqual({ species: getPokemonSpecies(Species.BLACEPHALON), mysteryEncounterData: expect.anything(), isBoss: true, moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] }); - expect(config.pokemonConfigs[1].mysteryEncounterData.types.length).toBe(2); + expect(config.pokemonConfigs?.[1].mysteryEncounterData?.types.length).toBe(2); expect([ Abilities.STURDY, Abilities.PICKUP, @@ -144,8 +144,8 @@ describe("Clowning Around - Mystery Encounter", () => { Abilities.MAGICIAN, Abilities.SHEER_FORCE, Abilities.PRANKSTER - ]).toContain(config.pokemonConfigs[1].mysteryEncounterData.ability); - expect(ClowningAroundEncounter.misc.ability).toBe(config.pokemonConfigs[1].mysteryEncounterData.ability); + ]).toContain(config.pokemonConfigs?.[1].mysteryEncounterData?.ability); + expect(ClowningAroundEncounter.misc.ability).toBe(config.pokemonConfigs?.[1].mysteryEncounterData?.ability); await vi.waitFor(() => expect(moveInitSpy).toHaveBeenCalled()); await vi.waitFor(() => expect(moveLoadSpy).toHaveBeenCalled()); expect(onInitResult).toBe(true); @@ -172,10 +172,10 @@ describe("Clowning Around - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.CLOWNING_AROUND, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(2); expect(enemyField[0].species.speciesId).toBe(Species.MR_MIME); expect(enemyField[0].moveset).toEqual([new PokemonMove(Moves.TEETER_DANCE), new PokemonMove(Moves.ALLY_SWITCH), new PokemonMove(Moves.DAZZLING_GLEAM), new PokemonMove(Moves.PSYCHIC)]); @@ -191,10 +191,10 @@ describe("Clowning Around - Mystery Encounter", () => { it("should let the player gain the ability after battle completion", async () => { await game.runToMysteryEncounter(MysteryEncounterType.CLOWNING_AROUND, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); const abilityToTrain = scene.currentBattle.mysteryEncounter.misc.ability; @@ -209,7 +209,7 @@ describe("Clowning Around - Mystery Encounter", () => { vi.spyOn(partyUiHandler, "show"); game.endPhase(); await game.phaseInterceptor.to(PostMysteryEncounterPhase); - expect(scene.getCurrentPhase().constructor.name).toBe(PostMysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(PostMysteryEncounterPhase.name); // Wait for Yes/No confirmation to appear await vi.waitFor(() => expect(optionSelectUiHandler.show).toHaveBeenCalled()); @@ -224,7 +224,7 @@ describe("Clowning Around - Mystery Encounter", () => { await game.phaseInterceptor.to(NewBattlePhase, false); const leadPokemon = scene.getParty()[0]; - expect(leadPokemon.mysteryEncounterData.ability).toBe(abilityToTrain); + expect(leadPokemon.mysteryEncounterData?.ability).toBe(abilityToTrain); }); }); @@ -255,6 +255,9 @@ describe("Clowning Around - Mystery Encounter", () => { it("should randomize held items of the Pokemon with the most items, and not the held items of other pokemon", async () => { await game.runToMysteryEncounter(MysteryEncounterType.CLOWNING_AROUND, defaultParty); + // Set some moves on party for attack type booster generation + scene.getParty()[0].moveset = [new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.THIEF)]; + // 2 Sitrus Berries on lead scene.modifiers = []; let itemType = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType; @@ -294,8 +297,8 @@ describe("Clowning Around - Mystery Encounter", () => { const secondItemsAfter = scene.getParty()[1].getHeldItems(); expect(secondItemsAfter.length).toBe(1); expect(secondItemsAfter[0].type.id).toBe("SOUL_DEW"); - expect(secondItemsAfter[0].stackCount).toBe(5); - }); + expect(secondItemsAfter[0]?.stackCount).toBe(5); + }, 2000000); it("should leave encounter without battle", async () => { const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); @@ -342,9 +345,9 @@ describe("Clowning Around - Mystery Encounter", () => { scene.getParty()[2].moveset = []; await runMysteryEncounterToEnd(game, 3); - const leadTypesAfter = scene.getParty()[0].mysteryEncounterData.types; - const secondaryTypesAfter = scene.getParty()[1].mysteryEncounterData.types; - const thirdTypesAfter = scene.getParty()[2].mysteryEncounterData.types; + const leadTypesAfter = scene.getParty()[0].mysteryEncounterData?.types; + const secondaryTypesAfter = scene.getParty()[1].mysteryEncounterData?.types; + const thirdTypesAfter = scene.getParty()[2].mysteryEncounterData?.types; expect(leadTypesAfter.length).toBe(2); expect(leadTypesAfter).not.toBe([Type.ICE, Type.WATER]); diff --git a/src/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts b/src/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts index 89afd9d43aa..1f4571c5d61 100644 --- a/src/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts @@ -37,7 +37,7 @@ describe("Dancing Lessons - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -60,9 +60,9 @@ describe("Dancing Lessons - Mystery Encounter", () => { expect(DancingLessonsEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT); expect(DancingLessonsEncounter.dialogue).toBeDefined(); expect(DancingLessonsEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(DancingLessonsEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(DancingLessonsEncounter.options.length).toBe(3); }); @@ -110,14 +110,14 @@ describe("Dancing Lessons - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.DANCING_LESSONS, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(Species.ORICORIO); expect(enemyField[0].summonData.battleStats).toEqual([1, 1, 1, 1, 1, 0, 0]); - const moveset = enemyField[0].moveset.map(m => m.moveId); + const moveset = enemyField[0].moveset.map(m => m?.moveId); expect(moveset.some(m => m === Moves.REVELATION_DANCE)).toBeTruthy(); const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]); @@ -127,10 +127,10 @@ describe("Dancing Lessons - Mystery Encounter", () => { it("should have a Baton in the rewards after battle", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DANCING_LESSONS, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -205,7 +205,7 @@ describe("Dancing Lessons - Mystery Encounter", () => { expect(partyCountBefore + 1).toBe(partyCountAfter); const oricorio = scene.getParty()[scene.getParty().length - 1]; expect(oricorio.species.speciesId).toBe(Species.ORICORIO); - const moveset = oricorio.moveset.map(m => m.moveId); + const moveset = oricorio.moveset.map(m => m?.moveId); expect(moveset?.some(m => m === Moves.REVELATION_DANCE)).toBeTruthy(); expect(moveset?.some(m => m === Moves.DRAGON_DANCE)).toBeTruthy(); }); @@ -217,7 +217,7 @@ describe("Dancing Lessons - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -226,7 +226,7 @@ describe("Dancing Lessons - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 3); const partyCountAfter = scene.getParty().length; - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); diff --git a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts index 43f9c5612db..136df416ea7 100644 --- a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts @@ -37,7 +37,7 @@ describe("Delibird-y - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -60,9 +60,9 @@ describe("Delibird-y - Mystery Encounter", () => { expect(DelibirdyEncounter.dialogue).toBeDefined(); expect(DelibirdyEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); expect(DelibirdyEncounter.dialogue.outro).toStrictEqual([{ text: `${namespace}.outro` }]); - expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(DelibirdyEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(DelibirdyEncounter.options.length).toBe(3); }); @@ -128,7 +128,7 @@ describe("Delibird-y - Mystery Encounter", () => { const itemModifier = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier) as HiddenAbilityRateBoosterModifier; expect(itemModifier).toBeDefined(); - expect(itemModifier.stackCount).toBe(1); + expect(itemModifier?.stackCount).toBe(1); }); it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => { @@ -148,9 +148,9 @@ describe("Delibird-y - Mystery Encounter", () => { const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier); expect(abilityCharmAfter).toBeDefined(); - expect(abilityCharmAfter.stackCount).toBe(4); + expect(abilityCharmAfter?.stackCount).toBe(4); expect(shellBellAfter).toBeDefined(); - expect(shellBellAfter.stackCount).toBe(1); + expect(shellBellAfter?.stackCount).toBe(1); }); it("should be disabled if player does not have enough money", async () => { @@ -159,7 +159,7 @@ describe("Delibird-y - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -167,7 +167,7 @@ describe("Delibird-y - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 1); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -217,9 +217,9 @@ describe("Delibird-y - Mystery Encounter", () => { const sitrusAfter = scene.findModifier(m => m instanceof BerryModifier); const candyJarAfter = scene.findModifier(m => m instanceof LevelIncrementBoosterModifier); - expect(sitrusAfter.stackCount).toBe(1); + expect(sitrusAfter?.stackCount).toBe(1); expect(candyJarAfter).toBeDefined(); - expect(candyJarAfter.stackCount).toBe(1); + expect(candyJarAfter?.stackCount).toBe(1); }); it("Should remove Reviver Seed and give the player a Healing Charm", async () => { @@ -240,7 +240,7 @@ describe("Delibird-y - Mystery Encounter", () => { expect(reviverSeedAfter).toBeUndefined(); expect(healingCharmAfter).toBeDefined(); - expect(healingCharmAfter.stackCount).toBe(1); + expect(healingCharmAfter?.stackCount).toBe(1); }); it("Should give the player a Shell Bell if they have max stacks of Candy Jars", async () => { @@ -265,11 +265,11 @@ describe("Delibird-y - Mystery Encounter", () => { const candyJarAfter = scene.findModifier(m => m instanceof LevelIncrementBoosterModifier); const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier); - expect(sitrusAfter.stackCount).toBe(1); + expect(sitrusAfter?.stackCount).toBe(1); expect(candyJarAfter).toBeDefined(); - expect(candyJarAfter.stackCount).toBe(99); + expect(candyJarAfter?.stackCount).toBe(99); expect(shellBellAfter).toBeDefined(); - expect(shellBellAfter.stackCount).toBe(1); + expect(shellBellAfter?.stackCount).toBe(1); }); it("Should give the player a Shell Bell if they have max stacks of Healing Charms", async () => { @@ -296,9 +296,9 @@ describe("Delibird-y - Mystery Encounter", () => { expect(reviverSeedAfter).toBeUndefined(); expect(healingCharmAfter).toBeDefined(); - expect(healingCharmAfter.stackCount).toBe(5); + expect(healingCharmAfter?.stackCount).toBe(5); expect(shellBellAfter).toBeDefined(); - expect(shellBellAfter.stackCount).toBe(1); + expect(shellBellAfter?.stackCount).toBe(1); }); it("should be disabled if player does not have any proper items", async () => { @@ -314,7 +314,7 @@ describe("Delibird-y - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -322,7 +322,7 @@ describe("Delibird-y - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 2); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -379,9 +379,9 @@ describe("Delibird-y - Mystery Encounter", () => { const soulDewAfter = scene.findModifier(m => m instanceof PokemonNatureWeightModifier); const berryPouchAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); - expect(soulDewAfter.stackCount).toBe(1); + expect(soulDewAfter?.stackCount).toBe(1); expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter.stackCount).toBe(1); + expect(berryPouchAfter?.stackCount).toBe(1); }); it("Should remove held item and give the player a Berry Pouch", async () => { @@ -402,7 +402,7 @@ describe("Delibird-y - Mystery Encounter", () => { expect(soulDewAfter).toBeUndefined(); expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter.stackCount).toBe(1); + expect(berryPouchAfter?.stackCount).toBe(1); }); it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => { @@ -429,9 +429,9 @@ describe("Delibird-y - Mystery Encounter", () => { expect(soulDewAfter).toBeUndefined(); expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter.stackCount).toBe(3); + expect(berryPouchAfter?.stackCount).toBe(3); expect(shellBellAfter).toBeDefined(); - expect(shellBellAfter.stackCount).toBe(1); + expect(shellBellAfter?.stackCount).toBe(1); }); it("should be disabled if player does not have any proper items", async () => { @@ -447,7 +447,7 @@ describe("Delibird-y - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -455,7 +455,7 @@ describe("Delibird-y - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 3); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); diff --git a/src/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts b/src/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts index 1ffd1708523..89387556cc5 100644 --- a/src/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts @@ -35,7 +35,7 @@ describe("Department Store Sale - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], @@ -65,9 +65,9 @@ describe("Department Store Sale - Mystery Encounter", () => { text: `${namespace}.intro_dialogue`, } ]); - expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(DepartmentStoreSaleEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(DepartmentStoreSaleEncounter.options.length).toBe(4); }); @@ -109,7 +109,7 @@ describe("Department Store Sale - Mystery Encounter", () => { it("should have shop with only TMs", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty); await runMysteryEncounterToEnd(game, 1); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -144,7 +144,7 @@ describe("Department Store Sale - Mystery Encounter", () => { it("should have shop with only Vitamins", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty); await runMysteryEncounterToEnd(game, 2); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -180,7 +180,7 @@ describe("Department Store Sale - Mystery Encounter", () => { it("should have shop with only X Items", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty); await runMysteryEncounterToEnd(game, 3); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -216,7 +216,7 @@ describe("Department Store Sale - Mystery Encounter", () => { it("should have shop with only Pokeballs", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty); await runMysteryEncounterToEnd(game, 4); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts index 31f41a32701..e9c5e303ec1 100644 --- a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts @@ -42,7 +42,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -65,9 +65,9 @@ describe("Fiery Fallout - Mystery Encounter", () => { expect(FieryFalloutEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(FieryFalloutEncounter.dialogue).toBeDefined(); expect(FieryFalloutEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(FieryFalloutEncounter.options.length).toBe(3); }); @@ -106,7 +106,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { expect(FieryFalloutEncounter.onInit).toBeDefined(); FieryFalloutEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(FieryFalloutEncounter.enemyPartyConfigs).toEqual([ { @@ -152,10 +152,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(2); expect(enemyField[0].species.speciesId).toBe(Species.VOLCARONA); expect(enemyField[1].species.speciesId).toBe(Species.VOLCARONA); @@ -169,10 +169,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { it("should give charcoal to lead pokemon", async () => { await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const leadPokemonId = scene.getParty()?.[0].id; const leadPokemonItems = scene.findModifiers(m => m instanceof PokemonHeldItemModifier @@ -202,9 +202,9 @@ describe("Fiery Fallout - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); const party = scene.getParty(); - const lapras = party.find((pkm) => pkm.species.speciesId === Species.LAPRAS); + const lapras = party.find((pkm) => pkm.species.speciesId === Species.LAPRAS)!; lapras.status = new Status(StatusEffect.POISON); - const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA); + const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA)!; vi.spyOn(abra, "isAllowedInBattle").mockReturnValue(false); await runMysteryEncounterToEnd(game, 2); @@ -251,7 +251,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3); // await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const leadPokemonId = scene.getParty()?.[0].id; const leadPokemonItems = scene.findModifiers(m => m instanceof PokemonHeldItemModifier @@ -274,12 +274,12 @@ describe("Fiery Fallout - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const continueEncounterSpy = vi.spyOn((encounterPhase as MysteryEncounterPhase), "continueEncounter"); await runSelectMysteryEncounterOption(game, 3); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(continueEncounterSpy).not.toHaveBeenCalled(); }); }); diff --git a/src/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts b/src/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts index 1c8cee8f8c3..a75fe05be0b 100644 --- a/src/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts @@ -38,7 +38,7 @@ describe("Fight or Flight - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -60,9 +60,9 @@ describe("Fight or Flight - Mystery Encounter", () => { expect(FightOrFlightEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(FightOrFlightEncounter.dialogue).toBeDefined(); expect(FightOrFlightEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(FightOrFlightEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(FightOrFlightEncounter.options.length).toBe(3); }); @@ -91,12 +91,12 @@ describe("Fight or Flight - Mystery Encounter", () => { expect(FightOrFlightEncounter.onInit).toBeDefined(); FightOrFlightEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); const config = FightOrFlightEncounter.enemyPartyConfigs[0]; expect(config).toBeDefined(); expect(config.levelAdditiveMultiplier).toBe(1); - expect(config.pokemonConfigs[0].isBoss).toBe(true); + expect(config.pokemonConfigs?.[0].isBoss).toBe(true); expect(onInitResult).toBe(true); }); @@ -120,12 +120,12 @@ describe("Fight or Flight - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.FIGHT_OR_FLIGHT, defaultParty); const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - const speciesToSpawn = config.pokemonConfigs[0].species.speciesId; + const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId; - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(speciesToSpawn); }); @@ -135,10 +135,10 @@ describe("Fight or Flight - Mystery Encounter", () => { const item = game.scene.currentBattle.mysteryEncounter.misc; - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -171,7 +171,7 @@ describe("Fight or Flight - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -179,7 +179,7 @@ describe("Fight or Flight - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 2); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -196,7 +196,7 @@ describe("Fight or Flight - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts index c9d2d276ecb..f77d9962f01 100644 --- a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts @@ -36,7 +36,7 @@ describe("Lost at Sea - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -59,9 +59,9 @@ describe("Lost at Sea - Mystery Encounter", () => { expect(LostAtSeaEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(LostAtSeaEncounter.dialogue).toBeDefined(); expect(LostAtSeaEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(LostAtSeaEncounter.options.length).toBe(3); }); @@ -98,7 +98,7 @@ describe("Lost at Sea - Mystery Encounter", () => { expect(LostAtSeaEncounter.onInit).toBeDefined(); LostAtSeaEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(LostAtSeaEncounter.dialogueTokens?.damagePercentage).toBe("25"); expect(LostAtSeaEncounter.dialogueTokens?.option1RequiredMove).toBe(Moves[Moves.SURF]); @@ -129,12 +129,12 @@ describe("Lost at Sea - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); - const blastoise = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT); - const expBefore = blastoise.exp; + const blastoise = party.find((pkm) => pkm.species.speciesId === Species.BLASTOISE); + const expBefore = blastoise!.exp; - await runMysteryEncounterToEnd(game, 2); + await runMysteryEncounterToEnd(game, 1); - expect(blastoise.exp).toBe(expBefore + Math.floor(laprasSpecies.baseExp * defaultWave / 5 + 1)); + expect(blastoise?.exp).toBe(expBefore + Math.floor(laprasSpecies.baseExp * defaultWave / 5 + 1)); }); it("should leave encounter without battle", async () => { @@ -152,7 +152,7 @@ describe("Lost at Sea - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -160,7 +160,7 @@ describe("Lost at Sea - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 1); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -194,11 +194,11 @@ describe("Lost at Sea - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); const pidgeot = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT); - const expBefore = pidgeot.exp; + const expBefore = pidgeot!.exp; await runMysteryEncounterToEnd(game, 2); - expect(pidgeot.exp).toBe(expBefore + Math.floor(laprasBaseExp * defaultWave / 5 + 1)); + expect(pidgeot!.exp).toBe(expBefore + Math.floor(laprasBaseExp * defaultWave / 5 + 1)); }); it("should leave encounter without battle", async () => { @@ -216,7 +216,7 @@ describe("Lost at Sea - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -224,7 +224,7 @@ describe("Lost at Sea - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 2); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -254,7 +254,7 @@ describe("Lost at Sea - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); - const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA); + const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA)!; vi.spyOn(abra, "isAllowedInBattle").mockReturnValue(false); await runMysteryEncounterToEnd(game, 3); diff --git a/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts b/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts index 31fb03cb7d3..67cabad2af4 100644 --- a/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts @@ -40,7 +40,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.FIGHT_OR_FLIGHT]], @@ -64,9 +64,9 @@ describe("Mysterious Challengers - Mystery Encounter", () => { expect(MysteriousChallengersEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT); expect(MysteriousChallengersEncounter.dialogue).toBeDefined(); expect(MysteriousChallengersEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(MysteriousChallengersEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(MysteriousChallengersEncounter.options.length).toBe(3); }); @@ -105,7 +105,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { expect(encounter.onInit).toBeDefined(); encounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(encounter.enemyPartyConfigs).toBeDefined(); expect(encounter.enemyPartyConfigs.length).toBe(3); @@ -125,11 +125,11 @@ describe("Mysterious Challengers - Mystery Encounter", () => { female: expect.any(Boolean), } ]); - expect(encounter.enemyPartyConfigs[1].trainerConfig.partyTemplates[0]).toEqual(new TrainerPartyCompoundTemplate( + expect(encounter.enemyPartyConfigs[1].trainerConfig?.partyTemplates[0]).toEqual(new TrainerPartyCompoundTemplate( new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true) )); - expect(encounter.enemyPartyConfigs[2].trainerConfig.partyTemplates[0]).toEqual(new TrainerPartyCompoundTemplate( + expect(encounter.enemyPartyConfigs[2].trainerConfig?.partyTemplates[0]).toEqual(new TrainerPartyCompoundTemplate( new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)) @@ -157,19 +157,19 @@ describe("Mysterious Challengers - Mystery Encounter", () => { it("should start battle against the trainer", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(scene.currentBattle.trainer).toBeDefined(); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); }); it("should have normal trainer rewards after battle", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -199,19 +199,19 @@ describe("Mysterious Challengers - Mystery Encounter", () => { it("should start battle against the trainer", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(scene.currentBattle.trainer).toBeDefined(); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); }); it("should have hard trainer rewards after battle", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -242,19 +242,19 @@ describe("Mysterious Challengers - Mystery Encounter", () => { it("should start battle against the trainer", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 3, null, true); + await runMysteryEncounterToEnd(game, 3, undefined, true); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(scene.currentBattle.trainer).toBeDefined(); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); }); it("should have brutal trainer rewards after battle", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, defaultParty); - await runMysteryEncounterToEnd(game, 3, null, true); + await runMysteryEncounterToEnd(game, 3, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/part-timer-encounter.test.ts b/src/test/mystery-encounter/encounters/part-timer-encounter.test.ts index 95e358bb6ae..df94e4fbe3e 100644 --- a/src/test/mystery-encounter/encounters/part-timer-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/part-timer-encounter.test.ts @@ -36,7 +36,7 @@ describe("Part-Timer - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], @@ -66,9 +66,9 @@ describe("Part-Timer - Mystery Encounter", () => { text: `${namespace}.intro_dialogue`, } ]); - expect(PartTimerEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(PartTimerEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(PartTimerEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(PartTimerEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(PartTimerEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(PartTimerEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(PartTimerEncounter.options.length).toBe(3); }); @@ -127,7 +127,7 @@ describe("Part-Timer - Mystery Encounter", () => { // Expect PP of mon's moves to have been reduced to 2 const moves = scene.getParty()[0].moveset; for (const move of moves) { - expect(move.getMovePp() - move.ppUsed).toBe(2); + expect((move?.getMovePp() ?? 0) - (move?.ppUsed ?? 0)).toBe(2); } }); @@ -147,7 +147,7 @@ describe("Part-Timer - Mystery Encounter", () => { // Expect PP of mon's moves to have been reduced to 2 const moves = scene.getParty()[1].moveset; for (const move of moves) { - expect(move.getMovePp() - move.ppUsed).toBe(2); + expect((move?.getMovePp() ?? 0) - (move?.ppUsed ?? 0)).toBe(2); } }); @@ -192,7 +192,7 @@ describe("Part-Timer - Mystery Encounter", () => { // Expect PP of mon's moves to have been reduced to 2 const moves = scene.getParty()[2].moveset; for (const move of moves) { - expect(move.getMovePp() - move.ppUsed).toBe(2); + expect((move?.getMovePp() ?? 0) - (move?.ppUsed ?? 0)).toBe(2); } }); @@ -212,7 +212,7 @@ describe("Part-Timer - Mystery Encounter", () => { // Expect PP of mon's moves to have been reduced to 2 const moves = scene.getParty()[3].moveset; for (const move of moves) { - expect(move.getMovePp() - move.ppUsed).toBe(2); + expect((move?.getMovePp() ?? 0) - (move?.ppUsed ?? 0)).toBe(2); } }); @@ -252,7 +252,7 @@ describe("Part-Timer - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -260,7 +260,7 @@ describe("Part-Timer - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 3); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); @@ -279,7 +279,7 @@ describe("Part-Timer - Mystery Encounter", () => { // Expect PP of mon's moves to have been reduced to 2 const moves = scene.getParty()[0].moveset; for (const move of moves) { - expect(move.getMovePp() - move.ppUsed).toBe(2); + expect((move?.getMovePp() ?? 0) - (move?.ppUsed ?? 0)).toBe(2); } }); diff --git a/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts b/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts index 833503e2636..7dcf10669d6 100644 --- a/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts @@ -35,7 +35,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], @@ -62,9 +62,9 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { { text: `${namespace}.intro` }, { speaker: `${namespace}.speaker`, text: `${namespace}.intro_dialogue` } ]); - expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(ThePokemonSalesmanEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(ThePokemonSalesmanEncounter.options.length).toBe(2); }); @@ -101,7 +101,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { expect(ThePokemonSalesmanEncounter.onInit).toBeDefined(); ThePokemonSalesmanEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(ThePokemonSalesmanEncounter.dialogueTokens?.purchasePokemon).toBeDefined(); expect(ThePokemonSalesmanEncounter.dialogueTokens?.price).toBeDefined(); @@ -167,7 +167,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); - expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; vi.spyOn(mysteryEncounterPhase, "continueEncounter"); vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); @@ -175,7 +175,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { await runSelectMysteryEncounterOption(game, 1); - expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); diff --git a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts index 5c526ddeb57..e68ee9753df 100644 --- a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts @@ -11,7 +11,6 @@ import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } f import { CommandPhase, MovePhase, SelectModifierPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import BattleScene from "#app/battle-scene"; -import * as Modifiers from "#app/modifier/modifier"; import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter"; import { Nature } from "#app/data/nature"; import { BerryType } from "#enums/berry-type"; @@ -19,7 +18,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { PokemonMove } from "#app/field/pokemon"; import { Mode } from "#app/ui/ui"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import { PokemonBaseStatTotalModifier } from "#app/modifier/modifier"; +import { BerryModifier, PokemonBaseStatTotalModifier } from "#app/modifier/modifier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; @@ -45,7 +44,7 @@ describe("The Strong Stuff - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -68,9 +67,9 @@ describe("The Strong Stuff - Mystery Encounter", () => { expect(TheStrongStuffEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(TheStrongStuffEncounter.dialogue).toBeDefined(); expect(TheStrongStuffEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(TheStrongStuffEncounter.options.length).toBe(2); }); @@ -109,7 +108,7 @@ describe("The Strong Stuff - Mystery Encounter", () => { expect(TheStrongStuffEncounter.onInit).toBeDefined(); TheStrongStuffEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(TheStrongStuffEncounter.enemyPartyConfigs).toEqual([ { @@ -198,19 +197,19 @@ describe("The Strong Stuff - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(Species.SHUCKLE); expect(enemyField[0].summonData.battleStats).toEqual([0, 2, 0, 2, 0, 0, 0]); - const shuckleItems = scene.getModifiers(Modifiers.BerryModifier, false); + const shuckleItems = enemyField[0].getHeldItems(); expect(shuckleItems.length).toBe(4); - expect(shuckleItems.find(m => m.berryType === BerryType.SITRUS)?.stackCount).toBe(1); - expect(shuckleItems.find(m => m.berryType === BerryType.GANLON)?.stackCount).toBe(1); - expect(shuckleItems.find(m => m.berryType === BerryType.APICOT)?.stackCount).toBe(1); - expect(shuckleItems.find(m => m.berryType === BerryType.LUM)?.stackCount).toBe(2); + expect(shuckleItems.find(m => m instanceof BerryModifier && m.berryType === BerryType.SITRUS)?.stackCount).toBe(1); + expect(shuckleItems.find(m => m instanceof BerryModifier && m.berryType === BerryType.GANLON)?.stackCount).toBe(1); + expect(shuckleItems.find(m => m instanceof BerryModifier && m.berryType === BerryType.APICOT)?.stackCount).toBe(1); + expect(shuckleItems.find(m => m instanceof BerryModifier && m.berryType === BerryType.LUM)?.stackCount).toBe(2); expect(enemyField[0].moveset).toEqual([new PokemonMove(Moves.INFESTATION), new PokemonMove(Moves.SALT_CURE), new PokemonMove(Moves.GASTRO_ACID), new PokemonMove(Moves.HEAL_ORDER)]); // Should have used moves pre-battle @@ -222,10 +221,10 @@ describe("The Strong Stuff - Mystery Encounter", () => { it("should have Soul Dew in rewards", async () => { await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts b/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts index 667c2d2ec3d..f30acd3b0a4 100644 --- a/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts @@ -43,7 +43,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); const biomeMap = new Map([ [Biome.VOLCANO, [MysteryEncounterType.FIGHT_OR_FLIGHT]], @@ -73,9 +73,9 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { text: `${namespace}.intro_dialogue`, } ]); - expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(TheWinstrateChallengeEncounter.options.length).toBe(2); }); @@ -114,7 +114,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { expect(encounter.onInit).toBeDefined(); encounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(encounter.enemyPartyConfigs).toBeDefined(); expect(encounter.enemyPartyConfigs.length).toBe(5); @@ -273,42 +273,42 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { it("should battle all 5 trainers for a Macho Brace reward", async () => { await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty); - await runMysteryEncounterToEnd(game, 1, null, true); + await runMysteryEncounterToEnd(game, 1, undefined, true); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(scene.currentBattle.trainer).toBeDefined(); - expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICTOR); + expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICTOR); expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(4); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); await skipBattleToNextBattle(game); expect(scene.currentBattle.trainer).toBeDefined(); - expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICTORIA); + expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICTORIA); expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(3); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); await skipBattleToNextBattle(game); expect(scene.currentBattle.trainer).toBeDefined(); - expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VIVI); + expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VIVI); expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(2); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); await skipBattleToNextBattle(game); expect(scene.currentBattle.trainer).toBeDefined(); - expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICKY); + expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICKY); expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(1); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); await skipBattleToNextBattle(game); expect(scene.currentBattle.trainer).toBeDefined(); - expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VITO); + expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VITO); expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(0); expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE); // Should have Macho Brace in the rewards await skipBattleToNextBattle(game, true); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); @@ -348,7 +348,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { it("should have a Rarer Candy in the rewards", async () => { await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty); await runMysteryEncounterToEnd(game, 2); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts b/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts index 3d4cd8855cd..37e7ffd1e40 100644 --- a/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts @@ -41,7 +41,7 @@ describe("Trash to Treasure - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -63,9 +63,9 @@ describe("Trash to Treasure - Mystery Encounter", () => { expect(TrashToTreasureEncounter.encounterTier).toBe(MysteryEncounterTier.ULTRA); expect(TrashToTreasureEncounter.dialogue).toBeDefined(); expect(TrashToTreasureEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); - expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(TrashToTreasureEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(TrashToTreasureEncounter.options.length).toBe(2); }); @@ -96,7 +96,7 @@ describe("Trash to Treasure - Mystery Encounter", () => { expect(TrashToTreasureEncounter.onInit).toBeDefined(); TrashToTreasureEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(TrashToTreasureEncounter.enemyPartyConfigs).toEqual([ { @@ -138,19 +138,19 @@ describe("Trash to Treasure - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.TRASH_TO_TREASURE, defaultParty); await runMysteryEncounterToEnd(game, 1); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const leftovers = scene.findModifier(m => m instanceof TurnHealModifier) as TurnHealModifier; expect(leftovers).toBeDefined(); - expect(leftovers.stackCount).toBe(2); + expect(leftovers?.stackCount).toBe(2); const shellBell = scene.findModifier(m => m instanceof HitHealModifier) as HitHealModifier; expect(shellBell).toBeDefined(); - expect(shellBell.stackCount).toBe(2); + expect(shellBell?.stackCount).toBe(2); const blackSludge = scene.findModifier(m => m instanceof RemoveHealShopModifier) as RemoveHealShopModifier; expect(blackSludge).toBeDefined(); - expect(blackSludge.stackCount).toBe(1); + expect(blackSludge?.stackCount).toBe(1); }); it("should leave encounter without battle", async () => { @@ -183,10 +183,10 @@ describe("Trash to Treasure - Mystery Encounter", () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); await game.runToMysteryEncounter(MysteryEncounterType.TRASH_TO_TREASURE, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); const enemyField = scene.getEnemyField(); - expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); expect(enemyField.length).toBe(1); expect(enemyField[0].species.speciesId).toBe(Species.GARBODOR); expect(enemyField[0].moveset).toEqual([new PokemonMove(Moves.PAYBACK), new PokemonMove(Moves.GUNK_SHOT), new PokemonMove(Moves.STOMPING_TANTRUM), new PokemonMove(Moves.DRAIN_PUNCH)]); @@ -200,10 +200,10 @@ describe("Trash to Treasure - Mystery Encounter", () => { it("should have 2 Rogue, 1 Ultra, 1 Great in rewards", async () => { await game.runToMysteryEncounter(MysteryEncounterType.TRASH_TO_TREASURE, defaultParty); - await runMysteryEncounterToEnd(game, 2, null, true); + await runMysteryEncounterToEnd(game, 2, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts b/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts index 0650b3b0ad4..fc5b868f1a1 100644 --- a/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts @@ -36,7 +36,7 @@ describe("Weird Dream - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(true); + game.override.disableTrainerWaves(); vi.spyOn(EncounterTransformationSequence, "doPokemonTransformationSequence").mockImplementation(() => new Promise(resolve => resolve())); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( @@ -67,9 +67,9 @@ describe("Weird Dream - Mystery Encounter", () => { text: `${namespace}.intro_dialogue`, }, ]); - expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`); - expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`); - expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`); + expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`); + expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`); + expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`); expect(WeirdDreamEncounter.options.length).toBe(2); }); @@ -99,7 +99,7 @@ describe("Weird Dream - Mystery Encounter", () => { expect(WeirdDreamEncounter.onInit).toBeDefined(); WeirdDreamEncounter.populateDialogueTokensFromRequirements(scene); - const onInitResult = onInit(scene); + const onInitResult = onInit!(scene); expect(loadBgmSpy).toHaveBeenCalled(); expect(onInitResult).toBe(true); @@ -129,7 +129,7 @@ describe("Weird Dream - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); const pokemonAfter = scene.getParty(); const bstsAfter = pokemonAfter.map(pokemon => pokemon.getSpeciesForm().getBaseStatTotal()); @@ -138,7 +138,7 @@ describe("Weird Dream - Mystery Encounter", () => { for (let i = 0; i < pokemonAfter.length; i++) { const newPokemon = pokemonAfter[i]; expect(newPokemon.getSpeciesForm().speciesId).not.toBe(pokemonPrior[i].getSpeciesForm().speciesId); - expect(newPokemon.mysteryEncounterData.types.length).toBe(2); + expect(newPokemon.mysteryEncounterData?.types.length).toBe(2); } const plus90To110 = bstDiff.filter(bst => bst > 80); @@ -152,7 +152,7 @@ describe("Weird Dream - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); await runMysteryEncounterToEnd(game, 1); await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); + expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); diff --git a/src/test/mystery-encounter/mystery-encounter-utils.test.ts b/src/test/mystery-encounter/mystery-encounter-utils.test.ts index a0e055e3bcf..26442f9eaf4 100644 --- a/src/test/mystery-encounter/mystery-encounter-utils.test.ts +++ b/src/test/mystery-encounter/mystery-encounter-utils.test.ts @@ -230,7 +230,7 @@ describe("Mystery Encounter Utils", () => { it("gets species of specified types", () => { // Only 9 tiers are: Koraidon, Miraidon, Arceus, Rayquaza, Kyogre, Groudon, Zacian - const result = getRandomSpeciesByStarterTier(9, null, [Type.GROUND]); + const result = getRandomSpeciesByStarterTier(9, undefined, [Type.GROUND]); const pokeSpecies = getPokemonSpecies(result); expect(pokeSpecies.speciesId).toBe(Species.GROUDON); }); diff --git a/src/test/mystery-encounter/mystery-encounter.test.ts b/src/test/mystery-encounter/mystery-encounter.test.ts index 0ba28bb77ec..d2a2e7f9d92 100644 --- a/src/test/mystery-encounter/mystery-encounter.test.ts +++ b/src/test/mystery-encounter/mystery-encounter.test.ts @@ -29,14 +29,14 @@ describe("Mystery Encounters", () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); - expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(MysteryEncounterPhase.name); }); it("", async () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); - expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(MysteryEncounterPhase.name); }); it("spawns mysterious challengers encounter", async () => { diff --git a/src/test/phases/mystery-encounter-phase.test.ts b/src/test/phases/mystery-encounter-phase.test.ts index 74ed7ff190d..5e02f6c94ab 100644 --- a/src/test/phases/mystery-encounter-phase.test.ts +++ b/src/test/phases/mystery-encounter-phase.test.ts @@ -37,7 +37,7 @@ describe("Mystery Encounter Phases", () => { await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); - expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); + expect(game.scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); }); it("Runs MysteryEncounterPhase", async() => { @@ -73,7 +73,7 @@ describe("Mystery Encounter Phases", () => { handler.processInput(Button.ACTION); // Waitfor required so that option select messages and preOptionPhase logic are handled - await vi.waitFor(() => expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterOptionSelectedPhase.name)); + await vi.waitFor(() => expect(game.scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterOptionSelectedPhase.name)); expect(game.scene.ui.getMode()).toBe(Mode.MESSAGE); expect(dialogueSpy).toHaveBeenCalledTimes(1); expect(messageSpy).toHaveBeenCalledTimes(2); diff --git a/src/test/phases/select-modifier-phase.test.ts b/src/test/phases/select-modifier-phase.test.ts index 7efcf47ac03..13c907c6414 100644 --- a/src/test/phases/select-modifier-phase.test.ts +++ b/src/test/phases/select-modifier-phase.test.ts @@ -28,12 +28,6 @@ describe("SelectModifierPhase", () => { game = new GameManager(phaserGame); scene = game.scene; - vi.spyOn(scene, "resetSeed").mockImplementation(() => { - scene.waveSeed = "test"; - Phaser.Math.RND.sow([scene.waveSeed]); - scene.rngCounter = 0; - }); - initSceneWithoutEncounterPhase(scene, [Species.ABRA, Species.VOLCARONA]); }); @@ -49,7 +43,7 @@ describe("SelectModifierPhase", () => { await game.phaseInterceptor.run(SelectModifierPhase); expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); - }, 20000); + }); it("should generate random modifiers", async () => { const selectModifierPhase = new SelectModifierPhase(scene); @@ -60,10 +54,7 @@ describe("SelectModifierPhase", () => { expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler; expect(modifierSelectHandler.options.length).toEqual(3); - expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TEMP_STAT_BOOSTER"); - expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("POKEBALL"); - expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("BERRY"); - }, 5000); + }); it("should modify reroll cost", async () => { const options = [ @@ -73,12 +64,12 @@ describe("SelectModifierPhase", () => { ]; const selectModifierPhase1 = new SelectModifierPhase(scene); - const selectModifierPhase2 = new SelectModifierPhase(scene, 0, null, { rerollMultiplier: 2 }); + const selectModifierPhase2 = new SelectModifierPhase(scene, 0, undefined, { rerollMultiplier: 2 }); const cost1 = selectModifierPhase1.getRerollCost(options, false); const cost2 = selectModifierPhase2.getRerollCost(options, false); expect(cost2).toEqual(cost1 * 2); - }, 5000); + }); it("should generate random modifiers from reroll", async () => { let selectModifierPhase = new SelectModifierPhase(scene); @@ -88,9 +79,6 @@ describe("SelectModifierPhase", () => { expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler; expect(modifierSelectHandler.options.length).toEqual(3); - expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TEMP_STAT_BOOSTER"); - expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("POKEBALL"); - expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("BERRY"); // Simulate selecting reroll selectModifierPhase = new SelectModifierPhase(scene, 1, [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.COMMON]); @@ -100,10 +88,7 @@ describe("SelectModifierPhase", () => { expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); expect(modifierSelectHandler.options.length).toEqual(3); - expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TM_COMMON"); - expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("LURE"); - expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("PP_UP"); - }, 5000); + }); it("should generate random modifiers of same tier for reroll with reroll lock", async () => { // Just use fully random seed for this test @@ -137,13 +122,13 @@ describe("SelectModifierPhase", () => { expect(modifierSelectHandler.options[0].modifierTypeOption.type.tier - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[0]); expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[1]); expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[2]); - }, 5000); + }); it("should generate custom modifiers", async () => { const customModifiers: CustomModifierSettings = { guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_ULTRA, modifierTypes.LEFTOVERS, modifierTypes.AMULET_COIN, modifierTypes.GOLDEN_PUNCH] }; - const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers); + const selectModifierPhase = new SelectModifierPhase(scene, 0, undefined, customModifiers); scene.pushPhase(selectModifierPhase); await game.phaseInterceptor.run(SelectModifierPhase); @@ -156,7 +141,7 @@ describe("SelectModifierPhase", () => { expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("LEFTOVERS"); expect(modifierSelectHandler.options[3].modifierTypeOption.type.id).toEqual("AMULET_COIN"); expect(modifierSelectHandler.options[4].modifierTypeOption.type.id).toEqual("GOLDEN_PUNCH"); - }, 5000); + }); it("should generate custom modifier tiers that can upgrade from luck", async () => { const customModifiers: CustomModifierSettings = { @@ -170,7 +155,7 @@ describe("SelectModifierPhase", () => { } scene.getParty().push(pokemon, pokemon, pokemon, pokemon, pokemon, pokemon); - const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers); + const selectModifierPhase = new SelectModifierPhase(scene, 0, undefined, customModifiers); scene.pushPhase(selectModifierPhase); await game.phaseInterceptor.run(SelectModifierPhase); @@ -183,14 +168,14 @@ describe("SelectModifierPhase", () => { expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ULTRA); expect(modifierSelectHandler.options[3].modifierTypeOption.type.tier - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ROGUE); expect(modifierSelectHandler.options[4].modifierTypeOption.type.tier - modifierSelectHandler.options[4].modifierTypeOption.upgradeCount).toEqual(ModifierTier.MASTER); - }, 5000); + }); it("should generate custom modifiers and modifier tiers together", async () => { const customModifiers: CustomModifierSettings = { guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_COMMON], guaranteedModifierTiers: [ModifierTier.MASTER, ModifierTier.MASTER] }; - const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers); + const selectModifierPhase = new SelectModifierPhase(scene, 0, undefined, customModifiers); scene.pushPhase(selectModifierPhase); await game.phaseInterceptor.run(SelectModifierPhase); @@ -202,7 +187,7 @@ describe("SelectModifierPhase", () => { expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("TM_COMMON"); expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER); expect(modifierSelectHandler.options[3].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER); - }, 5000); + }); it("should fill remaining modifiers if fillRemaining is true with custom modifiers", async () => { const customModifiers: CustomModifierSettings = { @@ -210,7 +195,7 @@ describe("SelectModifierPhase", () => { guaranteedModifierTiers: [ModifierTier.MASTER], fillRemaining: true }; - const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers); + const selectModifierPhase = new SelectModifierPhase(scene, 0, undefined, customModifiers); scene.pushPhase(selectModifierPhase); await game.phaseInterceptor.run(SelectModifierPhase); @@ -220,5 +205,5 @@ describe("SelectModifierPhase", () => { expect(modifierSelectHandler.options.length).toEqual(3); expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MEMORY_MUSHROOM"); expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER); - }, 5000); + }); }); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 260df8e79c5..a3e0b972f63 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -171,8 +171,8 @@ export default class GameManager { */ async runToMysteryEncounter(encounterType?: MysteryEncounterType, species?: Species[]) { if (!isNullOrUndefined(encounterType)) { - this.override.disableTrainerWaves(true); - this.override.mysteryEncounter(encounterType); + this.override.disableTrainerWaves(); + this.override.mysteryEncounter(encounterType!); } await this.runToTitle(); diff --git a/src/test/utils/gameManagerUtils.ts b/src/test/utils/gameManagerUtils.ts index f4aecbbb096..ff0f735c82d 100644 --- a/src/test/utils/gameManagerUtils.ts +++ b/src/test/utils/gameManagerUtils.ts @@ -108,5 +108,5 @@ export function initSceneWithoutEncounterPhase(scene, species?: Species[]) { scene.getParty().push(starterPokemon); }); - scene.currentBattle = new Battle(getGameMode(GameModes.CLASSIC), 5, BattleType.WILD, null, false); + scene.currentBattle = new Battle(getGameMode(GameModes.CLASSIC), 5, BattleType.WILD, undefined, false); } diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index d5eaee003db..40f0111ae78 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -8,8 +8,10 @@ import * as GameMode from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import { ModifierOverride } from "#app/modifier/modifier-type.js"; import Overrides from "#app/overrides"; -import { vi } from "vitest"; +import { MockInstance, vi } from "vitest"; import { GameManagerHelper } from "./gameManagerHelper"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; /** * Helper to handle overrides in tests @@ -281,6 +283,41 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override the encounter chance for a mystery encounter. + * @param percentage the encounter chance in % + * @returns spy instance + */ + mysteryEncounterChance(percentage: number) { + const maxRate: number = 256; // 100% + const rate = maxRate * (percentage / 100); + const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate); + this.log(`Mystery encounter chance set to ${percentage}% (=${rate})!`); + return spy; + } + + /** + * Override the encounter chance for a mystery encounter. + * @returns spy instance + * @param tier + */ + mysteryEncounterTier(tier: MysteryEncounterTier): MockInstance { + const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_TIER_OVERRIDE", "get").mockReturnValue(tier); + this.log(`Mystery encounter tier set to ${tier}!`); + return spy; + } + + /** + * Override the encounter that spawns for the scene + * @param encounterType + * @returns spy instance + */ + mysteryEncounter(encounterType: MysteryEncounterType) { + const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(encounterType); + this.log(`Mystery encounter override set to ${encounterType}!`); + return spy; + } + private log(...params: any[]) { console.log("Overrides:", ...params); } diff --git a/src/test/utils/mocks/mockGameObject.ts b/src/test/utils/mocks/mockGameObject.ts index 9138e0f687a..4c243ec9ca1 100644 --- a/src/test/utils/mocks/mockGameObject.ts +++ b/src/test/utils/mocks/mockGameObject.ts @@ -1,3 +1,3 @@ export interface MockGameObject { - + name: string; } diff --git a/src/test/utils/mocks/mocksContainer/mockContainer.ts b/src/test/utils/mocks/mocksContainer/mockContainer.ts index 319d702bfd9..78d84f7845b 100644 --- a/src/test/utils/mocks/mocksContainer/mockContainer.ts +++ b/src/test/utils/mocks/mocksContainer/mockContainer.ts @@ -14,7 +14,7 @@ export default class MockContainer implements MockGameObject { public frame; protected textureManager; public list: MockGameObject[] = []; - private name?: string; + name: string; constructor(textureManager: MockTextureManager, x, y) { this.x = x; diff --git a/src/test/utils/mocks/mocksContainer/mockGraphics.ts b/src/test/utils/mocks/mocksContainer/mockGraphics.ts index e026b212e16..70a38c80aa0 100644 --- a/src/test/utils/mocks/mocksContainer/mockGraphics.ts +++ b/src/test/utils/mocks/mocksContainer/mockGraphics.ts @@ -3,6 +3,7 @@ import { MockGameObject } from "../mockGameObject"; export default class MockGraphics implements MockGameObject { private scene; public list: MockGameObject[] = []; + name: string; constructor(textureManager, config) { this.scene = textureManager.scene; } diff --git a/src/test/utils/mocks/mocksContainer/mockRectangle.ts b/src/test/utils/mocks/mocksContainer/mockRectangle.ts index 26c2f74ea42..696427d10a3 100644 --- a/src/test/utils/mocks/mocksContainer/mockRectangle.ts +++ b/src/test/utils/mocks/mocksContainer/mockRectangle.ts @@ -4,6 +4,7 @@ export default class MockRectangle implements MockGameObject { private fillColor; private scene; public list: MockGameObject[] = []; + name: string; constructor(textureManager, x, y, width, height, fillColor) { this.fillColor = fillColor; diff --git a/src/test/utils/mocks/mocksContainer/mockSprite.ts b/src/test/utils/mocks/mocksContainer/mockSprite.ts index 9c566fc4bcb..6020b6aadc0 100644 --- a/src/test/utils/mocks/mocksContainer/mockSprite.ts +++ b/src/test/utils/mocks/mocksContainer/mockSprite.ts @@ -14,6 +14,7 @@ export default class MockSprite implements MockGameObject { public scene; public anims; public list: MockGameObject[] = []; + name: string; constructor(textureManager, x, y, texture) { this.textureManager = textureManager; this.scene = textureManager.scene; diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts index 825f2474a6f..f307da99361 100644 --- a/src/test/utils/mocks/mocksContainer/mockText.ts +++ b/src/test/utils/mocks/mocksContainer/mockText.ts @@ -11,7 +11,7 @@ export default class MockText implements MockGameObject { public list: MockGameObject[] = []; public style; public text = ""; - private name?: string; + name: string; public color?: string; constructor(textureManager, x, y, content, styleOptions) { diff --git a/src/test/utils/mocks/mocksContainer/mockTexture.ts b/src/test/utils/mocks/mocksContainer/mockTexture.ts index 03bedb4751b..988e9be150f 100644 --- a/src/test/utils/mocks/mocksContainer/mockTexture.ts +++ b/src/test/utils/mocks/mocksContainer/mockTexture.ts @@ -12,6 +12,7 @@ export default class MockTexture implements MockGameObject { public source; public frames: object; public firstFrame: string; + name: string; constructor(manager, key: string, source) { this.manager = manager; diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 40644683a99..d30adf11f7d 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -336,7 +336,7 @@ export default class PhaseInterceptor { const actionForNextPrompt = this.prompts[0]; const expireFn = actionForNextPrompt.expireFn && actionForNextPrompt.expireFn(); const currentMode = this.scene.ui.getMode(); - const currentPhase = this.scene.getCurrentPhase().constructor.name; + const currentPhase = this.scene.getCurrentPhase()?.constructor.name; const currentHandler = this.scene.ui.getHandler(); if (expireFn) { this.prompts.shift(); diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index d5bae208629..094b8264bb1 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -18,24 +18,24 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; export default class MysteryEncounterUiHandler extends UiHandler { private cursorContainer: Phaser.GameObjects.Container; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj?: Phaser.GameObjects.Image; private optionsContainer: Phaser.GameObjects.Container; private tooltipWindow: Phaser.GameObjects.NineSlice; private tooltipContainer: Phaser.GameObjects.Container; - private tooltipScrollTween: Phaser.Tweens.Tween; + private tooltipScrollTween?: Phaser.Tweens.Tween; private descriptionWindow: Phaser.GameObjects.NineSlice; private descriptionContainer: Phaser.GameObjects.Container; - private descriptionScrollTween: Phaser.Tweens.Tween; + private descriptionScrollTween?: Phaser.Tweens.Tween; private rarityBall: Phaser.GameObjects.Sprite; private dexProgressWindow: Phaser.GameObjects.NineSlice; private dexProgressContainer: Phaser.GameObjects.Container; private showDexProgress: boolean = false; - private overrideSettings: OptionSelectSettings; + private overrideSettings?: OptionSelectSettings; private encounterOptions: MysteryEncounterOption[] = []; private optionsMeetsReqs: boolean[]; @@ -330,9 +330,9 @@ export default class MysteryEncounterUiHandler extends UiHandler { this.encounterOptions = this.overrideSettings?.overrideOptions ?? mysteryEncounter.options; this.optionsMeetsReqs = []; - const titleText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.title, TextStyle.TOOLTIP_TITLE); - const descriptionText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.description, TextStyle.TOOLTIP_CONTENT); - const queryText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.query, TextStyle.TOOLTIP_CONTENT); + const titleText: string | null = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue?.title, TextStyle.TOOLTIP_TITLE); + const descriptionText: string | null = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue?.description, TextStyle.TOOLTIP_CONTENT); + const queryText: string | null = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue?.query, TextStyle.TOOLTIP_CONTENT); // Clear options container (except cursor) this.optionsContainer.removeAll(true); @@ -355,9 +355,9 @@ export default class MysteryEncounterUiHandler extends UiHandler { } this.optionsMeetsReqs.push(option.meetsRequirements(this.scene)); - const optionDialogue = option.dialogue; + const optionDialogue = option.dialogue!; const label = !this.optionsMeetsReqs[i] && optionDialogue.disabledButtonLabel ? optionDialogue.disabledButtonLabel : optionDialogue.buttonLabel; - let text: string; + let text: string | null; if (option.hasRequirements() && this.optionsMeetsReqs[i] && (option.optionMode === MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)) { // Options with special requirements that are met are automatically colored green text = getEncounterText(this.scene, label, TextStyle.SUMMARY_GREEN); @@ -383,7 +383,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { this.optionsContainer.add(viewPartyText); // Description Window - const titleTextObject = addBBCodeTextObject(this.scene, 0, 0, titleText, TextStyle.TOOLTIP_TITLE, { wordWrap: { width: 750 }, align: "center", lineSpacing: -8 }); + const titleTextObject = addBBCodeTextObject(this.scene, 0, 0, titleText ?? "", TextStyle.TOOLTIP_TITLE, { wordWrap: { width: 750 }, align: "center", lineSpacing: -8 }); this.descriptionContainer.add(titleTextObject); titleTextObject.setPosition(72 - titleTextObject.displayWidth / 2, 5.5); @@ -395,7 +395,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { const ballType = getPokeballAtlasKey(index); this.rarityBall.setTexture("pb", ballType); - const descriptionTextObject = addBBCodeTextObject(this.scene, 6, 25, descriptionText, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } }); + const descriptionTextObject = addBBCodeTextObject(this.scene, 6, 25, descriptionText ?? "", TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } }); // Sets up the mask that hides the description text to give an illusion of scrolling const descriptionTextMaskRect = this.scene.make.graphics({}); @@ -412,7 +412,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (this.descriptionScrollTween) { this.descriptionScrollTween.remove(); - this.descriptionScrollTween = null; + this.descriptionScrollTween = undefined; } // Animates the description text moving upwards @@ -429,7 +429,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { this.descriptionContainer.add(descriptionTextObject); - const queryTextObject = addBBCodeTextObject(this.scene, 0, 0, queryText, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } }); + const queryTextObject = addBBCodeTextObject(this.scene, 0, 0, queryText ?? "", TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } }); this.descriptionContainer.add(queryTextObject); queryTextObject.setPosition(75 - queryTextObject.displayWidth / 2, 90); @@ -460,9 +460,9 @@ export default class MysteryEncounterUiHandler extends UiHandler { return; } - let text: string; + let text: string | null; const cursorOption = this.encounterOptions[cursor]; - const optionDialogue = cursorOption.dialogue; + const optionDialogue = cursorOption.dialogue!; if (!this.optionsMeetsReqs[cursor] && (cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT || cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) && optionDialogue.disabledButtonTooltip) { text = getEncounterText(this.scene, optionDialogue.disabledButtonTooltip, TextStyle.TOOLTIP_CONTENT); } else { @@ -470,9 +470,11 @@ export default class MysteryEncounterUiHandler extends UiHandler { } // Auto-color options green/blue for good/bad by looking for (+)/(-) - const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0]; - text = text.replace(/(\(\+\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) + "[/color][/shadow]" + primaryStyleString); - text = text.replace(/(\(\-\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) + "[/color][/shadow]" + primaryStyleString); + if (text) { + const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))!][0]; + text = text.replace(/(\(\+\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) + "[/color][/shadow]" + primaryStyleString); + text = text.replace(/(\(\-\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) + "[/color][/shadow]" + primaryStyleString); + } if (text) { const tooltipTextObject = addBBCodeTextObject(this.scene, 6, 7, text, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 600 }, fontSize: "72px" }); @@ -492,7 +494,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (this.tooltipScrollTween) { this.tooltipScrollTween.remove(); - this.tooltipScrollTween = null; + this.tooltipScrollTween = undefined; } // Animates the tooltip text moving upwards @@ -518,7 +520,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { clear(): void { super.clear(); - this.overrideSettings = null; + this.overrideSettings = undefined; this.optionsContainer.setVisible(false); this.optionsContainer.removeAll(true); this.dexProgressContainer.setVisible(false); @@ -534,7 +536,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (this.cursorObj) { this.cursorObj.destroy(); } - this.cursorObj = null; + this.cursorObj = undefined; } /** diff --git a/src/ui/text.ts b/src/ui/text.ts index 262e1280c38..62534f8ee45 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -243,7 +243,7 @@ export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: Ui export function getTextWithColors(content: string, primaryStyle: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string { // Apply primary styling before anything else let text = getBBCodeFrag(content, primaryStyle, uiTheme) + "[/color][/shadow]"; - const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0]; + const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))!][0]; // Set custom colors text = text.replace(/@\[([^{]*)\]{([^}]*)}/gi, (substring, textStyle: string, textToColor: string) => {