diff --git a/public/audio/cry/646-black.mp3 b/public/audio/cry/646-black.mp3 new file mode 100644 index 00000000000..d84cd4c9241 Binary files /dev/null and b/public/audio/cry/646-black.mp3 differ diff --git a/public/audio/cry/646-white.mp3 b/public/audio/cry/646-white.mp3 new file mode 100644 index 00000000000..d213f890811 Binary files /dev/null and b/public/audio/cry/646-white.mp3 differ diff --git a/public/images/items.json b/public/images/items.json index 080e0efe4f5..37abc478838 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -1165,7 +1165,7 @@ } }, { - "filename": "electirizer", + "filename": "dna_splicers", "rotated": false, "trimmed": true, "sourceSize": { @@ -1186,7 +1186,7 @@ } }, { - "filename": "enigma_berry", + "filename": "electirizer", "rotated": false, "trimmed": true, "sourceSize": { @@ -1207,7 +1207,7 @@ } }, { - "filename": "ganlon_berry", + "filename": "enigma_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -1228,7 +1228,7 @@ } }, { - "filename": "guard_spec", + "filename": "ganlon_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -1249,7 +1249,7 @@ } }, { - "filename": "ice_stone", + "filename": "guard_spec", "rotated": false, "trimmed": true, "sourceSize": { @@ -1312,7 +1312,7 @@ } }, { - "filename": "magmarizer", + "filename": "ice_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -1501,7 +1501,7 @@ } }, { - "filename": "mini_black_hole", + "filename": "magmarizer", "rotated": false, "trimmed": true, "sourceSize": { @@ -1522,7 +1522,7 @@ } }, { - "filename": "protector", + "filename": "mini_black_hole", "rotated": false, "trimmed": true, "sourceSize": { @@ -1543,7 +1543,7 @@ } }, { - "filename": "reaper_cloth", + "filename": "protector", "rotated": false, "trimmed": true, "sourceSize": { @@ -1554,13 +1554,34 @@ "x": 5, "y": 5, "w": 22, - "h": 23 + "h": 22 }, "frame": { "x": 183, "y": 90, "w": 22, - "h": 23 + "h": 22 + } + }, + { + "filename": "apicot_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 205, + "y": 92, + "w": 19, + "h": 20 } }, { @@ -1578,33 +1599,12 @@ "h": 21 }, "frame": { - "x": 205, - "y": 92, + "x": 224, + "y": 91, "w": 21, "h": 21 } }, - { - "filename": "metal_coat", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 226, - "y": 91, - "w": 19, - "h": 22 - } - }, { "filename": "iron", "rotated": false, @@ -1627,7 +1627,7 @@ } }, { - "filename": "shed_shell", + "filename": "reaper_cloth", "rotated": false, "trimmed": true, "sourceSize": { @@ -1638,13 +1638,13 @@ "x": 5, "y": 5, "w": 22, - "h": 22 + "h": 23 }, "frame": { "x": 261, "y": 100, "w": 22, - "h": 22 + "h": 23 } }, { @@ -1732,7 +1732,7 @@ } }, { - "filename": "starf_berry", + "filename": "shed_shell", "rotated": false, "trimmed": true, "sourceSize": { @@ -1753,7 +1753,7 @@ } }, { - "filename": "thunder_stone", + "filename": "starf_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -1774,7 +1774,7 @@ } }, { - "filename": "tm_bug", + "filename": "thunder_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -1795,7 +1795,7 @@ } }, { - "filename": "tm_dark", + "filename": "tm_bug", "rotated": false, "trimmed": true, "sourceSize": { @@ -1810,13 +1810,13 @@ }, "frame": { "x": 183, - "y": 113, + "y": 112, "w": 22, "h": 22 } }, { - "filename": "tm_dragon", + "filename": "tm_dark", "rotated": false, "trimmed": true, "sourceSize": { @@ -1831,7 +1831,7 @@ }, "frame": { "x": 205, - "y": 113, + "y": 112, "w": 22, "h": 22 } @@ -1852,7 +1852,7 @@ }, "frame": { "x": 227, - "y": 113, + "y": 112, "w": 18, "h": 24 } @@ -1879,7 +1879,7 @@ } }, { - "filename": "tm_electric", + "filename": "tm_dragon", "rotated": false, "trimmed": true, "sourceSize": { @@ -1894,7 +1894,7 @@ }, "frame": { "x": 261, - "y": 122, + "y": 123, "w": 22, "h": 22 } @@ -1942,7 +1942,7 @@ } }, { - "filename": "tm_fairy", + "filename": "tm_electric", "rotated": false, "trimmed": true, "sourceSize": { @@ -1984,7 +1984,7 @@ } }, { - "filename": "tm_fighting", + "filename": "tm_fairy", "rotated": false, "trimmed": true, "sourceSize": { @@ -2005,7 +2005,7 @@ } }, { - "filename": "tm_fire", + "filename": "tm_fighting", "rotated": false, "trimmed": true, "sourceSize": { @@ -2026,7 +2026,7 @@ } }, { - "filename": "tm_flying", + "filename": "tm_fire", "rotated": false, "trimmed": true, "sourceSize": { @@ -2047,7 +2047,7 @@ } }, { - "filename": "tm_ghost", + "filename": "tm_flying", "rotated": false, "trimmed": true, "sourceSize": { @@ -2068,7 +2068,7 @@ } }, { - "filename": "tm_grass", + "filename": "tm_ghost", "rotated": false, "trimmed": true, "sourceSize": { @@ -2088,6 +2088,27 @@ "h": 22 } }, + { + "filename": "tm_grass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 152, + "y": 133, + "w": 22, + "h": 22 + } + }, { "filename": "tm_ground", "rotated": false, @@ -2103,8 +2124,8 @@ "h": 22 }, "frame": { - "x": 152, - "y": 133, + "x": 130, + "y": 155, "w": 22, "h": 22 } @@ -2124,7 +2145,7 @@ "h": 22 }, "frame": { - "x": 130, + "x": 152, "y": 155, "w": 22, "h": 22 @@ -2145,8 +2166,8 @@ "h": 22 }, "frame": { - "x": 152, - "y": 155, + "x": 174, + "y": 134, "w": 22, "h": 22 } @@ -2166,8 +2187,8 @@ "h": 22 }, "frame": { - "x": 174, - "y": 135, + "x": 196, + "y": 134, "w": 22, "h": 22 } @@ -2187,8 +2208,8 @@ "h": 22 }, "frame": { - "x": 196, - "y": 135, + "x": 174, + "y": 156, "w": 22, "h": 22 } @@ -2208,8 +2229,8 @@ "h": 22 }, "frame": { - "x": 174, - "y": 157, + "x": 196, + "y": 156, "w": 22, "h": 22 } @@ -2229,8 +2250,8 @@ "h": 22 }, "frame": { - "x": 196, - "y": 157, + "x": 218, + "y": 136, "w": 22, "h": 22 } @@ -2251,28 +2272,7 @@ }, "frame": { "x": 218, - "y": 137, - "w": 22, - "h": 22 - } - }, - { - "filename": "water_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 218, - "y": 159, + "y": 158, "w": 22, "h": 22 } @@ -2320,7 +2320,7 @@ } }, { - "filename": "x_accuracy", + "filename": "water_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -2335,7 +2335,7 @@ }, "frame": { "x": 261, - "y": 144, + "y": 145, "w": 22, "h": 22 } @@ -2356,13 +2356,13 @@ }, "frame": { "x": 261, - "y": 166, + "y": 167, "w": 22, "h": 19 } }, { - "filename": "x_attack", + "filename": "x_accuracy", "rotated": false, "trimmed": true, "sourceSize": { @@ -2383,7 +2383,7 @@ } }, { - "filename": "x_defense", + "filename": "x_attack", "rotated": false, "trimmed": true, "sourceSize": { @@ -2404,7 +2404,7 @@ } }, { - "filename": "spell_tag", + "filename": "metal_coat", "rotated": false, "trimmed": true, "sourceSize": { @@ -2412,16 +2412,37 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 6, + "x": 6, + "y": 5, "w": 19, - "h": 21 + "h": 22 }, "frame": { "x": 89, "y": 172, "w": 19, - "h": 21 + "h": 22 + } + }, + { + "filename": "x_defense", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 45, + "y": 194, + "w": 22, + "h": 22 } }, { @@ -2439,7 +2460,7 @@ "h": 22 }, "frame": { - "x": 45, + "x": 67, "y": 194, "w": 22, "h": 22 @@ -2460,14 +2481,14 @@ "h": 22 }, "frame": { - "x": 67, - "y": 194, + "x": 108, + "y": 176, "w": 22, "h": 22 } }, { - "filename": "max_ether", + "filename": "spell_tag", "rotated": false, "trimmed": true, "sourceSize": { @@ -2476,15 +2497,15 @@ }, "spriteSourceSize": { "x": 7, - "y": 4, - "w": 18, - "h": 24 + "y": 6, + "w": 19, + "h": 21 }, "frame": { "x": 89, - "y": 193, - "w": 18, - "h": 24 + "y": 194, + "w": 19, + "h": 21 } }, { @@ -2502,8 +2523,8 @@ "h": 22 }, "frame": { - "x": 108, - "y": 176, + "x": 130, + "y": 177, "w": 22, "h": 22 } @@ -2523,7 +2544,7 @@ "h": 21 }, "frame": { - "x": 130, + "x": 152, "y": 177, "w": 21, "h": 21 @@ -2544,8 +2565,29 @@ "h": 20 }, "frame": { - "x": 151, - "y": 177, + "x": 173, + "y": 178, + "w": 20, + "h": 20 + } + }, + { + "filename": "magnet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 193, + "y": 178, "w": 20, "h": 20 } @@ -2565,33 +2607,12 @@ "h": 19 }, "frame": { - "x": 107, + "x": 108, "y": 198, "w": 20, "h": 19 } }, - { - "filename": "magnet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 127, - "y": 198, - "w": 20, - "h": 20 - } - }, { "filename": "mb", "rotated": false, @@ -2607,8 +2628,8 @@ "h": 20 }, "frame": { - "x": 171, - "y": 179, + "x": 128, + "y": 199, "w": 20, "h": 20 } @@ -2628,8 +2649,8 @@ "h": 20 }, "frame": { - "x": 191, - "y": 179, + "x": 213, + "y": 180, "w": 20, "h": 20 } @@ -2649,8 +2670,8 @@ "h": 20 }, "frame": { - "x": 211, - "y": 181, + "x": 233, + "y": 182, "w": 20, "h": 20 } @@ -2698,7 +2719,7 @@ } }, { - "filename": "max_lure", + "filename": "max_ether", "rotated": false, "trimmed": true, "sourceSize": { @@ -2706,15 +2727,15 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, + "x": 7, "y": 4, - "w": 17, + "w": 18, "h": 24 }, "frame": { "x": 46, "y": 255, - "w": 17, + "w": 18, "h": 24 } }, @@ -2733,8 +2754,8 @@ "h": 19 }, "frame": { - "x": 231, - "y": 182, + "x": 253, + "y": 186, "w": 20, "h": 19 } @@ -2761,7 +2782,7 @@ } }, { - "filename": "super_lure", + "filename": "max_lure", "rotated": false, "trimmed": true, "sourceSize": { @@ -2775,33 +2796,12 @@ "h": 24 }, "frame": { - "x": 63, - "y": 240, + "x": 81, + "y": 216, "w": 17, "h": 24 } }, - { - "filename": "ub", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 63, - "y": 264, - "w": 20, - "h": 20 - } - }, { "filename": "potion", "rotated": false, @@ -2816,69 +2816,6 @@ "w": 17, "h": 23 }, - "frame": { - "x": 81, - "y": 217, - "w": 17, - "h": 23 - } - }, - { - "filename": "protein", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 80, - "y": 240, - "w": 16, - "h": 24 - } - }, - { - "filename": "apicot_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 83, - "y": 264, - "w": 19, - "h": 20 - } - }, - { - "filename": "super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, "frame": { "x": 98, "y": 217, @@ -2886,48 +2823,6 @@ "h": 23 } }, - { - "filename": "zinc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 96, - "y": 240, - "w": 16, - "h": 24 - } - }, - { - "filename": "candy_jar", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 102, - "y": 264, - "w": 19, - "h": 20 - } - }, { "filename": "revive", "rotated": false, @@ -2950,7 +2845,7 @@ } }, { - "filename": "wl_ability_urge", + "filename": "ub", "rotated": false, "trimmed": true, "sourceSize": { @@ -2959,19 +2854,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 8, + "y": 6, "w": 20, - "h": 18 + "h": 20 }, "frame": { "x": 127, - "y": 218, + "y": 219, "w": 20, - "h": 18 + "h": 20 } }, { - "filename": "metronome", + "filename": "super_lure", "rotated": false, "trimmed": true, "sourceSize": { @@ -2979,20 +2874,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 5, + "x": 8, + "y": 4, "w": 17, - "h": 22 + "h": 24 }, "frame": { - "x": 147, - "y": 198, + "x": 64, + "y": 240, "w": 17, - "h": 22 + "h": 24 } }, { - "filename": "big_mushroom", + "filename": "candy_jar", "rotated": false, "trimmed": true, "sourceSize": { @@ -3003,13 +2898,34 @@ "x": 6, "y": 6, "w": 19, - "h": 19 + "h": 20 }, "frame": { - "x": 147, - "y": 220, + "x": 64, + "y": 264, "w": 19, - "h": 19 + "h": 20 + } + }, + { + "filename": "protein", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 81, + "y": 240, + "w": 16, + "h": 24 } }, { @@ -3027,14 +2943,14 @@ "h": 20 }, "frame": { - "x": 164, - "y": 199, + "x": 83, + "y": 264, "w": 19, "h": 20 } }, { - "filename": "miracle_seed", + "filename": "zinc", "rotated": false, "trimmed": true, "sourceSize": { @@ -3042,37 +2958,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 19, - "h": 19 + "x": 8, + "y": 4, + "w": 16, + "h": 24 }, "frame": { - "x": 183, - "y": 199, - "w": 19, - "h": 19 - } - }, - { - "filename": "golden_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 166, - "y": 219, - "w": 17, - "h": 20 + "x": 97, + "y": 240, + "w": 16, + "h": 24 } }, { @@ -3090,12 +2985,159 @@ "h": 20 }, "frame": { - "x": 183, - "y": 218, + "x": 102, + "y": 264, "w": 18, "h": 20 } }, + { + "filename": "super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 113, + "y": 240, + "w": 17, + "h": 23 + } + }, + { + "filename": "metronome", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 130, + "y": 239, + "w": 17, + "h": 22 + } + }, + { + "filename": "golden_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 120, + "y": 263, + "w": 17, + "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": 137, + "y": 261, + "w": 17, + "h": 20 + } + }, + { + "filename": "big_mushroom", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 19 + }, + "frame": { + "x": 148, + "y": 199, + "w": 19, + "h": 19 + } + }, + { + "filename": "miracle_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 167, + "y": 198, + "w": 19, + "h": 19 + } + }, + { + "filename": "wl_ability_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 186, + "y": 198, + "w": 20, + "h": 18 + } + }, { "filename": "wl_antidote", "rotated": false, @@ -3111,8 +3153,8 @@ "h": 18 }, "frame": { - "x": 202, - "y": 201, + "x": 206, + "y": 200, "w": 20, "h": 18 } @@ -3132,8 +3174,8 @@ "h": 18 }, "frame": { - "x": 222, - "y": 201, + "x": 226, + "y": 202, "w": 20, "h": 18 } @@ -3153,54 +3195,12 @@ "h": 18 }, "frame": { - "x": 201, - "y": 219, + "x": 246, + "y": 205, "w": 20, "h": 18 } }, - { - "filename": "wl_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 221, - "y": 219, - "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": 242, - "y": 201, - "w": 17, - "h": 20 - } - }, { "filename": "oval_stone", "rotated": false, @@ -3216,12 +3216,33 @@ "h": 19 }, "frame": { - "x": 241, - "y": 221, + "x": 266, + "y": 205, "w": 18, "h": 19 } }, + { + "filename": "wl_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 186, + "y": 216, + "w": 20, + "h": 18 + } + }, { "filename": "wl_full_heal", "rotated": false, @@ -3237,8 +3258,8 @@ "h": 18 }, "frame": { - "x": 112, - "y": 240, + "x": 206, + "y": 218, "w": 20, "h": 18 } @@ -3258,8 +3279,8 @@ "h": 18 }, "frame": { - "x": 121, - "y": 258, + "x": 226, + "y": 220, "w": 20, "h": 18 } @@ -3279,8 +3300,8 @@ "h": 18 }, "frame": { - "x": 132, - "y": 240, + "x": 246, + "y": 223, "w": 20, "h": 18 } @@ -3300,8 +3321,8 @@ "h": 18 }, "frame": { - "x": 152, - "y": 239, + "x": 148, + "y": 218, "w": 20, "h": 18 } @@ -3321,8 +3342,8 @@ "h": 18 }, "frame": { - "x": 141, - "y": 258, + "x": 147, + "y": 236, "w": 20, "h": 18 } @@ -3342,8 +3363,8 @@ "h": 18 }, "frame": { - "x": 172, - "y": 239, + "x": 154, + "y": 254, "w": 20, "h": 18 } @@ -3363,8 +3384,8 @@ "h": 18 }, "frame": { - "x": 161, - "y": 257, + "x": 167, + "y": 236, "w": 20, "h": 18 } @@ -3384,8 +3405,8 @@ "h": 18 }, "frame": { - "x": 181, - "y": 257, + "x": 174, + "y": 254, "w": 20, "h": 18 } @@ -3405,8 +3426,8 @@ "h": 18 }, "frame": { - "x": 192, - "y": 238, + "x": 187, + "y": 236, "w": 20, "h": 18 } @@ -3426,8 +3447,8 @@ "h": 18 }, "frame": { - "x": 212, - "y": 237, + "x": 194, + "y": 254, "w": 20, "h": 18 } @@ -3447,8 +3468,8 @@ "h": 18 }, "frame": { - "x": 201, - "y": 256, + "x": 214, + "y": 238, "w": 20, "h": 18 } @@ -3468,8 +3489,8 @@ "h": 18 }, "frame": { - "x": 221, - "y": 255, + "x": 214, + "y": 256, "w": 20, "h": 18 } @@ -3489,8 +3510,8 @@ "h": 18 }, "frame": { - "x": 241, - "y": 240, + "x": 234, + "y": 241, "w": 20, "h": 18 } @@ -3510,8 +3531,8 @@ "h": 18 }, "frame": { - "x": 241, - "y": 258, + "x": 234, + "y": 259, "w": 20, "h": 18 } @@ -3522,6 +3543,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b487cc2f66e6f01e2835d69c91ef15c7:5ec601e7ece980a5741a0e30d1974a3d:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:a758207f86968eadc2af85a2228ef355:f1dd54661f7a44fe3bcd89ae87d14b1d:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 706c4a1050c..f077e5fc849 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/public/images/items/dna_splicers.png b/public/images/items/dna_splicers.png new file mode 100644 index 00000000000..5a3c7fed75b Binary files /dev/null and b/public/images/items/dna_splicers.png differ diff --git a/public/images/ui/summary_bg.png b/public/images/ui/summary_bg.png index 4c0896b4f17..e4da2dd5da2 100644 Binary files a/public/images/ui/summary_bg.png and b/public/images/ui/summary_bg.png differ diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 0e432ad15cf..362bdc81e77 100644 --- a/src/battle-phases.ts +++ b/src/battle-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, EnemyInstantReviveChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; +import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyInstantReviveChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler"; import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball"; import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims"; @@ -16,7 +16,7 @@ import { EvolutionPhase } from "./evolution-phase"; import { BattlePhase } from "./battle-phase"; import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat"; import { Biome, biomeLinks } from "./data/biome"; -import { ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, TmModifierType, getEnemyBuffModifierTypeOptionsForWave, getModifierType, getPlayerModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; +import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, TmModifierType, getEnemyBuffModifierTypeOptionsForWave, getModifierType, getPlayerModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import { BattlerTagLapseType, BattlerTagType, HideSpriteTag as HiddenTag, TrappedTag } from "./data/battler-tag"; import { getPokemonMessage } from "./messages"; @@ -118,7 +118,7 @@ export class SelectStarterPhase extends BattlePhase { Promise.all(loadPokemonAssets).then(() => { this.scene.ui.clearText(); this.scene.ui.setMode(Mode.MESSAGE).then(() => { - SoundFade.fadeOut(this.scene.sound.get('menu'), 500, true); + SoundFade.fadeOut(this.scene, this.scene.sound.get('menu'), 500, true); this.scene.time.delayedCall(500, () => this.scene.playBgm()); this.end(); }); @@ -2819,6 +2819,7 @@ export class AttemptRunPhase extends PokemonPhase { enemyField.forEach(enemyPokemon => { enemyPokemon.hideInfo().then(() => enemyPokemon.destroy()); enemyPokemon.hp = 0; + enemyPokemon.trySetStatus(StatusEffect.FAINT); }); this.scene.clearEnemyHeldItemModifiers(); @@ -2878,28 +2879,42 @@ export class SelectModifierPhase extends BattlePhase { const modifierType = typeOptions[cursor].type; if (modifierType instanceof PokemonModifierType) { - const pokemonModifierType = modifierType as PokemonModifierType; - const isMoveModifier = modifierType instanceof PokemonMoveModifierType; - const isTmModifier = modifierType instanceof TmModifierType; - const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER - : isTmModifier ? PartyUiMode.TM_MODIFIER : PartyUiMode.MODIFIER; - const tmMoveId = isTmModifier - ? (modifierType as TmModifierType).moveId - : undefined; - this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => { - if (slotIndex < 6) { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { - const modifierType = typeOptions[cursor].type; - const modifier = !isMoveModifier - ? modifierType.newModifier(party[slotIndex]) - : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1); - this.scene.ui.clearText(); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.addModifier(modifier, false, true).then(() => super.end()); - }); - } else - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, ); - }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId); + if (modifierType instanceof FusePokemonModifierType) { + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => { + if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex]); + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.addModifier(modifier, false, true).then(() => super.end()); + }); + } else + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback); + }, modifierType.selectFilter); + } else { + const pokemonModifierType = modifierType as PokemonModifierType; + const isMoveModifier = modifierType instanceof PokemonMoveModifierType; + const isTmModifier = modifierType instanceof TmModifierType; + const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER + : isTmModifier ? PartyUiMode.TM_MODIFIER : PartyUiMode.MODIFIER; + const tmMoveId = isTmModifier + ? (modifierType as TmModifierType).moveId + : undefined; + this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => { + if (slotIndex < 6) { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + const modifierType = typeOptions[cursor].type; + const modifier = !isMoveModifier + ? modifierType.newModifier(party[slotIndex]) + : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1); + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.addModifier(modifier, false, true).then(() => super.end()); + }); + } else + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, ); + }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId); + } } else { this.addModifier(typeOptions[cursor].type.newModifier()).then(() => super.end()); this.scene.ui.clearText(); diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 4d4d5b1cd7b..fc217cd1ee3 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -5,7 +5,7 @@ import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon'; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species'; import * as Utils from './utils'; -import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier } from './modifier/modifier'; +import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier } from './modifier/modifier'; import { PokeballType } from './data/pokeball'; import { initAutoPlay } from './system/auto-play'; import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from './data/battle-anims'; @@ -352,7 +352,7 @@ export default class BattleScene extends Phaser.Scene { update() { this.checkInput(); - this.ui.update(); + this.ui?.update(); } launchBattle() { @@ -1007,7 +1007,7 @@ export default class BattleScene extends Phaser.Scene { return false; } - playSound(soundName: string, config?: object): AnySound { + playSound(sound: string | AnySound, config?: object): AnySound { if (config) { if (config.hasOwnProperty('volume')) config['volume'] *= this.masterVolume * this.seVolume; @@ -1015,8 +1015,13 @@ export default class BattleScene extends Phaser.Scene { config['volume'] = this.masterVolume * this.seVolume; } else config = { volume: this.masterVolume * this.seVolume }; - this.sound.play(soundName, config); - return this.sound.get(soundName) as AnySound; + if (typeof sound === 'string') { + this.sound.play(sound, config); + return this.sound.get(sound) as AnySound; + } else { + sound.play(config); + return sound; + } } playSoundWithoutBgm(soundName: string, pauseDuration?: integer): AnySound { @@ -1149,7 +1154,8 @@ export default class BattleScene extends Phaser.Scene { args.push(hpRestoreMultiplier.value); } else args.push(1); - } + } else if (modifier instanceof FusePokemonModifier) + args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); if (modifier.shouldApply(args)) modifier.apply(args); diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index c65b32e1ab9..99f8181447d 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -242,7 +242,7 @@ class AnimTimedSoundEvent extends AnimTimedEvent { } return Math.ceil((scene.sound.get(this.resourceName).totalDuration * 1000) / 33.33); } else - return Math.ceil(battleAnim.user.cry(soundConfig) / 33.33); + return Math.ceil((battleAnim.user.cry(soundConfig).totalDuration * 1000) / 33.33); } getEventType(): string { diff --git a/src/data/move.ts b/src/data/move.ts index 6cd272849c3..f489f94a6b4 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2023,6 +2023,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } else { switchOutTarget.hideInfo().then(() => switchOutTarget.destroy()); switchOutTarget.hp = 0; + switchOutTarget.trySetStatus(StatusEffect.FAINT); user.scene.queueMessage(getPokemonMessage(switchOutTarget, ' fled!'), null, true, 500); diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index 2c3db0122c1..00244b751d3 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -1,11 +1,21 @@ import { Moves } from "./move"; import { Species } from "./species"; -interface PokemonLevelMoves { - [key: string]: Array> +export type LevelMoves = (integer | Moves)[][]; + +interface PokemonSpeciesLevelMoves { + [key: string]: LevelMoves } -export const pokemonLevelMoves: PokemonLevelMoves = { +interface PokemonFormLevelMoves { + [key: integer]: LevelMoves +} + +interface PokemonSpeciesFormLevelMoves { + [key: string]: PokemonFormLevelMoves +} + +export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.BULBASAUR]: [ [ 1, Moves.TACKLE ], [ 3, Moves.GROWL ], @@ -10965,4 +10975,43 @@ export const pokemonLevelMoves: PokemonLevelMoves = { [ 80, Moves.HYPER_BEAM ], [ 88, Moves.OUTRAGE ] ] -}; \ No newline at end of file +}; + +export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = { + [Species.KYUREM]: { + 1: [ + [ 1, Moves.DRAGON_RAGE ], + [ 1, Moves.ICY_WIND ], + [ 8, Moves.IMPRISON ], + [ 15, Moves.ANCIENT_POWER ], + [ 22, Moves.ICE_BEAM ], + [ 29, Moves.DRAGON_BREATH ], + [ 36, Moves.SLASH ], + [ 43, Moves.SCARY_FACE ], + [ 50, Moves.ICE_BURN ], + [ 57, Moves.DRAGON_PULSE ], + [ 64, Moves.IMPRISON ], + [ 71, Moves.ENDEAVOR ], + [ 78, Moves.BLIZZARD ], + [ 85, Moves.OUTRAGE ], + [ 92, Moves.HYPER_VOICE ] + ], + 2: [ + [ 1, Moves.DRAGON_RAGE ], + [ 1, Moves.ICY_WIND ], + [ 8, Moves.IMPRISON ], + [ 15, Moves.ANCIENT_POWER ], + [ 22, Moves.ICE_BEAM ], + [ 29, Moves.DRAGON_BREATH ], + [ 36, Moves.SLASH ], + [ 43, Moves.SCARY_FACE ], + [ 50, Moves.FREEZE_SHOCK ], + [ 57, Moves.DRAGON_PULSE ], + [ 64, Moves.IMPRISON ], + [ 71, Moves.ENDEAVOR ], + [ 78, Moves.BLIZZARD ], + [ 85, Moves.OUTRAGE ], + [ 92, Moves.HYPER_VOICE ] + ] + } +} \ No newline at end of file diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 98b64dff286..d24156f8338 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1,11 +1,12 @@ import { Abilities } from './ability'; -import BattleScene from '../battle-scene'; +import BattleScene, { AnySound } from '../battle-scene'; import { GrowthRate } from './exp'; import { SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from './pokemon-evolutions'; import { Species } from './species'; import { Type } from './type'; import * as Utils from '../utils'; import { TrainerType, trainerConfigs } from './trainer-type'; +import { LevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from './pokemon-level-moves'; export function getPokemonSpecies(species: Species): PokemonSpecies { if (species >= Species.XERNEAS) @@ -74,6 +75,12 @@ export abstract class PokemonSpeciesForm { return !abilityIndex ? this.ability1 : abilityIndex === 1 && this.ability2 ? this.ability2 : this.abilityHidden } + getLevelMoves(): LevelMoves { + if (pokemonSpeciesFormLevelMoves.hasOwnProperty(this.speciesId) && pokemonSpeciesFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)) + return pokemonSpeciesFormLevelMoves[this.speciesId][this.formIndex]; + return pokemonSpeciesLevelMoves[this.speciesId]; + } + isObtainable() { return this.generation <= 5 && this.getFormSpriteKey(this.formIndex) !== 'mega'; } @@ -147,15 +154,21 @@ export abstract class PokemonSpeciesForm { const forms = getPokemonSpecies(this.speciesId).forms; if (forms.length) { const formKey = forms[formIndex || 0].formKey; - if (formKey === 'mega' || formKey === 'eternamax') - ret += `-${formKey}`; + switch (formKey) { + case 'mega': + case 'white': + case 'black': + case 'eternamax': + ret += `-${formKey}`; + break; + } } return ret; } loadAssets(scene: BattleScene, female: boolean, formIndex?: integer, shiny?: boolean, startLoad?: boolean): Promise { return new Promise(resolve => { - scene.load.audio(this.speciesId.toString(), `audio/cry/${this.getCryKey(formIndex)}.mp3`); + scene.load.audio(this.getCryKey(formIndex), `audio/cry/${this.getCryKey(formIndex)}.mp3`); scene.loadAtlas(this.getSpriteKey(female, formIndex, shiny), 'pokemon', this.getSpriteAtlasPath(female, formIndex, shiny)); scene.load.once(Phaser.Loader.Events.COMPLETE, () => { const originalWarn = console.warn; @@ -192,9 +205,13 @@ export abstract class PokemonSpeciesForm { }); } - cry(scene: BattleScene, soundConfig?: Phaser.Types.Sound.SoundConfig): integer { - scene.playSound(this.speciesId.toString(), soundConfig); - return scene.sound.get(this.speciesId.toString()).totalDuration * 1000; + cry(scene: BattleScene, soundConfig?: Phaser.Types.Sound.SoundConfig, ignorePlay?: boolean): AnySound { + const cryKey = this.getCryKey(this.formIndex); + let cry = scene.sound.get(cryKey) as AnySound; + cry = scene.playSound(cry || cryKey, soundConfig); + if (ignorePlay) + cry.stop(); + return cry; } } @@ -1132,8 +1149,8 @@ export function initSpecies() { ), new PokemonSpecies(Species.KYUREM, "Kyurem", 5, false, true, false, "Boundary Pokémon", Type.DRAGON, Type.ICE, 3, 325, Abilities.PRESSURE, Abilities.NONE, Abilities.NONE, 660, 125, 130, 90, 130, 90, 95, 3, 0, 297, GrowthRate.SLOW, "Undiscovered", null, null, 120, false, true, new PokemonForm("Normal", "", Type.DRAGON, Type.ICE, 3, 325, Abilities.PRESSURE, Abilities.NONE, Abilities.NONE, 660, 125, 130, 90, 130, 90, 95, 3, 0, 297, GrowthRate.SLOW, "Undiscovered", null, null, 120, false), - new PokemonForm("Black", "black", Type.DRAGON, Type.ICE, 3.3, 325, Abilities.TERAVOLT, Abilities.NONE, Abilities.NONE, 700, 125, 170, 100, 120, 90, 95, 3, 0, 315, GrowthRate.SLOW, "Undiscovered", null, null, 120, false), - new PokemonForm("White", "white", Type.DRAGON, Type.ICE, 3.6, 325, Abilities.TURBOBLAZE, Abilities.NONE, Abilities.NONE, 700, 125, 120, 90, 170, 100, 95, 3, 0, 315, GrowthRate.SLOW, "Undiscovered", null, null, 120, false) + new PokemonForm("White", "white", Type.DRAGON, Type.ICE, 3.6, 325, Abilities.TURBOBLAZE, Abilities.NONE, Abilities.NONE, 700, 125, 120, 90, 170, 100, 95, 3, 0, 315, GrowthRate.SLOW, "Undiscovered", null, null, 120, false), + new PokemonForm("Black", "black", Type.DRAGON, Type.ICE, 3.3, 325, Abilities.TERAVOLT, Abilities.NONE, Abilities.NONE, 700, 125, 170, 100, 120, 90, 95, 3, 0, 315, GrowthRate.SLOW, "Undiscovered", null, null, 120, false) ), new PokemonSpecies(Species.KELDEO, "Keldeo", 5, false, false, true, "Colt Pokémon", Type.WATER, Type.FIGHTING, 1.4, 48.5, Abilities.JUSTIFIED, Abilities.NONE, Abilities.NONE, 580, 91, 72, 90, 129, 90, 108, 3, 35, 261, GrowthRate.SLOW, "Undiscovered", null, null, 80, false, true, new PokemonForm("Ordinary Forme", "ordinary", Type.WATER, Type.FIGHTING, 1.4, 48.5, Abilities.JUSTIFIED, Abilities.NONE, Abilities.NONE, 580, 91, 72, 90, 129, 90, 108, 3, 35, 261, GrowthRate.SLOW, "Undiscovered", null, null, 80, false), diff --git a/src/data/trainer-type.ts b/src/data/trainer-type.ts index b90a0066e30..a9b03a2d393 100644 --- a/src/data/trainer-type.ts +++ b/src/data/trainer-type.ts @@ -4,7 +4,6 @@ import { EnemyPokemon } from "../pokemon"; import * as Utils from "../utils"; import { Moves } from "./move"; import { pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions"; -import { pokemonLevelMoves } from "./pokemon-level-moves"; import PokemonSpecies, { PokemonSpeciesFilter, getPokemonSpecies } from "./pokemon-species"; import { Species } from "./species"; import { tmSpecies } from "./tms"; @@ -552,7 +551,7 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.BREEDER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.POKEFAN).setHasGenders().setDouble() .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.FIVE_WEAKER, trainerPartyTemplates.SIX_WEAKER)), [TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.CLERK), - [TrainerType.CYCLIST]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.CYCLIST).setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.QUICK_ATTACK)), + [TrainerType.CYCLIST]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.CYCLIST).setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.QUICK_ATTACK)), [TrainerType.DANCER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST), [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK), [TrainerType.DOCTOR]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK), @@ -575,8 +574,8 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.JANITOR]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK), [TrainerType.LINEBACKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST), [TrainerType.MAID]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setSpeciesFilter(s => s.eggType1 === 'Field' || s.eggType2 === 'Field'), - [TrainerType.MUSICIAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.SING)), - [TrainerType.NURSE]: new TrainerConfig(++t).setEncounterBgm('lass').setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.CHARM) || !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.HEAL_PULSE)), + [TrainerType.MUSICIAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SING)), + [TrainerType.NURSE]: new TrainerConfig(++t).setEncounterBgm('lass').setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.CHARM) || !!s.getLevelMoves().find(plm => plm[1] === Moves.HEAL_PULSE)), [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setEncounterBgm('lass'), [TrainerType.OFFICER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesPools([ Species.VULPIX, Species.GROWLITHE, Species.SNUBBULL, Species.HOUNDOUR, Species.POOCHYENA, Species.ELECTRIKE, Species.LILLIPUP ]), [TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)), diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 533e5318b61..47ba5ea7cb7 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -440,6 +440,28 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge } } +export class FusePokemonModifierType extends PokemonModifierType { + constructor(name: string, iconImage?: string) { + super(name, 'Combines two Pokémon, giving the first Pokémon the ability of the second', (_type, args) => new Modifiers.FusePokemonModifier(this, (args[0] as PlayerPokemon).id, (args[1] as PlayerPokemon).id), + (pokemon: PlayerPokemon) => { + if (pokemon.isFusion()) + return PartyUiHandler.NoEffectMessage; + return null; + }, iconImage); + } +} + +export class UnfusePokemonModifierType extends PokemonModifierType { + constructor(name: string, iconImage?: string) { + super(name, 'Removes the fusion aspects of a spliced Pokémon, but the second Pokémon is lost', (_type, args) => new Modifiers.UnfusePokemonModifier(this, (args[0] as PlayerPokemon).id), + (pokemon: PlayerPokemon) => { + if (!pokemon.isFusion()) + return PartyUiHandler.NoEffectMessage; + return null; + }, iconImage); + } +} + class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { constructor() { super((party: Pokemon[], pregenArgs?: any[]) => { @@ -671,6 +693,9 @@ export const modifierTypes = { SHINY_CHARM: () => new ModifierType('Shiny Charm', 'Dramatically increases the chance of a wild Pokémon being shiny', (type, _args) => new Modifiers.ShinyRateBoosterModifier(type)), ABILITY_CHARM: () => new ModifierType('Ability Charm', 'Dramatically increases the chance of a wild Pokémon having a hidden ability', (type, _args) => new Modifiers.HiddenAbilityRateBoosterModifier(type)), + DNA_SPLICERS: () => new FusePokemonModifierType('DNA Splicers'), + REVERSE_DNA_SPLICERS: () => new UnfusePokemonModifierType('Reverse DNA Splicers', 'dna_splicers'), + MINI_BLACK_HOLE: () => new TurnHeldItemTransferModifierType('Mini Black Hole'), GOLDEN_POKEBALL: () => new ModifierType(`Golden ${getPokeballName(PokeballType.POKEBALL)}`, 'Adds 1 extra item option at the end of every battle', @@ -713,7 +738,7 @@ const modifierPool = { new WeightedModifierType(modifierTypes.LURE, 2), new WeightedModifierType(modifierTypes.TEMP_STAT_BOOSTER, 4), new WeightedModifierType(modifierTypes.BERRY, 2), - new WeightedModifierType(modifierTypes.TM_COMMON, 1) + new WeightedModifierType(modifierTypes.TM_COMMON, 1), ].map(m => { m.setTier(ModifierTier.COMMON); return m; }), [ModifierTier.GREAT]: [ new WeightedModifierType(modifierTypes.GREAT_BALL, 6), @@ -774,11 +799,13 @@ const modifierPool = { new WeightedModifierType(modifierTypes.OVAL_CHARM, 2), new WeightedModifierType(modifierTypes.ABILITY_CHARM, 2), new WeightedModifierType(modifierTypes.EXP_BALANCE, 1), + new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party.filter(p => p.fusionSpecies).length > 1 ? 3 : 0), ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), [ModifierTier.MASTER]: [ new WeightedModifierType(modifierTypes.MASTER_BALL, 3), new WeightedModifierType(modifierTypes.SHINY_CHARM, 2), - new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0) + new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party.filter(p => !p.fusionSpecies).length > 1 ? 1 : 0), + new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }), [ModifierTier.LUXURY]: [ new WeightedModifierType(modifierTypes.GOLDEN_EXP_CHARM, 1), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 4777be5d0d4..9437b65566b 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -908,6 +908,38 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier { } } +export class FusePokemonModifier extends ConsumablePokemonModifier { + public fusePokemonId: integer; + + constructor(type: ModifierType, pokemonId: integer, fusePokemonId: integer) { + super(type, pokemonId); + + this.fusePokemonId = fusePokemonId; + } + + shouldApply(args: any[]): boolean { + return super.shouldApply(args) && args[1] instanceof PlayerPokemon && this.fusePokemonId === (args[1] as PlayerPokemon).id; + } + + apply(args: any[]): boolean { + (args[0] as PlayerPokemon).fuse(args[1] as PlayerPokemon); + + return true; + } +} + +export class UnfusePokemonModifier extends ConsumablePokemonModifier { + constructor(type: ModifierType, pokemonId: integer) { + super(type, pokemonId); + } + + apply(args: any[]): boolean { + (args[0] as PlayerPokemon).unfuse(); + + return true; + } +} + export class MultipleParticipantExpBonusModifier extends PersistentModifier { constructor(type: ModifierType, stackCount?: integer) { super(type, stackCount); diff --git a/src/pokemon.ts b/src/pokemon.ts index 771ab3931a3..f30db3a3c23 100644 --- a/src/pokemon.ts +++ b/src/pokemon.ts @@ -1,8 +1,7 @@ import Phaser from 'phaser'; import BattleScene, { AnySound } from './battle-scene'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './ui/battle-info'; -import Move, { StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, Moves, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, AttackMove, AddBattlerTagAttr } from "./data/move"; -import { pokemonLevelMoves } from './data/pokemon-level-moves'; +import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, Moves, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, AttackMove, AddBattlerTagAttr } from "./data/move"; import { default as PokemonSpecies, PokemonSpeciesForm, getPokemonSpecies } from './data/pokemon-species'; import * as Utils from './utils'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier } from './data/type'; @@ -28,6 +27,7 @@ import PokemonData from './system/pokemon-data'; import { BattlerIndex } from './battle'; import { Mode } from './ui/ui'; import PartyUiHandler, { PartyOption, PartyUiMode } from './ui/party-ui-handler'; +import SoundFade from 'phaser3-rex-plugins/plugins/soundfade'; export enum FieldPosition { CENTER, @@ -59,6 +59,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public winCount: integer; public pokerus: boolean; + public fusionSpecies: PokemonSpecies; + public fusionFormIndex: integer; + public fusionAbilityIndex: integer; + public fusionShiny: boolean; + public fusionGender: Gender; + public summonData: PokemonSummonData; public battleSummonData: PokemonBattleSummonData; public turnData: PokemonTurnData; @@ -107,6 +113,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.status = dataSource.status; this.winCount = dataSource.winCount; this.pokerus = !!dataSource.pokerus; + this.fusionSpecies = dataSource.fusionSpecies instanceof PokemonSpecies ? dataSource.fusionSpecies : getPokemonSpecies(dataSource.fusionSpecies); + this.fusionFormIndex = dataSource.fusionFormIndex; + this.fusionAbilityIndex = dataSource.fusionAbilityIndex; + this.fusionShiny = dataSource.fusionShiny; + this.fusionGender = dataSource.fusionGender; } else { this.generateAndPopulateMoveset(); @@ -216,6 +227,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { .then(() => { loadMoveAnimAssets(this.scene, moveIds); this.getSpeciesForm().loadAssets(this.scene, this.getGender() === Gender.FEMALE, this.formIndex, this.shiny); + if (this.fusionSpecies) + this.getFusionSpeciesForm().loadAssets(this.scene, this.getGender() === Gender.FEMALE, this.fusionFormIndex, this.shiny); if (this.isPlayer()) this.scene.loadAtlas(this.getBattleSpriteKey(), 'pokemon', this.getBattleSpriteAtlasPath()); this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => { @@ -287,6 +300,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.species.forms[this.formIndex]; } + getFusionSpeciesForm(): PokemonSpeciesForm { + if (!this.fusionSpecies.forms?.length || this.fusionFormIndex >= this.fusionSpecies.forms.length) + return this.fusionSpecies; + return this.fusionSpecies.forms[this.fusionFormIndex]; + } + getSprite(): Phaser.GameObjects.Sprite { return this.getAt(0) as Phaser.GameObjects.Sprite; } @@ -373,6 +392,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!this.stats) this.stats = [ 0, 0, 0, 0, 0, 0 ]; const baseStats = this.getSpeciesForm().baseStats.slice(0); + if (this.fusionSpecies) { + const fusionBaseStats = this.getFusionSpeciesForm().baseStats; + for (let s = 0; s < this.stats.length; s++) + baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2); + } this.scene.applyModifiers(PokemonBaseStatModifier, this.isPlayer(), this, baseStats); const stats = Utils.getEnumValues(Stat); for (let s of stats) { @@ -452,6 +476,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getAbility(): Ability { if (ABILITY_OVERRIDE && this.isPlayer()) return abilities[ABILITY_OVERRIDE]; + if (this.fusionSpecies) + return abilities[this.getFusionSpeciesForm().getAbility(this.fusionAbilityIndex)]; return abilities[this.getSpeciesForm().getAbility(this.abilityIndex)]; } @@ -493,7 +519,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getLevelMoves(startingLevel?: integer): Moves[] { const ret: Moves[] = []; - const levelMoves = pokemonLevelMoves[this.species.speciesId]; + const levelMoves = this.getSpeciesForm().getLevelMoves();; if (levelMoves) { if (!startingLevel) startingLevel = this.level; @@ -540,7 +566,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { generateAndPopulateMoveset(): void { this.moveset = []; const movePool = []; - const allLevelMoves = pokemonLevelMoves[this.species.speciesId]; + const allLevelMoves = this.getSpeciesForm().getLevelMoves(); if (!allLevelMoves) { console.log(this.species.speciesId, 'ERROR') return; @@ -917,22 +943,46 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.summonData.moveQueue; } - cry(soundConfig?: Phaser.Types.Sound.SoundConfig): integer { - return this.getSpeciesForm().cry(this.scene, soundConfig); + cry(soundConfig?: Phaser.Types.Sound.SoundConfig): AnySound { + const cry = this.getSpeciesForm().cry(this.scene, soundConfig); + let duration = cry.totalDuration * 1000; + if (this.fusionSpecies) { + let fusionCry = this.getFusionSpeciesForm().cry(this.scene, soundConfig, true); + duration = Math.min(duration, fusionCry.totalDuration * 1000); + fusionCry.destroy(); + this.scene.time.delayedCall(Utils.fixedInt(Math.ceil(duration * 0.4)), () => { + try { + SoundFade.fadeOut(this.scene, cry, Utils.fixedInt(Math.ceil(duration * 0.2))); + fusionCry = this.getFusionSpeciesForm().cry(this.scene, Object.assign({ seek: Math.max(fusionCry.totalDuration * 0.4, 0) }, soundConfig)); + SoundFade.fadeIn(this.scene, fusionCry, Utils.fixedInt(Math.ceil(duration * 0.2)), this.scene.masterVolume * this.scene.seVolume, 0); + } catch (err) { + console.error(err); + } + }); + } + + return cry; } - faintCry(callback: Function) { - const key = this.species.speciesId.toString(); + faintCry(callback: Function): void { + if (this.fusionSpecies) + return this.fusionFaintCry(callback); + + const key = this.getSpeciesForm().getCryKey(); let i = 0; let rate = 0.85; - const crySound = this.scene.playSound(key, { rate: rate }) as AnySound; + const cry = this.scene.playSound(key, { rate: rate }) as AnySound; const sprite = this.getSprite(); const tintSprite = this.getTintSprite(); + const delay = Math.max(this.scene.sound.get(key).totalDuration * 50, 25); + let frameProgress = 0; let frameThreshold: number; + sprite.anims.pause(); tintSprite.anims.pause(); + let faintCryTimer = this.scene.time.addEvent({ delay: Utils.fixedInt(delay), repeat: -1, @@ -947,9 +997,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } frameProgress -= frameThreshold; } - if (crySound && !crySound.pendingRemove) { + if (cry && !cry.pendingRemove) { rate *= 0.99; - crySound.setRate(rate); + cry.setRate(rate); } else { faintCryTimer.destroy(); @@ -959,12 +1009,98 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } }); + // Failsafe this.scene.time.delayedCall(Utils.fixedInt(3000), () => { if (!faintCryTimer || !this.scene) return; - if (crySound?.isPlaying) - crySound.stop(); + if (cry?.isPlaying) + cry.stop(); + faintCryTimer.destroy(); + if (callback) + callback(); + }); + } + + private fusionFaintCry(callback: Function): void { + const key = this.getSpeciesForm().getCryKey(); + let i = 0; + let rate = 0.85; + let cry = this.scene.playSound(key, { rate: rate }) as AnySound; + const sprite = this.getSprite(); + const tintSprite = this.getTintSprite(); + let duration = cry.totalDuration * 1000; + + let fusionCry = this.scene.playSound(this.getFusionSpeciesForm().getCryKey(this.fusionFormIndex), { rate: rate }) as AnySound; + fusionCry.stop(); + duration = Math.min(duration, fusionCry.totalDuration * 1000); + fusionCry.destroy(); + + const delay = Math.max(duration * 0.05, 25); + + let transitionIndex = 0; + let durationProgress = 0; + + const transitionThreshold = Math.ceil(duration * 0.4); + while (durationProgress < transitionThreshold) { + ++i; + durationProgress += delay * rate; + rate *= 0.99; + } + + transitionIndex = i; + + i = 0; + rate = 0.85; + + let frameProgress = 0; + let frameThreshold: number; + + sprite.anims.pause(); + tintSprite.anims.pause(); + + let faintCryTimer = this.scene.time.addEvent({ + delay: Utils.fixedInt(delay), + repeat: -1, + callback: () => { + ++i; + frameThreshold = sprite.anims.msPerFrame / rate; + frameProgress += delay; + while (frameProgress > frameThreshold) { + if (sprite.anims.duration) { + sprite.anims.nextFrame(); + tintSprite.anims.nextFrame(); + } + frameProgress -= frameThreshold; + } + if (i === transitionIndex) { + SoundFade.fadeOut(this.scene, cry, Utils.fixedInt(Math.ceil((duration / rate) * 0.2))); + fusionCry = this.scene.playSound(this.getFusionSpeciesForm().getCryKey(this.fusionFormIndex), Object.assign({ seek: Math.max(fusionCry.totalDuration * 0.4, 0), rate: rate })); + SoundFade.fadeIn(this.scene, fusionCry, Utils.fixedInt(Math.ceil((duration / rate) * 0.2)), this.scene.masterVolume * this.scene.seVolume, 0); + } + rate *= 0.99; + if (cry && !cry.pendingRemove) + cry.setRate(rate); + if (fusionCry && !fusionCry.pendingRemove) + fusionCry.setRate(rate); + if ((!cry || cry.pendingRemove) && (!fusionCry || fusionCry.pendingRemove)) { + faintCryTimer.destroy(); + faintCryTimer = null; + if (callback) + callback(); + } + } + }); + + // Failsafe + this.scene.time.delayedCall(Utils.fixedInt(3000), () => { + console.log(faintCryTimer) + if (!faintCryTimer || !this.scene) + return; + if (cry?.isPlaying) + cry.stop(); + if (fusionCry?.isPlaying) + fusionCry.stop(); faintCryTimer.destroy(); if (callback) callback(); @@ -1220,6 +1356,53 @@ export class PlayerPokemon extends Pokemon { } } } + + isFusion(): boolean { + return !!(this.fusionSpecies || (this.species.speciesId === Species.KYUREM && this.formIndex)); + } + + fuse(pokemon: PlayerPokemon): Promise { + return new Promise(resolve => { + if (this.species.speciesId === Species.KYUREM && (pokemon.species.speciesId === Species.RESHIRAM || pokemon.species.speciesId === Species.ZEKROM)) + this.formIndex = pokemon.species.speciesId === Species.RESHIRAM ? 1 : 2; + else { + this.fusionSpecies = pokemon.species; + this.fusionFormIndex = pokemon.formIndex; + this.fusionAbilityIndex = pokemon.abilityIndex; + this.fusionShiny = pokemon.shiny; + this.fusionGender = pokemon.gender; + } + + this.calculateStats(); + this.updateInfo(true).then(() => { + const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon); + const fusedPartyMemberHeldModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).pokemonId === pokemon.id, true) as PokemonHeldItemModifier[]; + const transferModifiers: Promise[] = []; + for (let modifier of fusedPartyMemberHeldModifiers) + transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, true, false)); + Promise.allSettled(transferModifiers).then(() => { + this.scene.removePartyMemberModifiers(fusedPartyMemberIndex); + this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0]; + pokemon.destroy(); + resolve(); + }); + }); + }); + } + + unfuse(): Promise { + return new Promise(resolve => { + this.fusionSpecies = undefined; + this.fusionFormIndex = 0; + this.fusionAbilityIndex = 0; + this.fusionShiny = false; + this.fusionGender = 0; + + this.calculateStats(); + this.updateInfo(true).then(() => resolve()); + }); + } } export class EnemyPokemon extends Pokemon { diff --git a/src/system/game-speed.ts b/src/system/game-speed.ts index edd2ea74aa8..728e039073a 100644 --- a/src/system/game-speed.ts +++ b/src/system/game-speed.ts @@ -45,7 +45,7 @@ export function initGameSpeed() { sound: Phaser.Sound.BaseSound, duration: number, destroy?: boolean - ) => originalFadeOut(scene, sound, thisArg.gameSpeed === 1 ? duration : Math.ceil(duration /= thisArg.gameSpeed), destroy)) as FadeOut; + ) => originalFadeOut(scene, sound, transformValue(duration), destroy)) as FadeOut; const originalFadeIn = SoundFade.fadeIn; SoundFade.fadeIn = (( @@ -54,5 +54,5 @@ export function initGameSpeed() { duration: number, endVolume?: number, startVolume?: number - ) => originalFadeIn(scene, sound, thisArg.gameSpeed === 1 ? duration : Math.ceil(duration /= thisArg.gameSpeed), endVolume, startVolume)) as FadeIn; + ) => originalFadeIn(scene, sound, transformValue(duration), endVolume, startVolume)) as FadeIn; } \ No newline at end of file diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 5c768e02017..4ce2caa988b 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -27,6 +27,12 @@ export default class PokemonData { public winCount: integer; public pokerus: boolean; + public fusionSpecies: Species; + public fusionFormIndex: integer; + public fusionAbilityIndex: integer; + public fusionShiny: boolean; + public fusionGender: Gender; + public summonData: PokemonSummonData; constructor(source: Pokemon | any) { @@ -48,6 +54,12 @@ export default class PokemonData { this.winCount = source.winCount; this.pokerus = !!source.pokerus; + this.fusionSpecies = sourcePokemon ? sourcePokemon.fusionSpecies?.speciesId : source.fusionSpecies; + this.fusionFormIndex = source.fusionFormIndex; + this.fusionAbilityIndex = source.fusionAbilityIndex; + this.fusionShiny = source.fusionShiny; + this.fusionGender = source.fusionGender; + if (sourcePokemon) { this.moveset = sourcePokemon.moveset; this.status = sourcePokemon.status; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 9077ea948a9..8553a33adb2 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -271,7 +271,8 @@ export default class BattleInfo extends Phaser.GameObjects.Container { ratio = 0; instant = true; } - let duration = this.visible && !instant ? ((levelExp - this.lastLevelExp) / relLevelExp) * 1650 : 0; + const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction('Sine.easeIn')(1 - (Math.max(this.lastLevel - 100, 0) / 150)); + let duration = this.visible && !instant ? (((levelExp - this.lastLevelExp) / relLevelExp) * 1650) * durationMultiplier : 0; if (duration) (this.scene as BattleScene).playSound('exp'); this.scene.tweens.add({ diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 525bf843dd1..7524b1ee446 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -21,6 +21,7 @@ export enum PartyUiMode { MOVE_MODIFIER, TM_MODIFIER, MODIFIER_TRANSFER, + SPLICE, RELEASE } @@ -31,6 +32,7 @@ export enum PartyOption { APPLY, TEACH, TRANSFER, + SPLICE, SUMMARY, RELEASE, MOVE_1, @@ -41,6 +43,7 @@ export enum PartyOption { export type PartySelectCallback = (cursor: integer, option: PartyOption) => void; export type PartyModifierTransferSelectCallback = (fromCursor: integer, index: integer, toCursor?: integer) => void; +export type PartyModifierSpliceSelectCallback = (fromCursor: integer, toCursor?: integer) => void; export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string; export type PokemonModifierTransferSelectFilter = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => string; export type PokemonMoveSelectFilter = (pokemonMove: PokemonMove) => string; @@ -200,9 +203,9 @@ export default class PartyUiHandler extends MessageUiHandler { } else if ((option !== PartyOption.SUMMARY && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL) || (option === PartyOption.RELEASE && this.partyUiMode === PartyUiMode.RELEASE)) { let filterResult: string; - if (option !== PartyOption.TRANSFER) { + if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) { filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon); - if (filterResult === null && this.partyUiMode === PartyUiMode.MOVE_MODIFIER) + if (option === PartyOption.TRANSFER && filterResult === null && this.partyUiMode === PartyUiMode.MOVE_MODIFIER) filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]); } else { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier @@ -210,11 +213,19 @@ export default class PartyUiHandler extends MessageUiHandler { filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(pokemon, itemModifiers[this.transferOptionCursor]); } if (filterResult === null) { - this.clearOptions(); + if (this.partyUiMode !== PartyUiMode.SPLICE) + this.clearOptions(); if (this.selectCallback) { if (option === PartyOption.TRANSFER) { (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.cursor); this.clearTransfer(); + } else if (this.partyUiMode === PartyUiMode.SPLICE) { + if (option === PartyOption.SPLICE) { + (this.selectCallback as PartyModifierSpliceSelectCallback)(this.transferCursor, this.cursor); + this.clearTransfer(); + } else + this.startTransfer(); + this.clearOptions(); } else if (option === PartyOption.RELEASE) this.doRelease(this.cursor); else { @@ -276,7 +287,7 @@ export default class PartyUiHandler extends MessageUiHandler { this.processInput(Button.CANCEL); return; } else if (button === Button.CANCEL) { - if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && this.transferMode) { + if ((this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE) && this.transferMode) { this.clearTransfer(); ui.playSelect(); } else if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH) { @@ -404,6 +415,10 @@ export default class PartyUiHandler extends MessageUiHandler { if (!this.transferMode) optionsMessage = 'Select a held item to transfer.'; break; + case PartyUiMode.SPLICE: + if (!this.transferMode) + optionsMessage = 'Select another Pokémon to splice.'; + break; } this.showText(optionsMessage, 0); @@ -441,6 +456,13 @@ export default class PartyUiHandler extends MessageUiHandler { case PartyUiMode.MODIFIER_TRANSFER: this.options.push(PartyOption.TRANSFER); break; + case PartyUiMode.SPLICE: + if (this.transferMode) { + if (this.cursor !== this.transferCursor) + this.options.push(PartyOption.SPLICE); + } else + this.options.push(PartyOption.APPLY); + break; case PartyUiMode.RELEASE: this.options.push(PartyOption.RELEASE); break; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 93e870518bd..6795dd78e44 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -100,19 +100,19 @@ export default class SummaryUiHandler extends UiHandler { this.pokemonSprite = this.scene.add.sprite(56, -106, `pkmn__sub`); this.summaryContainer.add(this.pokemonSprite); - this.nameText = addTextObject(this.scene, 6, -39, '', TextStyle.SUMMARY); - this.nameText.setOrigin(0, 1); + this.nameText = addTextObject(this.scene, 6, -54, '', TextStyle.SUMMARY); + this.nameText.setOrigin(0, 0); this.summaryContainer.add(this.nameText); - this.pokeball = this.scene.add.sprite(6, -23, 'pb'); + this.pokeball = this.scene.add.sprite(6, -19, 'pb'); this.pokeball.setOrigin(0, 1); this.summaryContainer.add(this.pokeball); - this.levelText = addTextObject(this.scene, 36, -22, '', TextStyle.SUMMARY); + this.levelText = addTextObject(this.scene, 36, -18, '', TextStyle.SUMMARY); this.levelText.setOrigin(0, 1); this.summaryContainer.add(this.levelText); - this.genderText = addTextObject(this.scene, 96, -22, '', TextStyle.SUMMARY); + this.genderText = addTextObject(this.scene, 96, -18, '', TextStyle.SUMMARY); this.genderText.setOrigin(0, 1); this.summaryContainer.add(this.genderText); @@ -199,7 +199,17 @@ export default class SummaryUiHandler extends UiHandler { this.pokemonSprite.play(this.pokemon.getSpriteKey(true)); this.pokemon.cry(); - this.nameText.setText(this.pokemon.name); + let nameLabel = this.pokemon.name; + if (this.pokemon.fusionSpecies) + nameLabel += `/\n ${this.pokemon.fusionSpecies.name}`; + + this.nameText.setText(nameLabel); + + this.nameText.setFontSize(`${!this.pokemon.fusionSpecies ? '96px' : '72px'}`); + const nameShadowSize = !this.pokemon.fusionSpecies ? 6 : 4.5; + this.nameText.setShadowOffset(nameShadowSize, nameShadowSize); + this.nameText.setLineSpacing(!this.pokemon.fusionSpecies ? 5 : 0); + this.pokeball.setFrame(getPokeballAtlasKey(this.pokemon.pokeball)); this.levelText.setText(this.pokemon.level.toString()); this.genderText.setText(getGenderSymbol(this.pokemon.getGender(true))); @@ -478,7 +488,7 @@ export default class SummaryUiHandler extends UiHandler { if (this.pokemon.species.type2) profileContainer.add(getTypeIcon(1, this.pokemon.species.type2)); - const ability = abilities[this.pokemon.species.getAbility(this.pokemon.abilityIndex)]; + const ability = this.pokemon.getAbility(); const abilityNameText = addTextObject(this.scene, 7, 66, ability.name, TextStyle.SUMMARY); abilityNameText.setOrigin(0, 1); diff --git a/src/ui/text.ts b/src/ui/text.ts index 549d7cf9c3b..420132820c1 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -101,7 +101,6 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean) { } export function getModifierTierTextTint(tier: integer): integer { - console.log(tier); switch (tier) { case 0: // ModifierTier.COMMON: return 0xffffff;