From 8e3f13db43e25029bc96eed7fa6d9d8cfcc4555e Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Mon, 19 Aug 2024 10:54:09 -0400 Subject: [PATCH 1/4] adds Winstrate Challenge mystery encounter --- public/images/items.json | 2209 +++++++++-------- public/images/items.png | Bin 56766 -> 57721 bytes public/images/items/macho_brace.png | Bin 0 -> 372 bytes public/images/trainer/vicky.json | 41 + public/images/trainer/vicky.png | Bin 0 -> 765 bytes public/images/trainer/victor.json | 41 + public/images/trainer/victor.png | Bin 0 -> 794 bytes public/images/trainer/victoria.json | 41 + public/images/trainer/victoria.png | Bin 0 -> 813 bytes public/images/trainer/vito.json | 41 + public/images/trainer/vito.png | Bin 0 -> 765 bytes public/images/trainer/vivi.json | 41 + public/images/trainer/vivi.png | Bin 0 -> 713 bytes src/battle-scene.ts | 37 +- src/battle.ts | 4 +- src/data/dialogue.ts | 50 + .../encounters/a-trainers-test-encounter.ts | 17 +- .../encounters/absolute-avarice-encounter.ts | 19 +- .../an-offer-you-cant-refuse-encounter.ts | 4 +- .../encounters/berries-abound-encounter.ts | 8 +- .../encounters/clowning-around-encounter.ts | 13 +- .../encounters/dancing-lessons-encounter.ts | 4 +- .../encounters/dark-deal-encounter.ts | 4 +- .../encounters/delibirdy-encounter.ts | 14 +- .../department-store-sale-encounter.ts | 4 +- .../encounters/field-trip-encounter.ts | 4 +- .../encounters/fiery-fallout-encounter.ts | 4 +- .../encounters/fight-or-flight-encounter.ts | 4 +- .../encounters/lost-at-sea-encounter.ts | 2 +- .../mysterious-challengers-encounter.ts | 4 +- .../encounters/mysterious-chest-encounter.ts | 9 +- .../encounters/part-timer-encounter.ts | 4 +- .../encounters/safari-zone-encounter.ts | 24 +- .../shady-vitamin-dealer-encounter.ts | 14 +- .../slumbering-snorlax-encounter.ts | 4 +- .../the-pokemon-salesman-encounter.ts | 4 +- .../encounters/the-strong-stuff-encounter.ts | 26 +- .../the-winstrate-challenge-encounter.ts | 488 ++++ .../encounters/training-session-encounter.ts | 6 +- .../encounters/trash-to-treasure-encounter.ts | 10 +- .../encounters/weird-dream-encounter.ts | 9 +- .../mystery-encounters/mystery-encounter.ts | 144 +- .../mystery-encounters/mystery-encounters.ts | 7 +- .../utils/encounter-phase-utils.ts | 44 +- .../encounter-transformation-sequence.ts | 44 +- src/data/trainer-config.ts | 15 + src/enums/mystery-encounter-mode.ts | 5 +- src/enums/mystery-encounter-type.ts | 3 +- src/enums/trainer-type.ts | 5 + src/field/mystery-encounter-intro.ts | 6 +- src/field/pokemon.ts | 3 +- src/interfaces/held-modifier-config.ts | 7 + src/locales/en/dialogue.ts | 45 + src/locales/en/modifier-type.ts | 1 + src/locales/en/mystery-encounter.ts | 4 +- .../the-winstrate-challenge-dialogue.ts | 24 + src/locales/en/trainers.ts | 6 + src/modifier/modifier-type.ts | 1 + src/modifier/modifier.ts | 48 + src/phases.ts | 15 +- src/phases/mystery-encounter-phases.ts | 39 +- src/system/game-data.ts | 6 +- .../clowning-around-encounter.test.ts | 21 +- .../encounters/delibirdy-encounter.test.ts | 32 +- .../mysterious-challengers-encounter.test.ts | 4 +- .../the-strong-stuff-encounter.test.ts | 2 +- .../mystery-encounter-utils.test.ts | 12 +- 67 files changed, 2374 insertions(+), 1377 deletions(-) create mode 100644 public/images/items/macho_brace.png create mode 100644 public/images/trainer/vicky.json create mode 100644 public/images/trainer/vicky.png create mode 100644 public/images/trainer/victor.json create mode 100644 public/images/trainer/victor.png create mode 100644 public/images/trainer/victoria.json create mode 100644 public/images/trainer/victoria.png create mode 100644 public/images/trainer/vito.json create mode 100644 public/images/trainer/vito.png create mode 100644 public/images/trainer/vivi.json create mode 100644 public/images/trainer/vivi.png create mode 100644 src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts create mode 100644 src/interfaces/held-modifier-config.ts create mode 100644 src/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.ts diff --git a/public/images/items.json b/public/images/items.json index 01d28e79e582..5ac69059d646 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -3349,7 +3349,7 @@ } }, { - "filename": "mystic_water", + "filename": "macho_brace", "rotated": false, "trimmed": true, "sourceSize": { @@ -3357,20 +3357,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 4, "y": 5, - "w": 20, + "w": 23, "h": 23 }, "frame": { "x": 162, "y": 400, - "w": 20, + "w": 23, "h": 23 } }, { - "filename": "never_melt_ice", + "filename": "mystic_water", "rotated": false, "trimmed": true, "sourceSize": { @@ -3378,20 +3378,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 6, "y": 5, - "w": 22, + "w": 20, "h": 23 }, "frame": { "x": 166, "y": 263, - "w": 22, + "w": 20, "h": 23 } }, { - "filename": "normal_tera_shard", + "filename": "never_melt_ice", "rotated": false, "trimmed": true, "sourceSize": { @@ -3399,8 +3399,8 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, + "x": 5, + "y": 5, "w": 22, "h": 23 }, @@ -3433,7 +3433,7 @@ } }, { - "filename": "petaya_berry", + "filename": "normal_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3441,8 +3441,8 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, + "x": 6, + "y": 4, "w": 22, "h": 23 }, @@ -3454,7 +3454,7 @@ } }, { - "filename": "poison_tera_shard", + "filename": "petaya_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -3462,8 +3462,8 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, + "x": 5, + "y": 5, "w": 22, "h": 23 }, @@ -3475,7 +3475,7 @@ } }, { - "filename": "psychic_tera_shard", + "filename": "poison_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3496,7 +3496,7 @@ } }, { - "filename": "rare_candy", + "filename": "psychic_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3504,15 +3504,15 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, + "x": 6, + "y": 4, + "w": 22, "h": 23 }, "frame": { - "x": 182, + "x": 185, "y": 400, - "w": 23, + "w": 22, "h": 23 } }, @@ -3538,7 +3538,7 @@ } }, { - "filename": "rarer_candy", + "filename": "rare_candy", "rotated": false, "trimmed": true, "sourceSize": { @@ -3559,7 +3559,7 @@ } }, { - "filename": "healing_charm", + "filename": "rarer_candy", "rotated": false, "trimmed": true, "sourceSize": { @@ -3567,20 +3567,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 4, "y": 5, "w": 23, - "h": 22 + "h": 23 }, "frame": { "x": 161, "y": 64, "w": 23, - "h": 22 + "h": 23 } }, { - "filename": "reaper_cloth", + "filename": "healing_charm", "rotated": false, "trimmed": true, "sourceSize": { @@ -3590,18 +3590,18 @@ "spriteSourceSize": { "x": 5, "y": 5, - "w": 22, - "h": 23 + "w": 23, + "h": 22 }, "frame": { "x": 161, - "y": 86, - "w": 22, - "h": 23 + "y": 87, + "w": 23, + "h": 22 } }, { - "filename": "rock_tera_shard", + "filename": "reaper_cloth", "rotated": false, "trimmed": true, "sourceSize": { @@ -3609,8 +3609,8 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, + "x": 5, + "y": 5, "w": 22, "h": 23 }, @@ -3622,7 +3622,7 @@ } }, { - "filename": "sharp_beak", + "filename": "rock_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3630,20 +3630,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, + "x": 6, + "y": 4, + "w": 22, "h": 23 }, "frame": { "x": 163, "y": 132, - "w": 21, + "w": 22, "h": 23 } }, { - "filename": "dawn_stone", + "filename": "deep_sea_tooth", "rotated": false, "trimmed": true, "sourceSize": { @@ -3651,15 +3651,15 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, "y": 6, - "w": 20, + "w": 22, "h": 21 }, "frame": { "x": 164, "y": 155, - "w": 20, + "w": 22, "h": 21 } }, @@ -3741,7 +3741,7 @@ "h": 23 }, "frame": { - "x": 183, + "x": 184, "y": 86, "w": 22, "h": 23 @@ -3769,7 +3769,7 @@ } }, { - "filename": "whipped_dream", + "filename": "sharp_beak", "rotated": false, "trimmed": true, "sourceSize": { @@ -3778,12 +3778,12 @@ }, "spriteSourceSize": { "x": 5, - "y": 4, + "y": 5, "w": 21, "h": 23 }, "frame": { - "x": 184, + "x": 185, "y": 132, "w": 21, "h": 23 @@ -3867,54 +3867,12 @@ "h": 22 }, "frame": { - "x": 205, + "x": 206, "y": 86, "w": 22, "h": 22 } }, - { - "filename": "charcoal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 205, - "y": 108, - "w": 22, - "h": 22 - } - }, - { - "filename": "dark_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 205, - "y": 130, - "w": 22, - "h": 22 - } - }, { "filename": "moon_stone", "rotated": false, @@ -4000,7 +3958,7 @@ } }, { - "filename": "deep_sea_tooth", + "filename": "charcoal", "rotated": false, "trimmed": true, "sourceSize": { @@ -4009,19 +3967,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 21 + "h": 22 }, "frame": { - "x": 184, + "x": 186, "y": 155, "w": 22, - "h": 21 + "h": 22 } }, { - "filename": "relic_crown", + "filename": "mystery_egg", "rotated": false, "trimmed": true, "sourceSize": { @@ -4029,20 +3987,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, + "x": 8, + "y": 8, + "w": 16, "h": 18 }, "frame": { "x": 170, "y": 176, - "w": 23, + "w": 16, "h": 18 } }, { - "filename": "sachet", + "filename": "black_glasses", "rotated": false, "trimmed": true, "sourceSize": { @@ -4050,20 +4008,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 18, - "h": 23 + "x": 4, + "y": 8, + "w": 23, + "h": 17 }, "frame": { - "x": 175, - "y": 194, - "w": 18, - "h": 23 + "x": 186, + "y": 177, + "w": 23, + "h": 17 } }, { - "filename": "dire_hit", + "filename": "whipped_dream", "rotated": false, "trimmed": true, "sourceSize": { @@ -4072,19 +4030,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 5, - "w": 22, - "h": 22 + "y": 4, + "w": 21, + "h": 23 }, "frame": { - "x": 206, - "y": 152, - "w": 22, - "h": 22 + "x": 175, + "y": 194, + "w": 21, + "h": 23 } }, { - "filename": "potion", + "filename": "dark_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -4092,20 +4050,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 5, - "w": 17, - "h": 23 + "w": 22, + "h": 22 }, "frame": { "x": 176, "y": 217, - "w": 17, - "h": 23 + "w": 22, + "h": 22 } }, { - "filename": "super_potion", + "filename": "dire_hit", "rotated": false, "trimmed": true, "sourceSize": { @@ -4113,16 +4071,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 5, - "w": 17, - "h": 23 + "w": 22, + "h": 22 }, "frame": { "x": 176, - "y": 240, - "w": 17, - "h": 23 + "y": 239, + "w": 22, + "h": 22 } }, { @@ -4245,7 +4203,7 @@ "h": 22 }, "frame": { - "x": 227, + "x": 228, "y": 86, "w": 22, "h": 22 @@ -4287,8 +4245,8 @@ "h": 22 }, "frame": { - "x": 227, - "y": 108, + "x": 250, + "y": 86, "w": 22, "h": 22 } @@ -4308,8 +4266,8 @@ "h": 22 }, "frame": { - "x": 227, - "y": 130, + "x": 272, + "y": 64, "w": 22, "h": 22 } @@ -4329,7 +4287,7 @@ "h": 22 }, "frame": { - "x": 249, + "x": 272, "y": 86, "w": 22, "h": 22 @@ -4350,7 +4308,7 @@ "h": 22 }, "frame": { - "x": 272, + "x": 294, "y": 64, "w": 22, "h": 22 @@ -4371,8 +4329,8 @@ "h": 22 }, "frame": { - "x": 249, - "y": 108, + "x": 294, + "y": 86, "w": 22, "h": 22 } @@ -4392,8 +4350,8 @@ "h": 22 }, "frame": { - "x": 271, - "y": 86, + "x": 317, + "y": 42, "w": 22, "h": 22 } @@ -4413,7 +4371,7 @@ "h": 22 }, "frame": { - "x": 294, + "x": 316, "y": 64, "w": 22, "h": 22 @@ -4434,8 +4392,8 @@ "h": 22 }, "frame": { - "x": 249, - "y": 130, + "x": 339, + "y": 42, "w": 22, "h": 22 } @@ -4455,8 +4413,8 @@ "h": 22 }, "frame": { - "x": 228, - "y": 152, + "x": 316, + "y": 86, "w": 22, "h": 22 } @@ -4476,8 +4434,8 @@ "h": 22 }, "frame": { - "x": 271, - "y": 108, + "x": 338, + "y": 64, "w": 22, "h": 22 } @@ -4497,14 +4455,14 @@ "h": 22 }, "frame": { - "x": 293, + "x": 338, "y": 86, "w": 22, "h": 22 } }, { - "filename": "poison_memory", + "filename": "metronome", "rotated": false, "trimmed": true, "sourceSize": { @@ -4512,20 +4470,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 7, "y": 5, - "w": 22, + "w": 17, "h": 22 }, "frame": { - "x": 271, - "y": 130, - "w": 22, + "x": 361, + "y": 42, + "w": 17, "h": 22 } }, { - "filename": "protector", + "filename": "liechi_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -4534,19 +4492,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 5, + "y": 6, "w": 22, - "h": 22 + "h": 21 }, "frame": { - "x": 250, - "y": 152, + "x": 378, + "y": 43, "w": 22, - "h": 22 + "h": 21 } }, { - "filename": "psychic_memory", + "filename": "poison_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -4560,14 +4518,14 @@ "h": 22 }, "frame": { - "x": 293, - "y": 108, + "x": 360, + "y": 64, "w": 22, "h": 22 } }, { - "filename": "rock_memory", + "filename": "protector", "rotated": false, "trimmed": true, "sourceSize": { @@ -4581,14 +4539,14 @@ "h": 22 }, "frame": { - "x": 293, - "y": 130, + "x": 360, + "y": 86, "w": 22, "h": 22 } }, { - "filename": "scroll_of_darkness", + "filename": "sachet", "rotated": false, "trimmed": true, "sourceSize": { @@ -4596,20 +4554,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 6, + "y": 4, + "w": 18, + "h": 23 }, "frame": { - "x": 272, - "y": 152, - "w": 22, - "h": 22 + "x": 382, + "y": 64, + "w": 18, + "h": 23 } }, { - "filename": "scroll_of_waters", + "filename": "psychic_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -4623,14 +4581,14 @@ "h": 22 }, "frame": { - "x": 294, - "y": 152, + "x": 400, + "y": 62, "w": 22, "h": 22 } }, { - "filename": "shed_shell", + "filename": "dawn_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -4638,20 +4596,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 6, + "y": 6, + "w": 20, + "h": 21 }, "frame": { - "x": 317, - "y": 42, - "w": 22, - "h": 22 + "x": 382, + "y": 87, + "w": 20, + "h": 21 } }, { - "filename": "starf_berry", + "filename": "hard_meteorite", "rotated": false, "trimmed": true, "sourceSize": { @@ -4659,20 +4617,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 7, "y": 5, - "w": 22, + "w": 20, "h": 22 }, "frame": { - "x": 316, - "y": 64, - "w": 22, + "x": 402, + "y": 84, + "w": 20, "h": 22 } }, { - "filename": "steel_memory", + "filename": "potion", "rotated": false, "trimmed": true, "sourceSize": { @@ -4680,20 +4638,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 8, "y": 5, - "w": 22, - "h": 22 + "w": 17, + "h": 23 }, "frame": { - "x": 315, - "y": 86, - "w": 22, - "h": 22 + "x": 196, + "y": 194, + "w": 17, + "h": 23 } }, { - "filename": "thick_club", + "filename": "super_potion", "rotated": false, "trimmed": true, "sourceSize": { @@ -4701,20 +4659,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 8, "y": 5, - "w": 22, - "h": 22 + "w": 17, + "h": 23 }, "frame": { - "x": 339, - "y": 42, - "w": 22, - "h": 22 + "x": 198, + "y": 217, + "w": 17, + "h": 23 } }, { - "filename": "thunder_stone", + "filename": "dusk_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -4722,20 +4680,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 6, + "y": 6, + "w": 21, + "h": 21 }, "frame": { - "x": 338, - "y": 64, - "w": 22, - "h": 22 + "x": 198, + "y": 240, + "w": 21, + "h": 21 } }, { - "filename": "tm_bug", + "filename": "rock_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -4749,14 +4707,14 @@ "h": 22 }, "frame": { - "x": 315, - "y": 108, + "x": 186, + "y": 261, "w": 22, "h": 22 } }, { - "filename": "tm_dark", + "filename": "metal_coat", "rotated": false, "trimmed": true, "sourceSize": { @@ -4764,20 +4722,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 6, "y": 5, - "w": 22, + "w": 19, "h": 22 }, "frame": { - "x": 315, - "y": 130, - "w": 22, + "x": 190, + "y": 283, + "w": 19, "h": 22 } }, { - "filename": "tm_dragon", + "filename": "leftovers", "rotated": false, "trimmed": true, "sourceSize": { @@ -4785,20 +4743,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 8, "y": 5, - "w": 22, + "w": 15, "h": 22 }, "frame": { - "x": 337, - "y": 86, - "w": 22, + "x": 208, + "y": 261, + "w": 15, "h": 22 } }, { - "filename": "tm_electric", + "filename": "scroll_of_darkness", "rotated": false, "trimmed": true, "sourceSize": { @@ -4812,14 +4770,14 @@ "h": 22 }, "frame": { - "x": 337, - "y": 108, + "x": 209, + "y": 283, "w": 22, "h": 22 } }, { - "filename": "tm_fairy", + "filename": "scroll_of_waters", "rotated": false, "trimmed": true, "sourceSize": { @@ -4833,14 +4791,14 @@ "h": 22 }, "frame": { - "x": 337, - "y": 130, + "x": 193, + "y": 305, "w": 22, "h": 22 } }, { - "filename": "tm_fighting", + "filename": "shed_shell", "rotated": false, "trimmed": true, "sourceSize": { @@ -4854,14 +4812,14 @@ "h": 22 }, "frame": { - "x": 316, - "y": 152, + "x": 215, + "y": 305, "w": 22, "h": 22 } }, { - "filename": "tm_fire", + "filename": "starf_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -4875,14 +4833,14 @@ "h": 22 }, "frame": { - "x": 338, - "y": 152, + "x": 201, + "y": 327, "w": 22, "h": 22 } }, { - "filename": "metronome", + "filename": "steel_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -4890,20 +4848,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 5, "y": 5, - "w": 17, + "w": 22, "h": 22 }, "frame": { - "x": 361, - "y": 42, - "w": 17, + "x": 201, + "y": 349, + "w": 22, "h": 22 } }, { - "filename": "liechi_berry", + "filename": "sitrus_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -4911,20 +4869,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 + "x": 6, + "y": 5, + "w": 20, + "h": 22 }, "frame": { - "x": 378, - "y": 43, - "w": 22, - "h": 21 + "x": 223, + "y": 327, + "w": 20, + "h": 22 } }, { - "filename": "tm_flying", + "filename": "thick_club", "rotated": false, "trimmed": true, "sourceSize": { @@ -4938,14 +4896,14 @@ "h": 22 }, "frame": { - "x": 360, - "y": 64, + "x": 223, + "y": 349, "w": 22, "h": 22 } }, { - "filename": "tm_ghost", + "filename": "thunder_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -4959,14 +4917,14 @@ "h": 22 }, "frame": { - "x": 359, - "y": 86, + "x": 203, + "y": 371, "w": 22, "h": 22 } }, { - "filename": "tm_grass", + "filename": "tm_bug", "rotated": false, "trimmed": true, "sourceSize": { @@ -4980,14 +4938,14 @@ "h": 22 }, "frame": { - "x": 359, - "y": 108, + "x": 225, + "y": 371, "w": 22, "h": 22 } }, { - "filename": "tm_ground", + "filename": "tm_dark", "rotated": false, "trimmed": true, "sourceSize": { @@ -5001,14 +4959,14 @@ "h": 22 }, "frame": { - "x": 359, - "y": 130, + "x": 207, + "y": 393, "w": 22, "h": 22 } }, { - "filename": "tm_ice", + "filename": "tm_dragon", "rotated": false, "trimmed": true, "sourceSize": { @@ -5022,14 +4980,14 @@ "h": 22 }, "frame": { - "x": 360, - "y": 152, + "x": 229, + "y": 393, "w": 22, "h": 22 } }, { - "filename": "hard_meteorite", + "filename": "relic_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -5037,20 +4995,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 20, - "h": 22 + "x": 9, + "y": 11, + "w": 15, + "h": 11 }, "frame": { - "x": 382, - "y": 64, - "w": 20, - "h": 22 + "x": 207, + "y": 415, + "w": 15, + "h": 11 } }, { - "filename": "tm_normal", + "filename": "burn_drive", "rotated": false, "trimmed": true, "sourceSize": { @@ -5058,20 +5016,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 4, + "y": 8, + "w": 23, + "h": 17 }, "frame": { - "x": 381, - "y": 86, - "w": 22, - "h": 22 + "x": 206, + "y": 108, + "w": 23, + "h": 17 } }, { - "filename": "tm_poison", + "filename": "chill_drive", "rotated": false, "trimmed": true, "sourceSize": { @@ -5079,20 +5037,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 4, + "y": 8, + "w": 23, + "h": 17 }, "frame": { - "x": 381, + "x": 229, "y": 108, - "w": 22, - "h": 22 + "w": 23, + "h": 17 } }, { - "filename": "tm_psychic", + "filename": "coupon", "rotated": false, "trimmed": true, "sourceSize": { @@ -5100,20 +5058,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 4, + "y": 7, + "w": 23, + "h": 19 }, "frame": { - "x": 381, - "y": 130, - "w": 22, - "h": 22 + "x": 252, + "y": 108, + "w": 23, + "h": 19 } }, { - "filename": "reviver_seed", + "filename": "golden_mystic_ticket", "rotated": false, "trimmed": true, "sourceSize": { @@ -5121,20 +5079,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 8, + "x": 4, + "y": 7, "w": 23, - "h": 20 + "h": 19 }, "frame": { - "x": 403, - "y": 62, + "x": 275, + "y": 108, "w": 23, - "h": 20 + "h": 19 } }, { - "filename": "shell_bell", + "filename": "mystic_ticket", "rotated": false, "trimmed": true, "sourceSize": { @@ -5142,20 +5100,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 4, "y": 7, "w": 23, - "h": 20 + "h": 19 }, "frame": { - "x": 403, - "y": 82, + "x": 298, + "y": 108, "w": 23, - "h": 20 + "h": 19 } }, { - "filename": "coupon", + "filename": "pair_of_tickets", "rotated": false, "trimmed": true, "sourceSize": { @@ -5169,14 +5127,14 @@ "h": 19 }, "frame": { - "x": 403, - "y": 102, + "x": 321, + "y": 108, "w": 23, "h": 19 } }, { - "filename": "golden_mystic_ticket", + "filename": "reviver_seed", "rotated": false, "trimmed": true, "sourceSize": { @@ -5184,20 +5142,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 7, + "x": 5, + "y": 8, "w": 23, - "h": 19 + "h": 20 }, "frame": { - "x": 403, - "y": 121, + "x": 344, + "y": 108, "w": 23, - "h": 19 + "h": 20 } }, { - "filename": "mystic_ticket", + "filename": "shell_bell", "rotated": false, "trimmed": true, "sourceSize": { @@ -5205,20 +5163,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, + "x": 5, "y": 7, "w": 23, - "h": 19 + "h": 20 }, "frame": { - "x": 403, - "y": 140, + "x": 367, + "y": 108, "w": 23, - "h": 19 + "h": 20 } }, { - "filename": "dusk_stone", + "filename": "tm_electric", "rotated": false, "trimmed": true, "sourceSize": { @@ -5226,20 +5184,125 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 206, + "y": 125, + "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": 228, + "y": 125, + "w": 22, + "h": 22 + } + }, + { + "filename": "deep_sea_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, "y": 6, - "w": 21, + "w": 22, + "h": 20 + }, + "frame": { + "x": 250, + "y": 127, + "w": 22, + "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": 272, + "y": 127, + "w": 22, + "h": 20 + } + }, + { + "filename": "malicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 294, + "y": 127, + "w": 22, + "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": 382, - "y": 152, - "w": 21, + "x": 316, + "y": 127, + "w": 22, "h": 21 } }, { - "filename": "pair_of_tickets", + "filename": "syrupy_apple", "rotated": false, "trimmed": true, "sourceSize": { @@ -5247,20 +5310,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 + "x": 5, + "y": 6, + "w": 22, + "h": 21 }, "frame": { - "x": 403, - "y": 159, - "w": 23, - "h": 19 + "x": 338, + "y": 128, + "w": 22, + "h": 21 } }, { - "filename": "leftovers", + "filename": "tart_apple", "rotated": false, "trimmed": true, "sourceSize": { @@ -5268,20 +5331,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 15, - "h": 22 + "x": 5, + "y": 6, + "w": 22, + "h": 21 }, "frame": { - "x": 193, - "y": 176, - "w": 15, - "h": 22 + "x": 360, + "y": 128, + "w": 22, + "h": 21 } }, { - "filename": "tm_rock", + "filename": "tm_fighting", "rotated": false, "trimmed": true, "sourceSize": { @@ -5296,13 +5359,13 @@ }, "frame": { "x": 208, - "y": 174, + "y": 147, "w": 22, "h": 22 } }, { - "filename": "tm_steel", + "filename": "tm_fire", "rotated": false, "trimmed": true, "sourceSize": { @@ -5317,13 +5380,13 @@ }, "frame": { "x": 230, - "y": 174, + "y": 147, "w": 22, "h": 22 } }, { - "filename": "tm_water", + "filename": "tm_flying", "rotated": false, "trimmed": true, "sourceSize": { @@ -5338,13 +5401,13 @@ }, "frame": { "x": 252, - "y": 174, + "y": 147, "w": 22, "h": 22 } }, { - "filename": "water_memory", + "filename": "tm_ghost", "rotated": false, "trimmed": true, "sourceSize": { @@ -5359,13 +5422,13 @@ }, "frame": { "x": 274, - "y": 174, + "y": 147, "w": 22, "h": 22 } }, { - "filename": "water_stone", + "filename": "big_nugget", "rotated": false, "trimmed": true, "sourceSize": { @@ -5373,20 +5436,62 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 + "x": 6, + "y": 6, + "w": 20, + "h": 20 }, "frame": { "x": 296, - "y": 174, + "y": 147, + "w": 20, + "h": 20 + } + }, + { + "filename": "black_sludge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 24, + "h": 24 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, "w": 22, - "h": 22 + "h": 19 + }, + "frame": { + "x": 316, + "y": 148, + "w": 22, + "h": 19 } }, { - "filename": "x_accuracy", + "filename": "relic_crown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 18 + }, + "frame": { + "x": 338, + "y": 149, + "w": 23, + "h": 18 + } + }, + { + "filename": "blunder_policy", "rotated": false, "trimmed": true, "sourceSize": { @@ -5395,19 +5500,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 5, + "y": 6, "w": 22, - "h": 22 + "h": 19 }, "frame": { - "x": 318, - "y": 174, + "x": 361, + "y": 149, "w": 22, - "h": 22 + "h": 19 } }, { - "filename": "x_attack", + "filename": "tm_grass", "rotated": false, "trimmed": true, "sourceSize": { @@ -5421,14 +5526,14 @@ "h": 22 }, "frame": { - "x": 340, - "y": 174, + "x": 209, + "y": 169, "w": 22, "h": 22 } }, { - "filename": "sitrus_berry", + "filename": "tm_ground", "rotated": false, "trimmed": true, "sourceSize": { @@ -5436,20 +5541,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, "y": 5, - "w": 20, + "w": 22, "h": 22 }, "frame": { - "x": 362, - "y": 174, - "w": 20, + "x": 231, + "y": 169, + "w": 22, "h": 22 } }, { - "filename": "poison_barb", + "filename": "tm_ice", "rotated": false, "trimmed": true, "sourceSize": { @@ -5458,19 +5563,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, - "w": 21, - "h": 21 + "y": 5, + "w": 22, + "h": 22 }, "frame": { - "x": 382, - "y": 173, - "w": 21, - "h": 21 + "x": 253, + "y": 169, + "w": 22, + "h": 22 } }, { - "filename": "black_glasses", + "filename": "tm_normal", "rotated": false, "trimmed": true, "sourceSize": { @@ -5478,20 +5583,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 + "x": 5, + "y": 5, + "w": 22, + "h": 22 }, "frame": { - "x": 403, - "y": 178, - "w": 23, - "h": 17 + "x": 275, + "y": 169, + "w": 22, + "h": 22 } }, { - "filename": "metal_coat", + "filename": "tm_poison", "rotated": false, "trimmed": true, "sourceSize": { @@ -5499,20 +5604,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, "y": 5, - "w": 19, + "w": 22, "h": 22 }, "frame": { - "x": 193, - "y": 198, - "w": 19, + "x": 297, + "y": 167, + "w": 22, "h": 22 } }, { - "filename": "x_defense", + "filename": "tm_psychic", "rotated": false, "trimmed": true, "sourceSize": { @@ -5526,14 +5631,35 @@ "h": 22 }, "frame": { - "x": 212, - "y": 196, + "x": 319, + "y": 167, "w": 22, "h": 22 } }, { - "filename": "x_sp_atk", + "filename": "blue_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 341, + "y": 167, + "w": 20, + "h": 20 + } + }, + { + "filename": "dubious_disc", "rotated": false, "trimmed": true, "sourceSize": { @@ -5542,19 +5668,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 5, + "y": 7, "w": 22, - "h": 22 + "h": 19 }, "frame": { - "x": 234, - "y": 196, + "x": 361, + "y": 168, "w": 22, - "h": 22 + "h": 19 } }, { - "filename": "x_sp_def", + "filename": "tm_rock", "rotated": false, "trimmed": true, "sourceSize": { @@ -5568,14 +5694,14 @@ "h": 22 }, "frame": { - "x": 256, - "y": 196, + "x": 213, + "y": 191, "w": 22, "h": 22 } }, { - "filename": "x_speed", + "filename": "tm_steel", "rotated": false, "trimmed": true, "sourceSize": { @@ -5589,14 +5715,14 @@ "h": 22 }, "frame": { - "x": 278, - "y": 196, + "x": 235, + "y": 191, "w": 22, "h": 22 } }, { - "filename": "sweet_apple", + "filename": "tm_water", "rotated": false, "trimmed": true, "sourceSize": { @@ -5605,19 +5731,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 21 + "h": 22 }, "frame": { - "x": 300, - "y": 196, + "x": 257, + "y": 191, "w": 22, - "h": 21 + "h": 22 } }, { - "filename": "syrupy_apple", + "filename": "water_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -5626,19 +5752,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 21 + "h": 22 }, "frame": { - "x": 322, - "y": 196, + "x": 215, + "y": 213, "w": 22, - "h": 21 + "h": 22 } }, { - "filename": "tart_apple", + "filename": "water_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -5647,19 +5773,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 21 + "h": 22 }, "frame": { - "x": 344, - "y": 196, + "x": 237, + "y": 213, "w": 22, - "h": 21 + "h": 22 } }, { - "filename": "quick_claw", + "filename": "x_accuracy", "rotated": false, "trimmed": true, "sourceSize": { @@ -5667,20 +5793,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 21 + "x": 5, + "y": 5, + "w": 22, + "h": 22 }, "frame": { - "x": 193, - "y": 220, - "w": 19, - "h": 21 + "x": 259, + "y": 213, + "w": 22, + "h": 22 } }, { - "filename": "deep_sea_scale", + "filename": "x_attack", "rotated": false, "trimmed": true, "sourceSize": { @@ -5689,19 +5815,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 20 + "h": 22 }, "frame": { - "x": 212, - "y": 218, + "x": 279, + "y": 191, "w": 22, - "h": 20 + "h": 22 } }, { - "filename": "fairy_feather", + "filename": "x_defense", "rotated": false, "trimmed": true, "sourceSize": { @@ -5710,19 +5836,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 7, + "y": 5, "w": 22, - "h": 20 + "h": 22 }, "frame": { - "x": 234, - "y": 218, + "x": 301, + "y": 189, "w": 22, - "h": 20 + "h": 22 } }, { - "filename": "malicious_armor", + "filename": "x_sp_atk", "rotated": false, "trimmed": true, "sourceSize": { @@ -5731,19 +5857,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 20 + "h": 22 }, "frame": { - "x": 256, - "y": 218, + "x": 281, + "y": 213, "w": 22, - "h": 20 + "h": 22 } }, { - "filename": "tera_orb", + "filename": "x_sp_def", "rotated": false, "trimmed": true, "sourceSize": { @@ -5752,19 +5878,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, + "y": 5, "w": 22, - "h": 20 + "h": 22 }, "frame": { - "x": 278, - "y": 218, + "x": 323, + "y": 189, "w": 22, - "h": 20 + "h": 22 } }, { - "filename": "shiny_stone", + "filename": "x_speed", "rotated": false, "trimmed": true, "sourceSize": { @@ -5773,19 +5899,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 6, - "w": 21, - "h": 21 + "y": 5, + "w": 22, + "h": 22 }, "frame": { - "x": 300, - "y": 217, - "w": 21, - "h": 21 + "x": 303, + "y": 211, + "w": 22, + "h": 22 } }, { - "filename": "zoom_lens", + "filename": "poison_barb", "rotated": false, "trimmed": true, "sourceSize": { @@ -5799,35 +5925,35 @@ "h": 21 }, "frame": { - "x": 321, - "y": 217, + "x": 325, + "y": 211, "w": 21, "h": 21 } }, { - "filename": "black_sludge", + "filename": "shiny_stone", "rotated": false, "trimmed": true, "sourceSize": { - "w": 24, - "h": 24 + "w": 32, + "h": 32 }, "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 22, - "h": 19 + "x": 5, + "y": 6, + "w": 21, + "h": 21 }, "frame": { - "x": 342, - "y": 217, - "w": 22, - "h": 19 + "x": 345, + "y": 187, + "w": 21, + "h": 21 } }, { - "filename": "spell_tag", + "filename": "quick_claw", "rotated": false, "trimmed": true, "sourceSize": { @@ -5835,20 +5961,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 6, "y": 6, "w": 19, "h": 21 }, "frame": { - "x": 193, - "y": 241, + "x": 366, + "y": 187, "w": 19, "h": 21 } }, { - "filename": "blunder_policy", + "filename": "tera_orb", "rotated": false, "trimmed": true, "sourceSize": { @@ -5859,17 +5985,17 @@ "x": 5, "y": 6, "w": 22, - "h": 19 + "h": 20 }, "frame": { - "x": 212, - "y": 238, + "x": 346, + "y": 208, "w": 22, - "h": 19 + "h": 20 } }, { - "filename": "dubious_disc", + "filename": "apicot_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -5877,20 +6003,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 + "x": 6, + "y": 6, + "w": 19, + "h": 20 }, "frame": { - "x": 234, - "y": 238, - "w": 22, - "h": 19 + "x": 368, + "y": 208, + "w": 19, + "h": 20 } }, { - "filename": "upgrade", + "filename": "zoom_lens", "rotated": false, "trimmed": true, "sourceSize": { @@ -5899,19 +6025,19 @@ }, "spriteSourceSize": { "x": 5, - "y": 7, - "w": 22, - "h": 19 + "y": 6, + "w": 21, + "h": 21 }, "frame": { - "x": 256, - "y": 238, - "w": 22, - "h": 19 + "x": 219, + "y": 235, + "w": 21, + "h": 21 } }, { - "filename": "burn_drive", + "filename": "upgrade", "rotated": false, "trimmed": true, "sourceSize": { @@ -5919,20 +6045,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 + "x": 5, + "y": 7, + "w": 22, + "h": 19 }, "frame": { - "x": 278, - "y": 238, - "w": 23, - "h": 17 + "x": 240, + "y": 235, + "w": 22, + "h": 19 } }, { - "filename": "chill_drive", + "filename": "douse_drive", "rotated": false, "trimmed": true, "sourceSize": { @@ -5946,14 +6072,14 @@ "h": 17 }, "frame": { - "x": 301, - "y": 238, + "x": 262, + "y": 235, "w": 23, "h": 17 } }, { - "filename": "soothe_bell", + "filename": "big_mushroom", "rotated": false, "trimmed": true, "sourceSize": { @@ -5961,20 +6087,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 22 + "x": 6, + "y": 6, + "w": 19, + "h": 19 }, "frame": { - "x": 366, - "y": 196, - "w": 17, - "h": 22 + "x": 285, + "y": 235, + "w": 19, + "h": 19 } }, { - "filename": "big_nugget", + "filename": "gb", "rotated": false, "trimmed": true, "sourceSize": { @@ -5988,14 +6114,14 @@ "h": 20 }, "frame": { - "x": 383, - "y": 194, + "x": 304, + "y": 233, "w": 20, "h": 20 } }, { - "filename": "douse_drive", + "filename": "soothe_bell", "rotated": false, "trimmed": true, "sourceSize": { @@ -6003,20 +6129,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 + "x": 8, + "y": 5, + "w": 17, + "h": 22 }, "frame": { - "x": 403, - "y": 195, - "w": 23, - "h": 17 + "x": 223, + "y": 256, + "w": 17, + "h": 22 } }, { - "filename": "shock_drive", + "filename": "magnet", "rotated": false, "trimmed": true, "sourceSize": { @@ -6024,20 +6150,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 + "x": 6, + "y": 6, + "w": 20, + "h": 20 }, "frame": { - "x": 403, - "y": 212, - "w": 23, - "h": 17 + "x": 240, + "y": 254, + "w": 20, + "h": 20 } }, { - "filename": "blue_orb", + "filename": "candy_jar", "rotated": false, "trimmed": true, "sourceSize": { @@ -6047,18 +6173,18 @@ "spriteSourceSize": { "x": 6, "y": 6, - "w": 20, + "w": 19, "h": 20 }, "frame": { - "x": 383, - "y": 214, - "w": 20, + "x": 390, + "y": 108, + "w": 19, "h": 20 } }, { - "filename": "apicot_berry", + "filename": "golden_egg", "rotated": false, "trimmed": true, "sourceSize": { @@ -6066,20 +6192,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 7, "y": 6, - "w": 19, + "w": 17, "h": 20 }, "frame": { - "x": 364, - "y": 218, - "w": 19, + "x": 409, + "y": 106, + "w": 17, "h": 20 } }, { - "filename": "wise_glasses", + "filename": "spell_tag", "rotated": false, "trimmed": true, "sourceSize": { @@ -6087,20 +6213,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 + "x": 7, + "y": 6, + "w": 19, + "h": 21 }, "frame": { - "x": 403, - "y": 229, - "w": 23, - "h": 17 + "x": 382, + "y": 128, + "w": 19, + "h": 21 } }, { - "filename": "everstone", + "filename": "lucky_egg", "rotated": false, "trimmed": true, "sourceSize": { @@ -6108,20 +6234,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 17 + "x": 7, + "y": 6, + "w": 17, + "h": 20 }, "frame": { - "x": 383, - "y": 234, - "w": 20, - "h": 17 + "x": 409, + "y": 126, + "w": 17, + "h": 20 } }, { - "filename": "big_mushroom", + "filename": "hard_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6132,17 +6258,17 @@ "x": 6, "y": 6, "w": 19, - "h": 19 + "h": 20 }, "frame": { - "x": 324, - "y": 238, + "x": 383, + "y": 149, "w": 19, - "h": 19 + "h": 20 } }, { - "filename": "metal_alloy", + "filename": "masterpiece_teacup", "rotated": false, "trimmed": true, "sourceSize": { @@ -6150,20 +6276,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, "y": 7, "w": 21, - "h": 19 + "h": 18 }, "frame": { - "x": 343, - "y": 236, + "x": 383, + "y": 169, "w": 21, - "h": 19 + "h": 18 } }, { - "filename": "candy_jar", + "filename": "mb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6173,18 +6299,18 @@ "spriteSourceSize": { "x": 6, "y": 6, - "w": 19, + "w": 20, "h": 20 }, "frame": { - "x": 364, - "y": 238, - "w": 19, + "x": 385, + "y": 187, + "w": 20, "h": 20 } }, { - "filename": "gb", + "filename": "pb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6198,14 +6324,14 @@ "h": 20 }, "frame": { - "x": 383, - "y": 251, + "x": 387, + "y": 207, "w": 20, "h": 20 } }, { - "filename": "magnet", + "filename": "metal_alloy", "rotated": false, "trimmed": true, "sourceSize": { @@ -6214,19 +6340,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 6, - "w": 20, - "h": 20 + "y": 7, + "w": 21, + "h": 19 }, "frame": { - "x": 403, - "y": 246, - "w": 20, - "h": 20 + "x": 405, + "y": 146, + "w": 21, + "h": 19 } }, { - "filename": "masterpiece_teacup", + "filename": "old_gateau", "rotated": false, "trimmed": true, "sourceSize": { @@ -6234,20 +6360,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 7, + "x": 6, + "y": 8, "w": 21, "h": 18 }, "frame": { - "x": 212, - "y": 257, + "x": 405, + "y": 165, "w": 21, "h": 18 } }, { - "filename": "old_gateau", + "filename": "sharp_meteorite", "rotated": false, "trimmed": true, "sourceSize": { @@ -6261,14 +6387,14 @@ "h": 18 }, "frame": { - "x": 233, - "y": 257, + "x": 405, + "y": 183, "w": 21, "h": 18 } }, { - "filename": "sharp_meteorite", + "filename": "miracle_seed", "rotated": false, "trimmed": true, "sourceSize": { @@ -6277,19 +6403,40 @@ }, "spriteSourceSize": { "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 407, + "y": 201, + "w": 19, + "h": 19 + } + }, + { + "filename": "shock_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, "y": 8, - "w": 21, - "h": 18 + "w": 23, + "h": 17 }, "frame": { - "x": 254, - "y": 257, - "w": 21, - "h": 18 + "x": 346, + "y": 228, + "w": 23, + "h": 17 } }, { - "filename": "hard_stone", + "filename": "dark_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6297,20 +6444,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 + "x": 7, + "y": 7, + "w": 18, + "h": 18 }, "frame": { - "x": 193, - "y": 262, - "w": 19, - "h": 20 + "x": 369, + "y": 228, + "w": 18, + "h": 18 } }, { - "filename": "mb", + "filename": "lum_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -6319,19 +6466,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 6, + "y": 7, "w": 20, - "h": 20 + "h": 19 }, "frame": { - "x": 190, - "y": 282, + "x": 387, + "y": 227, "w": 20, - "h": 20 + "h": 19 } }, { - "filename": "golden_egg", + "filename": "razor_fang", "rotated": false, "trimmed": true, "sourceSize": { @@ -6341,13 +6488,13 @@ "spriteSourceSize": { "x": 7, "y": 6, - "w": 17, + "w": 18, "h": 20 }, "frame": { - "x": 193, - "y": 302, - "w": 17, + "x": 407, + "y": 220, + "w": 18, "h": 20 } }, @@ -6366,14 +6513,14 @@ "h": 18 }, "frame": { - "x": 212, - "y": 275, + "x": 325, + "y": 232, "w": 21, "h": 18 } }, { - "filename": "lum_berry", + "filename": "wise_glasses", "rotated": false, "trimmed": true, "sourceSize": { @@ -6381,20 +6528,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 + "x": 4, + "y": 8, + "w": 23, + "h": 17 }, "frame": { - "x": 233, - "y": 275, - "w": 20, - "h": 19 + "x": 346, + "y": 245, + "w": 23, + "h": 17 } }, { - "filename": "pb", + "filename": "everstone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6403,19 +6550,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 6, + "y": 8, "w": 20, - "h": 20 + "h": 17 }, "frame": { - "x": 253, - "y": 275, + "x": 369, + "y": 246, "w": 20, - "h": 20 + "h": 17 } }, { - "filename": "pb_gold", + "filename": "flame_orb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6423,41 +6570,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 + "x": 7, + "y": 7, + "w": 18, + "h": 18 }, "frame": { - "x": 210, - "y": 293, - "w": 20, - "h": 20 + "x": 389, + "y": 246, + "w": 18, + "h": 18 } }, { - "filename": "power_herb", + "filename": "oval_stone", "rotated": false, "trimmed": true, "sourceSize": { - "w": 24, - "h": 24 + "w": 32, + "h": 32 }, "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 20, + "x": 7, + "y": 7, + "w": 18, "h": 19 }, "frame": { - "x": 230, - "y": 294, - "w": 20, + "x": 407, + "y": 240, + "w": 18, "h": 19 } }, { - "filename": "razor_claw", + "filename": "mega_bracelet", "rotated": false, "trimmed": true, "sourceSize": { @@ -6466,19 +6613,19 @@ }, "spriteSourceSize": { "x": 6, - "y": 7, + "y": 8, "w": 20, - "h": 19 + "h": 16 }, "frame": { - "x": 250, - "y": 295, + "x": 240, + "y": 274, "w": 20, - "h": 19 + "h": 16 } }, { - "filename": "mega_bracelet", + "filename": "prism_scale", "rotated": false, "trimmed": true, "sourceSize": { @@ -6486,20 +6633,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 9, "y": 8, - "w": 20, + "w": 15, + "h": 15 + }, + "frame": { + "x": 231, + "y": 290, + "w": 15, + "h": 15 + } + }, + { + "filename": "abomasite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, "h": 16 }, "frame": { - "x": 210, - "y": 313, - "w": 20, + "x": 246, + "y": 290, + "w": 16, "h": 16 } }, { - "filename": "rb", + "filename": "pb_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -6513,14 +6681,14 @@ "h": 20 }, "frame": { - "x": 230, - "y": 313, + "x": 237, + "y": 306, "w": 20, "h": 20 } }, { - "filename": "smooth_meteorite", + "filename": "rb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6528,20 +6696,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 6, "y": 6, "w": 20, "h": 20 }, "frame": { - "x": 250, - "y": 314, + "x": 243, + "y": 326, "w": 20, "h": 20 } }, { - "filename": "strange_ball", + "filename": "smooth_meteorite", "rotated": false, "trimmed": true, "sourceSize": { @@ -6549,20 +6717,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 7, "y": 6, "w": 20, "h": 20 }, "frame": { - "x": 201, - "y": 329, + "x": 245, + "y": 346, "w": 20, "h": 20 } }, { - "filename": "ub", + "filename": "strange_ball", "rotated": false, "trimmed": true, "sourceSize": { @@ -6576,14 +6744,14 @@ "h": 20 }, "frame": { - "x": 201, - "y": 349, + "x": 247, + "y": 366, "w": 20, "h": 20 } }, { - "filename": "razor_fang", + "filename": "ub", "rotated": false, "trimmed": true, "sourceSize": { @@ -6591,20 +6759,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 6, "y": 6, - "w": 18, + "w": 20, "h": 20 }, "frame": { - "x": 203, - "y": 369, - "w": 18, + "x": 257, + "y": 306, + "w": 20, "h": 20 } }, { - "filename": "white_herb", + "filename": "power_herb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6618,14 +6786,14 @@ "h": 19 }, "frame": { - "x": 221, - "y": 333, + "x": 263, + "y": 326, "w": 20, "h": 19 } }, { - "filename": "miracle_seed", + "filename": "razor_claw", "rotated": false, "trimmed": true, "sourceSize": { @@ -6635,39 +6803,39 @@ "spriteSourceSize": { "x": 6, "y": 7, - "w": 19, + "w": 20, "h": 19 }, "frame": { - "x": 221, - "y": 352, - "w": 19, + "x": 265, + "y": 345, + "w": 20, "h": 19 } }, { - "filename": "wl_ability_urge", + "filename": "white_herb", "rotated": false, "trimmed": true, "sourceSize": { - "w": 32, - "h": 32 + "w": 24, + "h": 24 }, "spriteSourceSize": { - "x": 6, - "y": 8, + "x": 2, + "y": 3, "w": 20, - "h": 18 + "h": 19 }, "frame": { - "x": 221, - "y": 371, + "x": 267, + "y": 364, "w": 20, - "h": 18 + "h": 19 } }, { - "filename": "wl_antidote", + "filename": "light_ball", "rotated": false, "trimmed": true, "sourceSize": { @@ -6675,20 +6843,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, + "x": 7, + "y": 7, + "w": 18, "h": 18 }, "frame": { - "x": 241, - "y": 334, - "w": 20, + "x": 251, + "y": 386, + "w": 18, "h": 18 } }, { - "filename": "oval_stone", + "filename": "light_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6699,17 +6867,17 @@ "x": 7, "y": 7, "w": 18, - "h": 19 + "h": 18 }, "frame": { - "x": 240, - "y": 352, + "x": 269, + "y": 383, "w": 18, - "h": 19 + "h": 18 } }, { - "filename": "dark_stone", + "filename": "toxic_orb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6723,56 +6891,14 @@ "h": 18 }, "frame": { - "x": 241, - "y": 371, + "x": 251, + "y": 404, "w": 18, "h": 18 } }, { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 203, - "y": 389, - "w": 15, - "h": 11 - } - }, - { - "filename": "lucky_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 205, - "y": 400, - "w": 17, - "h": 20 - } - }, - { - "filename": "flame_orb", + "filename": "wl_ability_urge", "rotated": false, "trimmed": true, "sourceSize": { @@ -6780,20 +6906,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, + "x": 6, + "y": 8, + "w": 20, "h": 18 }, "frame": { - "x": 261, - "y": 334, - "w": 18, + "x": 269, + "y": 401, + "w": 20, "h": 18 } }, { - "filename": "wl_awakening", + "filename": "relic_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -6801,20 +6927,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 + "x": 7, + "y": 9, + "w": 17, + "h": 16 }, "frame": { - "x": 258, - "y": 352, - "w": 20, - "h": 18 + "x": 407, + "y": 259, + "w": 17, + "h": 16 } }, { - "filename": "wl_burn_heal", + "filename": "wl_antidote", "rotated": false, "trimmed": true, "sourceSize": { @@ -6828,14 +6954,14 @@ "h": 18 }, "frame": { - "x": 259, - "y": 370, + "x": 324, + "y": 250, "w": 20, "h": 18 } }, { - "filename": "wl_custom_spliced", + "filename": "wl_awakening", "rotated": false, "trimmed": true, "sourceSize": { @@ -6849,14 +6975,14 @@ "h": 18 }, "frame": { - "x": 222, - "y": 389, + "x": 304, + "y": 253, "w": 20, "h": 18 } }, { - "filename": "light_ball", + "filename": "wl_burn_heal", "rotated": false, "trimmed": true, "sourceSize": { @@ -6864,20 +6990,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, + "x": 6, + "y": 8, + "w": 20, "h": 18 }, "frame": { - "x": 242, - "y": 389, - "w": 18, + "x": 344, + "y": 262, + "w": 20, "h": 18 } }, { - "filename": "wl_custom_thief", + "filename": "wl_custom_spliced", "rotated": false, "trimmed": true, "sourceSize": { @@ -6891,14 +7017,14 @@ "h": 18 }, "frame": { - "x": 260, - "y": 388, + "x": 324, + "y": 268, "w": 20, "h": 18 } }, { - "filename": "wl_elixir", + "filename": "wl_custom_thief", "rotated": false, "trimmed": true, "sourceSize": { @@ -6912,14 +7038,14 @@ "h": 18 }, "frame": { - "x": 222, - "y": 407, + "x": 364, + "y": 263, "w": 20, "h": 18 } }, { - "filename": "light_stone", + "filename": "wl_elixir", "rotated": false, "trimmed": true, "sourceSize": { @@ -6927,15 +7053,15 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, + "x": 6, + "y": 8, + "w": 20, "h": 18 }, "frame": { - "x": 242, - "y": 407, - "w": 18, + "x": 384, + "y": 264, + "w": 20, "h": 18 } }, @@ -6954,8 +7080,8 @@ "h": 18 }, "frame": { - "x": 260, - "y": 406, + "x": 344, + "y": 280, "w": 20, "h": 18 } @@ -6975,8 +7101,8 @@ "h": 18 }, "frame": { - "x": 403, - "y": 266, + "x": 364, + "y": 281, "w": 20, "h": 18 } @@ -6996,8 +7122,8 @@ "h": 18 }, "frame": { - "x": 343, - "y": 255, + "x": 384, + "y": 282, "w": 20, "h": 18 } @@ -7017,8 +7143,8 @@ "h": 18 }, "frame": { - "x": 363, - "y": 258, + "x": 404, + "y": 275, "w": 20, "h": 18 } @@ -7038,8 +7164,8 @@ "h": 18 }, "frame": { - "x": 383, - "y": 271, + "x": 404, + "y": 293, "w": 20, "h": 18 } @@ -7059,8 +7185,8 @@ "h": 18 }, "frame": { - "x": 403, - "y": 284, + "x": 262, + "y": 252, "w": 20, "h": 18 } @@ -7080,8 +7206,8 @@ "h": 18 }, "frame": { - "x": 278, - "y": 255, + "x": 260, + "y": 270, "w": 20, "h": 18 } @@ -7101,8 +7227,8 @@ "h": 18 }, "frame": { - "x": 298, - "y": 255, + "x": 262, + "y": 288, "w": 20, "h": 18 } @@ -7122,14 +7248,14 @@ "h": 18 }, "frame": { - "x": 318, - "y": 257, + "x": 282, + "y": 254, "w": 20, "h": 18 } }, { - "filename": "mystery_egg", + "filename": "absolite", "rotated": false, "trimmed": true, "sourceSize": { @@ -7140,34 +7266,13 @@ "x": 8, "y": 8, "w": 16, - "h": 18 + "h": 16 }, "frame": { - "x": 270, - "y": 295, + "x": 280, + "y": 272, "w": 16, - "h": 18 - } - }, - { - "filename": "toxic_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 270, - "y": 313, - "w": 18, - "h": 18 + "h": 16 } }, { @@ -7185,8 +7290,8 @@ "h": 18 }, "frame": { - "x": 279, - "y": 331, + "x": 282, + "y": 288, "w": 20, "h": 18 } @@ -7206,8 +7311,8 @@ "h": 18 }, "frame": { - "x": 279, - "y": 349, + "x": 277, + "y": 306, "w": 20, "h": 18 } @@ -7227,8 +7332,8 @@ "h": 18 }, "frame": { - "x": 279, - "y": 367, + "x": 283, + "y": 324, "w": 20, "h": 18 } @@ -7248,8 +7353,8 @@ "h": 18 }, "frame": { - "x": 280, - "y": 385, + "x": 285, + "y": 342, "w": 20, "h": 18 } @@ -7269,8 +7374,8 @@ "h": 18 }, "frame": { - "x": 280, - "y": 403, + "x": 287, + "y": 360, "w": 20, "h": 18 } @@ -7290,8 +7395,8 @@ "h": 18 }, "frame": { - "x": 273, - "y": 275, + "x": 287, + "y": 378, "w": 20, "h": 18 } @@ -7311,8 +7416,8 @@ "h": 18 }, "frame": { - "x": 293, - "y": 273, + "x": 289, + "y": 396, "w": 20, "h": 18 } @@ -7332,75 +7437,12 @@ "h": 18 }, "frame": { - "x": 313, - "y": 275, + "x": 297, + "y": 306, "w": 20, "h": 18 } }, - { - "filename": "abomasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 286, - "y": 293, - "w": 16, - "h": 16 - } - }, - { - "filename": "absolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 288, - "y": 309, - "w": 16, - "h": 16 - } - }, - { - "filename": "relic_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 9, - "w": 17, - "h": 16 - }, - "frame": { - "x": 302, - "y": 293, - "w": 17, - "h": 16 - } - }, { "filename": "aerodactylite", "rotated": false, @@ -7416,8 +7458,8 @@ "h": 16 }, "frame": { - "x": 304, - "y": 309, + "x": 303, + "y": 324, "w": 16, "h": 16 } @@ -7437,8 +7479,8 @@ "h": 16 }, "frame": { - "x": 319, - "y": 293, + "x": 296, + "y": 272, "w": 16, "h": 16 } @@ -7458,8 +7500,8 @@ "h": 16 }, "frame": { - "x": 320, - "y": 309, + "x": 305, + "y": 340, "w": 16, "h": 16 } @@ -7479,8 +7521,8 @@ "h": 16 }, "frame": { - "x": 299, - "y": 325, + "x": 302, + "y": 288, "w": 16, "h": 16 } @@ -7500,8 +7542,8 @@ "h": 16 }, "frame": { - "x": 299, - "y": 341, + "x": 307, + "y": 356, "w": 16, "h": 16 } @@ -7521,8 +7563,8 @@ "h": 16 }, "frame": { - "x": 315, - "y": 325, + "x": 307, + "y": 372, "w": 16, "h": 16 } @@ -7542,8 +7584,8 @@ "h": 16 }, "frame": { - "x": 299, - "y": 357, + "x": 318, + "y": 286, "w": 16, "h": 16 } @@ -7563,8 +7605,8 @@ "h": 16 }, "frame": { - "x": 315, - "y": 341, + "x": 309, + "y": 388, "w": 16, "h": 16 } @@ -7584,8 +7626,8 @@ "h": 16 }, "frame": { - "x": 315, - "y": 357, + "x": 309, + "y": 404, "w": 16, "h": 16 } @@ -7605,8 +7647,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 275, + "x": 318, + "y": 302, "w": 16, "h": 16 } @@ -7626,8 +7668,8 @@ "h": 16 }, "frame": { - "x": 335, - "y": 291, + "x": 319, + "y": 318, "w": 16, "h": 16 } @@ -7647,8 +7689,8 @@ "h": 16 }, "frame": { - "x": 336, - "y": 307, + "x": 321, + "y": 334, "w": 16, "h": 16 } @@ -7668,8 +7710,8 @@ "h": 16 }, "frame": { - "x": 331, - "y": 325, + "x": 323, + "y": 350, "w": 16, "h": 16 } @@ -7689,8 +7731,8 @@ "h": 16 }, "frame": { - "x": 331, - "y": 341, + "x": 323, + "y": 366, "w": 16, "h": 16 } @@ -7710,8 +7752,8 @@ "h": 16 }, "frame": { - "x": 331, - "y": 357, + "x": 325, + "y": 382, "w": 16, "h": 16 } @@ -7731,8 +7773,8 @@ "h": 16 }, "frame": { - "x": 300, - "y": 373, + "x": 325, + "y": 398, "w": 16, "h": 16 } @@ -7752,8 +7794,8 @@ "h": 16 }, "frame": { - "x": 300, - "y": 389, + "x": 334, + "y": 298, "w": 16, "h": 16 } @@ -7773,8 +7815,8 @@ "h": 16 }, "frame": { - "x": 316, - "y": 373, + "x": 335, + "y": 314, "w": 16, "h": 16 } @@ -7794,8 +7836,8 @@ "h": 16 }, "frame": { - "x": 300, - "y": 405, + "x": 337, + "y": 330, "w": 16, "h": 16 } @@ -7815,8 +7857,8 @@ "h": 16 }, "frame": { - "x": 316, - "y": 389, + "x": 339, + "y": 346, "w": 16, "h": 16 } @@ -7836,8 +7878,8 @@ "h": 16 }, "frame": { - "x": 316, - "y": 405, + "x": 339, + "y": 362, "w": 16, "h": 16 } @@ -7857,8 +7899,8 @@ "h": 16 }, "frame": { - "x": 332, - "y": 373, + "x": 341, + "y": 378, "w": 16, "h": 16 } @@ -7878,8 +7920,8 @@ "h": 16 }, "frame": { - "x": 332, - "y": 389, + "x": 341, + "y": 394, "w": 16, "h": 16 } @@ -7899,8 +7941,8 @@ "h": 16 }, "frame": { - "x": 332, - "y": 405, + "x": 341, + "y": 410, "w": 16, "h": 16 } @@ -7920,8 +7962,8 @@ "h": 16 }, "frame": { - "x": 347, - "y": 323, + "x": 351, + "y": 311, "w": 16, "h": 16 } @@ -7941,8 +7983,8 @@ "h": 16 }, "frame": { - "x": 347, - "y": 339, + "x": 353, + "y": 327, "w": 16, "h": 16 } @@ -7962,8 +8004,8 @@ "h": 16 }, "frame": { - "x": 347, - "y": 355, + "x": 355, + "y": 343, "w": 16, "h": 16 } @@ -7983,8 +8025,8 @@ "h": 16 }, "frame": { - "x": 348, - "y": 371, + "x": 355, + "y": 359, "w": 16, "h": 16 } @@ -8004,8 +8046,8 @@ "h": 16 }, "frame": { - "x": 348, - "y": 387, + "x": 357, + "y": 375, "w": 16, "h": 16 } @@ -8025,33 +8067,12 @@ "h": 16 }, "frame": { - "x": 348, - "y": 403, + "x": 357, + "y": 391, "w": 16, "h": 16 } }, - { - "filename": "prism_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 349, - "y": 276, - "w": 15, - "h": 15 - } - }, { "filename": "metagrossite", "rotated": false, @@ -8067,8 +8088,8 @@ "h": 16 }, "frame": { - "x": 364, - "y": 276, + "x": 357, + "y": 407, "w": 16, "h": 16 } @@ -8088,8 +8109,8 @@ "h": 16 }, "frame": { - "x": 364, - "y": 292, + "x": 367, + "y": 299, "w": 16, "h": 16 } @@ -8109,8 +8130,8 @@ "h": 16 }, "frame": { - "x": 380, - "y": 289, + "x": 383, + "y": 300, "w": 16, "h": 16 } @@ -8130,8 +8151,8 @@ "h": 16 }, "frame": { - "x": 380, - "y": 305, + "x": 399, + "y": 311, "w": 16, "h": 16 } @@ -8151,8 +8172,8 @@ "h": 16 }, "frame": { - "x": 364, - "y": 308, + "x": 369, + "y": 327, "w": 16, "h": 16 } @@ -8172,8 +8193,8 @@ "h": 16 }, "frame": { - "x": 363, - "y": 324, + "x": 371, + "y": 343, "w": 16, "h": 16 } @@ -8193,8 +8214,8 @@ "h": 16 }, "frame": { - "x": 363, - "y": 340, + "x": 371, + "y": 359, "w": 16, "h": 16 } @@ -8214,8 +8235,8 @@ "h": 16 }, "frame": { - "x": 396, - "y": 302, + "x": 373, + "y": 375, "w": 16, "h": 16 } @@ -8235,8 +8256,8 @@ "h": 16 }, "frame": { - "x": 380, - "y": 321, + "x": 373, + "y": 391, "w": 16, "h": 16 } @@ -8256,8 +8277,8 @@ "h": 16 }, "frame": { - "x": 396, - "y": 318, + "x": 373, + "y": 407, "w": 16, "h": 16 } @@ -8277,8 +8298,8 @@ "h": 16 }, "frame": { - "x": 379, - "y": 337, + "x": 385, + "y": 327, "w": 16, "h": 16 } @@ -8298,8 +8319,8 @@ "h": 16 }, "frame": { - "x": 396, - "y": 334, + "x": 387, + "y": 343, "w": 16, "h": 16 } @@ -8319,8 +8340,8 @@ "h": 16 }, "frame": { - "x": 379, - "y": 353, + "x": 387, + "y": 359, "w": 16, "h": 16 } @@ -8340,8 +8361,8 @@ "h": 16 }, "frame": { - "x": 395, - "y": 350, + "x": 401, + "y": 327, "w": 16, "h": 16 } @@ -8361,8 +8382,8 @@ "h": 16 }, "frame": { - "x": 395, - "y": 366, + "x": 389, + "y": 375, "w": 16, "h": 16 } @@ -8382,8 +8403,8 @@ "h": 16 }, "frame": { - "x": 364, - "y": 382, + "x": 389, + "y": 391, "w": 16, "h": 16 } @@ -8403,8 +8424,8 @@ "h": 16 }, "frame": { - "x": 364, - "y": 398, + "x": 389, + "y": 407, "w": 16, "h": 16 } @@ -8424,8 +8445,8 @@ "h": 16 }, "frame": { - "x": 380, - "y": 382, + "x": 403, + "y": 343, "w": 16, "h": 16 } @@ -8445,8 +8466,8 @@ "h": 16 }, "frame": { - "x": 380, - "y": 398, + "x": 403, + "y": 359, "w": 16, "h": 16 } @@ -8457,6 +8478,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:06a43a858ac0838c2d5400a7c8e124da:6c9201d0b6d07fc299c0fa41c226a22d:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:c428fceb82c2d05d4e09932aca0e849e:b87abcdcfeb40d09d19eb74093035e71:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 2bf9a012139f43291a28c0b4b5d5d0668894c046..3f69fbd7406666783a2424e36ec5477a66c7cfe7 100644 GIT binary patch literal 57721 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�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

`e4+Q}cJdkFIy!&WYh4>OJW34HZ_u+vxSM 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 Wnu+y)Bnvk(;Ag07rcNSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fgp&Q^6;tJBEps?lLUdtfI ztR=<&|KFQ4$FTe86vHgbIZM_YJ$u!wIq2%WXYby9^NLEkloPcCsDZI0$S;_|;n|He zAZMqii(`n!`Q(HJ(gGqP4iAmBG_4nLaI}i<=2)QNQ7ls8a_Q)bI3COxK0yIEOM!w*d{$P>KtR{g+%3bA$WQHy?Gb!20k*;-&L)HlhTRU+kK zn}G+H!8|LC3>^+}2CZp(df&t>NODt8dCnB-Fo)ax>oSH5J12?t7BmJ6x1N?2e}ALH z;K`dLaqr1@If5ls`SS$t?Pb;Ekzj2+=gO<<)~U<%g3)`o2Qvfn3azU%aXMQ27VC&m5I4xzLm1jW12haT#b zi>(R)OVcHy6l};&t%*v(w;1_d1Y8yC3;LiIuJ;Akjcp{wmi#a|?IdL^WXC#x%G=b^ zy3-AAr-`BVeTev@7wkmZs1qk;AAR@{hzC7Hqz?iSVd~ppjr$4=@pvvMO07ZT*<2x; zCI}L5XYvOc_c>8Rs@}-jFUE2?kEj||YqVH27()9fx{DF6b+829FBV>d`k&4Pih5P9 z#9OFq=IZH%00LQhkdBr8?v4L5feiRJ(!taeUm$_o& z>$LIu{90q#-R3c0vbPEiQ8#-4+AGLk(4O@gJ%*@4uMO#kch@gh2FYA~|8ZYPe;X5Q z4(9oK4ph&E+S_5j2Mz{r3GNrP*vad%E=Lr?%MI3NYU!=fOx=r9@_K!(&$mwKO}-q8 v0QK|pGbnt0CTewkd%JYUx5wFc#;^DXWB@PGf)ELR00000NkvXXu0mjf`Px}e literal 0 HcmV?d00001 diff --git a/public/images/trainer/victor.json b/public/images/trainer/victor.json new file mode 100644 index 000000000000..5afa97045672 --- /dev/null +++ b/public/images/trainer/victor.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "victor.png", + "format": "RGBA8888", + "size": { + "w": 55, + "h": 53 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 12, + "y": 27, + "w": 55, + "h": 53 + }, + "frame": { + "x": 0, + "y": 0, + "w": 55, + "h": 53 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:64eff0f697754cdf9552b46342c9292a:611e0e2cacbd90c1229ce5443b2414f0:0cc0f5a2c1b2eedb46dd8318e8feb1d8$" + } +} diff --git a/public/images/trainer/victor.png b/public/images/trainer/victor.png new file mode 100644 index 0000000000000000000000000000000000000000..3ffddea24bbfff8db534d97e5eacf7f37a17334e GIT binary patch literal 794 zcmV+#1LgdQP){}NCzF}o^`2AEdmr|O;pN5Q5 z;Bid-WvZZbI~PuM>_Rv*iBVkIfQK#wTfYOVkxeKgf5+j%Ot?#_T4QA+L>#*?_tv4C zs#RW1SCC2fZa9B1-|3pfa4m5bzC^v4sHyu~5rX=eBio2U|sdW?8 zK&V>cdZVN=4yW2yLB*YIo2X=7r^8KV_`ShE<{UD(>fc~nQ{GMln^YkNf%ZB?OtK`eJi7F_}RqvChd%{uC1UO)oFjU?2JysrcH3!Ziv{~e@N>Fx zC+H5T?Fpulb7EzEbA(to6VJgo(aRAtDz?kXU2(R2)TDDSSLG4WW<>@E4{mbRER*!BP)ubcy zhMiqIsaNjEt_OM!cXDZWPkg=`*n>b1;jGgd?s;%P&M%xwydGR*>U;1wI$k|NSy`)@ ze(UXC8}xQ`RyF;3gZ$18nJC*3&JKC$5Utb_au6(pFekbX{dscB(jY6VJxrv!Tb8%4 z8lPqM(*}QVoJe=BMHZ&dHM-wdv{7qhm1Z4+=z$NuH@dhIW9$M+cAztrK&x7%O0 Ye+BL%B0!s5t^fc407*qoM6N<$g0)v~<^TWy literal 0 HcmV?d00001 diff --git a/public/images/trainer/victoria.json b/public/images/trainer/victoria.json new file mode 100644 index 000000000000..7917113621a4 --- /dev/null +++ b/public/images/trainer/victoria.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "victoria.png", + "format": "RGBA8888", + "size": { + "w": 52, + "h": 54 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 14, + "y": 26, + "w": 52, + "h": 54 + }, + "frame": { + "x": 0, + "y": 0, + "w": 52, + "h": 54 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:4dafeae3674d63b12cc4d8044f67b5a3:7834687d784c31169256927f419c7958:cf0eb39e0a3f2e42f23ca29747d73c40$" + } +} diff --git a/public/images/trainer/victoria.png b/public/images/trainer/victoria.png new file mode 100644 index 0000000000000000000000000000000000000000..e2874f266adfd1a8df0bc7dc52043f35114cf485 GIT binary patch literal 813 zcmV+|1JeA7P)0000mP)t-s00000 z0022!N=i97Vw6gAN-29vT8lwBq;oO7dt$}S)!te;-lTix)k^=>z5oCJIms`400001 zbW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0+vZcK~zY`t(NO{q#zK4EqiDn zp!5E3yM05=o*guM!Vfc^_)$gEmMqKfj3nd7Op&1&WISY0d;orZ2$@t|1$zV~@%A5- zje(^*irFY~Y~LNm9O0d9QAE^t9X;I`OP)PyNskJIamG!LA|#oIwVS%3Z-}*708JI#< zYQ{vIpuTc2Ge{ZP8I}^5P?j)i?Uv$r^VC{4BIi3ulP>xc1a+s_Ewm8OZ5+;&y2~TA z)ep=yOM`>w3M_a+4AC+1;uy`cXnGdDEs7!glxrVvzz9Lwh%r zw&kdKqswI9WHeIrs*J83n+)HlA#^pPw<_ae2Ic%l-kM=~!}Y0)SR|LtB%SbnE3_H5 zMHyDW{hSmf$)I?r@%8m(Jv2BBZ-v}UFdkf%Q@XeC#mJh}Aq{W(MxRO)8ARF-qY)g7 zl8chhoahh=s2~qUe_WttCC^cvdARf7DwO{r^^9`Ch8-tL_(Pl`DJgqOT8lwBi-U`lIa<9jF}-_Y#Y#cmqz5oCJfe_@)00001 zbW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0%l1>K~zY`t(NPytsn@6o1(2K zt@nT1186tPYK(pOv3D!KCI|*~-CxY%E9hN^FEBap;lH3tI#2!;CBcOAUr6IVpfJ)z z@g}KeB;g&*y5C6uBD(pW(mW^sKspPMrr9h#_;*Ak@y*4iClW+%TFLa_9tq@Duul)! z@5Q5=dvD;9=qk0=Ba>LXM1UpXf-U2?q2yIff=p9I_G#|Nar~{QdQP^V)YqXA@cS*; zZ{!rE+Ic@CNlZHlMW_A(Y6(wZ7XZy@x}G}dsoCyw2psz~0UT;p&+ZP!7(?WRnS)-| zs9RGUl#C(o_OB$HBw@Z44aN+^uofQjiZ?`;Wf^3>z({>#gvi`d(-A|1T65HpweQlz z0X&U_o%D~xlQQD8+k5Zd$Bc|3|1vx`z<(sMJwnaNRg*2zojhK?ka%|Q4$I}bktk=& za)4|y=Ia(o+p3ifU#o&?+4-d=^B-Hg*8=X{(H12_!-DxyV?e70ys4!I*u`dRe>DBAQECg%qlfVs-& zXxHsLPWi`}V+8Jjdd+dojQBOFSIrMG_*FDg&wn2#B16o3#+yOm!0XDCvL*Kh2=A|w z^Iq@5C(3&?*w+Z7KXMY)RpbOvuPXz4;V=B0wXAfJ18|ES4?x%WbI!s63F!ksu@P!~ z1xOTH6s-s#rRWzutMdpr!YIz5l)^IbFV6Z^UxW>-<%vM)kxl;sMCdB-se#$Al%_OT zS|TR{lj|pNj9qkFQW{4+_qJ80$hTfXBEU%FrW!(`-BB2kU)m22Y!jhv!Lm4`MSks9 zgbGYsirYkDNz@nI16i`f$vp^MED5#`wkb?GZ#f4niSxS1=mCW=h7br)jjN1anHew| zV9&8(yK!O!&GbGa54S*VE)1;}q0XpH|FmcdOnpF@rpfe8gzF|cOl<%-c<{@h7Qm$r zw5H^Mbw_>HEjb12K(qq1fG=$8p5v@%h|}L@RJ} zTE(>4CX{#P!-aVQC*!h%Pztrs*Hw)Qo^!cX*(_6~_*OFQ4cE>h{r9sNdrcB1aoPPu>Ow00000NkvXXu0mjfrgJ)i literal 0 HcmV?d00001 diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 2b1c4ba719ed..d35c73c2a0dd 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -14,7 +14,7 @@ import { Arena, ArenaBase } from "./field/arena"; import { GameData } from "./system/game-data"; import { addTextObject, getTextColor, TextStyle } from "./ui/text"; import { allMoves } from "./data/move"; -import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue, ModifierPoolType, PokemonHeldItemModifierType } from "./modifier/modifier-type"; +import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue, ModifierPoolType } from "./modifier/modifier-type"; import AbilityBar from "./ui/ability-bar"; import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr } from "./data/ability"; import Battle, { BattleType, FixedBattleConfig } from "./battle"; @@ -67,12 +67,13 @@ import { UiTheme } from "#enums/ui-theme"; import { TimedEventManager } from "#app/timed-event-manager.js"; import i18next from "i18next"; import { TrainerType } from "#enums/trainer-type"; -import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter"; +import MysteryEncounter from "./data/mystery-encounters/mystery-encounter"; import { allMysteryEncounters, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters"; import { MysteryEncounterData } from "#app/data/mystery-encounters/mystery-encounter-data"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; +import HeldModifierConfig from "#app/interfaces/held-modifier-config"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -223,7 +224,7 @@ export default class BattleScene extends SceneBase { public pokemonInfoContainer: PokemonInfoContainer; private party: PlayerPokemon[]; public mysteryEncounterData: MysteryEncounterData = new MysteryEncounterData(null); - public lastMysteryEncounter: IMysteryEncounter; + public lastMysteryEncounter: MysteryEncounter; /** Combined Biome and Wave count text */ private biomeWaveText: Phaser.GameObjects.Text; private moneyText: Phaser.GameObjects.Text; @@ -1036,7 +1037,7 @@ export default class BattleScene extends SceneBase { } } - newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: IMysteryEncounter): Battle { + newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: MysteryEncounter): Battle { const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1); let newDouble: boolean; @@ -1066,6 +1067,10 @@ export default class BattleScene extends SceneBase { newBattleType = battleType; } + if (waveIndex === 64) { + newBattleType = BattleType.TRAINER; + } + if (newBattleType === BattleType.TRAINER) { const trainerType = this.arena.randomTrainerType(newWaveIndex); let doubleTrainer = false; @@ -2423,7 +2428,7 @@ export default class BattleScene extends SceneBase { }); } - generateEnemyModifiers(customHeldModifiers?: PokemonHeldItemModifierType[][]): Promise { + generateEnemyModifiers(heldModifiersConfigs?: HeldModifierConfig[][]): Promise { return new Promise(resolve => { if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { return resolve(); @@ -2445,8 +2450,16 @@ export default class BattleScene extends SceneBase { } party.every((enemyPokemon: EnemyPokemon, i: integer) => { - if (customHeldModifiers && i < customHeldModifiers.length && customHeldModifiers[i] && customHeldModifiers[i].length > 0) { - customHeldModifiers[i].forEach(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this)); + if (heldModifiersConfigs && i < heldModifiersConfigs.length && heldModifiersConfigs[i] && heldModifiersConfigs[i].length > 0) { + heldModifiersConfigs[i].forEach(mt => { + const stackCount = mt.stackCount ?? 1; + // const isTransferable = mt.isTransferable ?? true; + const modifier = mt.modifierType.newModifier(enemyPokemon); + modifier.stackCount = stackCount; + // TODO: set isTransferable + // modifier.setIsTransferable(isTransferable); + this.addEnemyModifier(modifier, false, true); + }); return true; } @@ -2702,9 +2715,9 @@ export default class BattleScene extends SceneBase { * @param override - used to load session encounter when restarting game, etc. * @returns */ - getMysteryEncounter(override: IMysteryEncounter): IMysteryEncounter { + getMysteryEncounter(override: MysteryEncounter): MysteryEncounter { // Loading override or session encounter - let encounter: IMysteryEncounter; + let encounter: MysteryEncounter; if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) { encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE]; } else { @@ -2726,7 +2739,7 @@ export default class BattleScene extends SceneBase { } if (encounter) { - encounter = new IMysteryEncounter(encounter); + encounter = new MysteryEncounter(encounter); encounter.populateDialogueTokensFromRequirements(this); return encounter; } @@ -2755,7 +2768,7 @@ export default class BattleScene extends SceneBase { tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE; } - let availableEncounters: IMysteryEncounter[] = []; + let availableEncounters: MysteryEncounter[] = []; // New encounter will never be the same as the most recent encounter const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null; const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType) ?? []; @@ -2802,7 +2815,7 @@ export default class BattleScene extends SceneBase { } encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)]; // New encounter object to not dirty flags - encounter = new IMysteryEncounter(encounter); + encounter = new MysteryEncounter(encounter); encounter.populateDialogueTokensFromRequirements(this); return encounter; } diff --git a/src/battle.ts b/src/battle.ts index 7205b883eb99..bec0e4363a24 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -14,7 +14,7 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; import i18next from "#app/plugins/i18n"; -import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter"; +import MysteryEncounter from "./data/mystery-encounters/mystery-encounter"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; export enum BattleType { @@ -70,7 +70,7 @@ export default class Battle { public lastUsedPokeball: PokeballType; public playerFaints: number; // The amount of times pokemon on the players side have fainted public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted - public mysteryEncounter: IMysteryEncounter; + public mysteryEncounter: MysteryEncounter; private rngCounter: integer = 0; diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index 5d4bea542de3..d8659c15a564 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -735,6 +735,56 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], + [TrainerType.VICTOR]: [ + { + encounter: [ + "dialogue:winstrates_victor.encounter.1", + ], + victory: [ + "dialogue:winstrates_victor.victory.1" + ], + } + ], + [TrainerType.VICTORIA]: [ + { + encounter: [ + "dialogue:winstrates_victoria.encounter.1", + ], + victory: [ + "dialogue:winstrates_victoria.victory.1" + ], + } + ], + [TrainerType.VIVI]: [ + { + encounter: [ + "dialogue:winstrates_vivi.encounter.1", + ], + victory: [ + "dialogue:winstrates_vivi.victory.1" + ], + } + ], + [TrainerType.VICKY]: [ + { + encounter: [ + "dialogue:winstrates_vicky.encounter.1", + ], + victory: [ + "dialogue:winstrates_vicky.victory.1" + ], + } + ], + [TrainerType.VITO]: [ + { + encounter: [ + "dialogue:winstrates_vito.encounter.1", + ], + victory: [ + "dialogue:winstrates_vito.victory.1" + ], + } + ], [TrainerType.BROCK]: { encounter: [ "dialogue:brock.encounter.1", 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 9a69a85d7226..132c7e34e080 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -2,7 +2,7 @@ import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattl import { trainerConfigs, } from "#app/data/trainer-config"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { TrainerType } from "#enums/trainer-type"; import { Species } from "#enums/species"; @@ -22,10 +22,10 @@ const namespace = "mysteryEncounter:aTrainersTest"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/115 | GitHub Issue #115} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const ATrainersTestEncounter: IMysteryEncounter = +export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.A_TRAINERS_TEST) .withEncounterTier(MysteryEncounterTier.ROGUE) - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withSceneWaveRangeRequirement(100, 180) .withIntroSpriteConfigs([]) // These are set in onInit() .withIntroDialogue([ { @@ -139,13 +139,6 @@ export const ATrainersTestEncounter: IMysteryEncounter = // Spawn standard trainer battle with memory mushroom reward const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; - let eggTier; - if (randSeedInt(64) >= 54) { - eggTier = EggTier.MASTER; - } else { - eggTier = EggTier.ULTRA; - } - await transitionMysteryEncounterIntroVisuals(scene); const eggOptions: IEggOptions = { @@ -153,9 +146,9 @@ export const ATrainersTestEncounter: IMysteryEncounter = pulled: false, sourceType: EggSourceType.EVENT, eventEggTypeDescriptor: encounter.misc.trainerEggDescription, - tier: eggTier + tier: EggTier.ULTRA }; - encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.${eggTier === EggTier.ULTRA ? "epic" : "legendary"}`)); + encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.epic`)); setEncounterRewards(scene, { fillRemaining: true }, [eggOptions]); return initBattleWithEnemyConfig(scene, config); diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index 45645a6b17ff..500512b70c3b 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -1,10 +1,10 @@ -import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import Pokemon, { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import { BerryModifierType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { PersistentModifierRequirement } from "../mystery-encounter-requirements"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -21,6 +21,7 @@ import { BattlerIndex } from "#app/battle"; import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { TrainerSlot } from "#app/data/trainer-config"; import { PokeballType } from "#app/data/pokeball"; +import HeldModifierConfig from "#app/interfaces/held-modifier-config"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounter:absoluteAvarice"; @@ -30,7 +31,7 @@ const namespace = "mysteryEncounter:absoluteAvarice"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/58 | GitHub Issue #58} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const AbsoluteAvariceEncounter: IMysteryEncounter = +export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.ABSOLUTE_AVARICE) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) @@ -191,13 +192,13 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter = encounter.misc = { berryItemsMap }; // Generates copies of the stolen berries to put on the Greedent - const bossModifierTypes: PokemonHeldItemModifierType[] = []; + const bossModifierConfigs: HeldModifierConfig[] = []; berryItems.forEach(berryMod => { // Can't define stack count on a ModifierType, have to just create separate instances for each stack // Overflow berries will be "lost" on the boss, but it's un-catchable anyway for (let i = 0; i < berryMod.stackCount; i++) { - const modifierType = generateModifierTypeOption(scene, modifierTypes.BERRY, [berryMod.berryType]).type as PokemonHeldItemModifierType; - bossModifierTypes.push(modifierType); + const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType; + bossModifierConfigs.push({ modifierType }); } scene.removeModifier(berryMod); @@ -212,7 +213,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter = isBoss: true, bossSegments: 3, moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF], - modifierTypes: bossModifierTypes, + modifierConfigs: bossModifierConfigs, tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: (pokemon: Pokemon) => { queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`); @@ -243,7 +244,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter = const encounter = scene.currentBattle.mysteryEncounter; // Provides 1x Reviver Seed to each party member at end of battle - const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type; + const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED); const givePartyPokemonReviverSeeds = () => { const party = scene.getParty(); party.forEach(p => { @@ -296,7 +297,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter = Phaser.Math.RND.shuffle(berryTypesAsArray); const randBerryType = berryTypesAsArray.pop(); - const berryModType = generateModifierTypeOption(scene, modifierTypes.BERRY, [randBerryType]).type as BerryModifierType; + const berryModType = generateModifierType(scene, modifierTypes.BERRY, [randBerryType]) as BerryModifierType; applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType); } } 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 8eabbbd8d052..6dfa72129fbb 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 @@ -3,7 +3,7 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "../mystery-encounter-requirements"; import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; @@ -21,7 +21,7 @@ const namespace = "mysteryEncounter:offerYouCantRefuse"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/72 | GitHub Issue #72} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const AnOfferYouCantRefuseEncounter: IMysteryEncounter = +export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index 4f67905235ed..30c82a9dd9ee 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -1,7 +1,7 @@ import { BattleStat } from "#app/data/battle-stat"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { - EnemyPartyConfig, generateModifierTypeOption, + EnemyPartyConfig, generateModifierType, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards @@ -19,7 +19,7 @@ import { randSeedInt } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getPokemonNameWithAffix } from "#app/messages"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -40,7 +40,7 @@ const namespace = "mysteryEncounter:berriesAbound"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const BerriesAboundEncounter: IMysteryEncounter = +export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.BERRIES_ABOUND) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 @@ -315,7 +315,7 @@ export const BerriesAboundEncounter: IMysteryEncounter = async function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) { const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType; - const berry = generateModifierTypeOption(scene, modifierTypes.BERRY, [berryType]).type as BerryModifierType; + const berry = generateModifierType(scene, modifierTypes.BERRY, [berryType]) as BerryModifierType; const party = scene.getParty(); diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index c03508a5700b..147343bad319 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -1,11 +1,11 @@ -import { EnemyPartyConfig, generateModifierTypeOption, 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"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; @@ -56,7 +56,7 @@ const RANDOM_ABILITY_POOL = [ * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/69 | GitHub Issue #69} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const ClowningAroundEncounter: IMysteryEncounter = +export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.CLOWNING_AROUND) .withEncounterTier(MysteryEncounterTier.ULTRA) .withSceneWaveRangeRequirement(80, 180) @@ -128,8 +128,7 @@ export const ClowningAroundEncounter: IMysteryEncounter = }, { // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter species: getPokemonSpecies(Species.BLACEPHALON), - ability: ability, - mysteryEncounterData: new MysteryEncounterPokemonData(null, null, null, [randSeedInt(18), randSeedInt(18)]), + mysteryEncounterData: new MysteryEncounterPokemonData(null, ability, null, [randSeedInt(18), randSeedInt(18)]), isBoss: true, moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] }, @@ -483,9 +482,9 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem const newItemType = pool[randIndex]; let newMod; if (tier === "Berries") { - newMod = generateModifierTypeOption(scene, modifierTypes.BERRY, [newItemType[0]]).type as PokemonHeldItemModifierType; + newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType; } else { - newMod = generateModifierTypeOption(scene, newItemType[0]).type as PokemonHeldItemModifierType; + newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType; } applyModifierTypeToPlayerPokemon(scene, pokemon, newMod); // Decrement max stacks and remove from pool if at max diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 5b1279848809..3e87d8e3aa9b 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -3,7 +3,7 @@ import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -77,7 +77,7 @@ const SENSU_STYLE_BIOMES = [ * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/130 | GitHub Issue #130} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const DancingLessonsEncounter: IMysteryEncounter = +export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DANCING_LESSONS) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) diff --git a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts index fde28a2ab00c..1251cc9bf326 100644 --- a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts +++ b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts @@ -6,7 +6,7 @@ import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; import { modifierTypes } from "#app/modifier/modifier-type"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils"; import { getRandomPlayerPokemon, getRandomSpeciesByStarterTier } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; @@ -74,7 +74,7 @@ const excludedBosses = [ * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/61 | GitHub Issue #61} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const DarkDealEncounter: IMysteryEncounter = +export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DARK_DEAL) .withEncounterTier(MysteryEncounterTier.ROGUE) .withIntroSpriteConfigs([ diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index bcab1b4bd02c..18b6883b529e 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -1,10 +1,10 @@ -import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { generateModifierType, leaveEncounterWithoutBattle, selectPokemonForOption, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { CombinationPokemonRequirement, HeldItemRequirement, MoneyRequirement } from "../mystery-encounter-requirements"; import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -36,7 +36,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [ * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/57 | GitHub Issue #57} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const DelibirdyEncounter: IMysteryEncounter = +export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DELIBIRDY) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) @@ -113,7 +113,7 @@ export const DelibirdyEncounter: IMysteryEncounter = if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead - const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType; + 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); @@ -188,7 +188,7 @@ export const DelibirdyEncounter: IMysteryEncounter = if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead - const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType; + 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); @@ -201,7 +201,7 @@ export const DelibirdyEncounter: IMysteryEncounter = if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead - const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType; + 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); @@ -281,7 +281,7 @@ export const DelibirdyEncounter: IMysteryEncounter = if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead - const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType; + 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); 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 fa27c31c2738..9a11a2e8888b 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts @@ -7,7 +7,7 @@ import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { +import MysteryEncounter, { MysteryEncounterBuilder, } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -20,7 +20,7 @@ const namespace = "mysteryEncounter:departmentStoreSale"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/33 | GitHub Issue #33} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const DepartmentStoreSaleEncounter: IMysteryEncounter = +export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DEPARTMENT_STORE_SALE) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 100) diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 93e2d71aa1af..27322ea052b3 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -7,7 +7,7 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -19,7 +19,7 @@ const namespace = "mysteryEncounter:fieldTrip"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/17 | GitHub Issue #17} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const FieldTripEncounter: IMysteryEncounter = +export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index 5b4b582da016..533f9b93e792 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -3,7 +3,7 @@ import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig import { AttackTypeBoosterModifierType, modifierTypes, } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { TypeRequirement } from "../mystery-encounter-requirements"; import { Species } from "#enums/species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; @@ -36,7 +36,7 @@ const DAMAGE_PERCENTAGE: number = 20; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/88 | GitHub Issue #88} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const FieryFalloutEncounter: IMysteryEncounter = +export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIERY_FALLOUT) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(40, 180) 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 2f000742ea9a..5fc827a0c77c 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts @@ -17,7 +17,7 @@ import { } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MoveRequirement } from "../mystery-encounter-requirements"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -33,7 +33,7 @@ const namespace = "mysteryEncounter:fightOrFlight"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const FightOrFlightEncounter: IMysteryEncounter = +export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIGHT_OR_FLIGHT) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 diff --git a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts index 02f2393811a6..02f4f2f1cdc7 100644 --- a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts +++ b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts @@ -127,7 +127,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with * @param scene Battle scene * @param guidePokemon pokemon choosen as a guide */ -function handlePokemonGuidingYouPhase(scene: BattleScene) { +async function handlePokemonGuidingYouPhase(scene: BattleScene) { const laprasSpecies = getPokemonSpecies(Species.LAPRAS); const { mysteryEncounter } = scene.currentBattle; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index 368b18b11c00..f3738059b0b3 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -15,7 +15,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import BattleScene from "#app/battle-scene"; import * as Utils from "#app/utils"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; /** the i18n namespace for the encounter */ @@ -26,7 +26,7 @@ const namespace = "mysteryEncounter:mysteriousChallengers"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/41 | GitHub Issue #41} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const MysteriousChallengersEncounter: IMysteryEncounter = +export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 diff --git a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts index f0a96356eef1..1d965e38fa6e 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts @@ -5,7 +5,7 @@ import { ModifierTier } from "#app/modifier/modifier-tier"; import { randSeedInt } from "#app/utils.js"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -18,7 +18,7 @@ const namespace = "mysteryEncounter:mysteriousChest"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/32 | GitHub Issue #32} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const MysteriousChestEncounter: IMysteryEncounter = +export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHEST) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) // waves 2 to 180 @@ -116,9 +116,8 @@ export const MysteriousChestEncounter: IMysteryEncounter = scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender()); // Show which Pokemon was KOed, then leave encounter with no rewards // Does this synchronously so that game over doesn't happen over result message - await showEncounterText(scene, `${namespace}.option.1.bad`).then(() => { - leaveEncounterWithoutBattle(scene); - }); + await showEncounterText(scene, `${namespace}.option.1.bad`); + leaveEncounterWithoutBattle(scene); } }) .build() diff --git a/src/data/mystery-encounters/encounters/part-timer-encounter.ts b/src/data/mystery-encounters/encounters/part-timer-encounter.ts index a7f53976bbbf..94318ac69267 100644 --- a/src/data/mystery-encounters/encounters/part-timer-encounter.ts +++ b/src/data/mystery-encounters/encounters/part-timer-encounter.ts @@ -2,7 +2,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals, updatePlayerMoney } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MoveRequirement } from "../mystery-encounter-requirements"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -20,7 +20,7 @@ const namespace = "mysteryEncounter:partTimer"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/82 | GitHub Issue #82} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const PartTimerEncounter: IMysteryEncounter = +export const PartTimerEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.PART_TIMER) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index e110d43fc507..56e3bb2852b4 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -1,7 +1,7 @@ import { initSubsequentOptionSelect, leaveEncounterWithoutBattle, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import MysteryEncounterOption, { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { TrainerSlot } from "#app/data/trainer-config"; import { ScanIvsPhase, SummonPhase } from "#app/phases"; @@ -17,7 +17,6 @@ import { getEncounterText, showEncounterText } from "#app/data/mystery-encounter import { getPokemonNameWithAffix } from "#app/messages"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:safariZone"; @@ -29,7 +28,7 @@ const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768]; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/39 | GitHub Issue #39} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const SafariZoneEncounter: IMysteryEncounter = +export const SafariZoneEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SAFARI_ZONE) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) @@ -66,7 +65,7 @@ export const SafariZoneEncounter: IMysteryEncounter = .withOptionPhase(async (scene: BattleScene) => { // Start safari encounter const encounter = scene.currentBattle.mysteryEncounter; - encounter.encounterMode = MysteryEncounterMode.CONTINUOUS_ENCOUNTER; + encounter.continuousEncounter = true; encounter.misc = { safariPokemonRemaining: 3 }; @@ -104,7 +103,7 @@ export const SafariZoneEncounter: IMysteryEncounter = /** * SAFARI ZONE MINIGAME OPTIONS * - * Catch and flee rate **stages** are calculated in the same way stat changes are (they range from -6/+6) + * Catch and flee rate stages are calculated in the same way stat changes are (they range from -6/+6) * https://bulbapedia.bulbagarden.net/wiki/Catch_rate#Great_Marsh_and_Johto_Safari_Zone * * Catch Rate calculation: @@ -130,21 +129,23 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [ }) .withOptionPhase(async (scene: BattleScene) => { // Throw a ball option - const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon; + const encounter = scene.currentBattle.mysteryEncounter; + const pokemon = encounter.misc.pokemon; const catchResult = await throwPokeball(scene, pokemon); if (catchResult) { // You caught pokemon // Check how many safari pokemon left - if (scene.currentBattle.mysteryEncounter.misc.safariPokemonRemaining > 0) { + if (encounter.misc.safariPokemonRemaining > 0) { await summonSafariPokemon(scene); initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: 0, hideDescription: true }); } else { // End safari mode + encounter.continuousEncounter = false; leaveEncounterWithoutBattle(scene, true); } } else { - // Pokemon failed to catch, end turn + // Pokemon catch failed, end turn await doEndTurn(scene, 0); } return true; @@ -217,14 +218,16 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [ }) .withOptionPhase(async (scene: BattleScene) => { // Flee option - const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon; + const encounter = scene.currentBattle.mysteryEncounter; + const pokemon = encounter.misc.pokemon; await doPlayerFlee(scene, pokemon); // Check how many safari pokemon left - if (scene.currentBattle.mysteryEncounter.misc.safariPokemonRemaining > 0) { + if (encounter.misc.safariPokemonRemaining > 0) { await summonSafariPokemon(scene); initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: 3, hideDescription: true }); } else { // End safari mode + encounter.continuousEncounter = false; leaveEncounterWithoutBattle(scene, true); } return true; @@ -487,6 +490,7 @@ async function doEndTurn(scene: BattleScene, cursorIndex: number) { initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true }); } else { // End safari mode + encounter.continuousEncounter = false; leaveEncounterWithoutBattle(scene, true); } } else { 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 86a8a614ba64..6ce4474206d3 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -1,4 +1,4 @@ -import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { generateModifierType, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { StatusEffect } from "#app/data/status-effect"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; @@ -6,7 +6,7 @@ import { randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MoneyRequirement } from "../mystery-encounter-requirements"; import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -22,7 +22,7 @@ const namespace = "mysteryEncounter:shadyVitaminDealer"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/34 | GitHub Issue #34} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const ShadyVitaminDealerEncounter: IMysteryEncounter = +export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SHADY_VITAMIN_DEALER) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) @@ -79,8 +79,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney); // Calculate modifiers and dialogue tokens const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, + generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER), + generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER), ]; encounter.setDialogueToken("boost1", modifiers[0].name); encounter.setDialogueToken("boost2", modifiers[1].name); @@ -162,8 +162,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter = updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney); // Calculate modifiers and dialogue tokens const modifiers = [ - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, - generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, + generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER), + generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER), ]; encounter.setDialogueToken("boost1", modifiers[0].name); encounter.setDialogueToken("boost2", modifiers[1].name); diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index 6d56f2cde460..4f24ca699363 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -4,7 +4,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; import { StatusEffect } from "#app/data/status-effect"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MoveRequirement } from "../mystery-encounter-requirements"; import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, } from "../utils/encounter-phase-utils"; @@ -25,7 +25,7 @@ const namespace = "mysteryEncounter:slumberingSnorlax"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/103 | GitHub Issue #103} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const SlumberingSnorlaxEncounter: IMysteryEncounter = +export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SLUMBERING_SNORLAX) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 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 80b7354b7479..e1c7ff8a7f6f 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -2,7 +2,7 @@ import { leaveEncounterWithoutBattle, transitionMysteryEncounterIntroVisuals, up import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MoneyRequirement } from "../mystery-encounter-requirements"; import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; @@ -25,7 +25,7 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 6; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/36 | GitHub Issue #36} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const ThePokemonSalesmanEncounter: IMysteryEncounter = +export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_POKEMON_SALESMAN) .withEncounterTier(MysteryEncounterTier.ULTRA) .withSceneWaveRangeRequirement(10, 180) 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 36ac31f80462..fd67d2a02347 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -1,8 +1,8 @@ -import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { EnemyPartyConfig, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes, PokemonHeldItemModifierType, } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Species } from "#enums/species"; import { Nature } from "#app/data/nature"; @@ -26,7 +26,7 @@ const namespace = "mysteryEncounter:theStrongStuff"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/54 | GitHub Issue #54} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const TheStrongStuffEncounter: IMysteryEncounter = +export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_STRONG_STUFF) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 @@ -74,12 +74,20 @@ export const TheStrongStuffEncounter: IMysteryEncounter = mysteryEncounterData: new MysteryEncounterPokemonData(1.5), nature: Nature.BOLD, moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER], - modifierTypes: [ - generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type as PokemonHeldItemModifierType, - generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.APICOT]).type as PokemonHeldItemModifierType, - generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.GANLON]).type as PokemonHeldItemModifierType, - generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.LUM]).type as PokemonHeldItemModifierType, - generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.LUM]).type as PokemonHeldItemModifierType + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, + stackCount: 2 + } ], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: (pokemon: Pokemon) => { diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts new file mode 100644 index 000000000000..434cabb4a429 --- /dev/null +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -0,0 +1,488 @@ +import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import BattleScene from "#app/battle-scene"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; +import { TrainerType } from "#enums/trainer-type"; +import { Species } from "#enums/species"; +import { Abilities } from "#enums/abilities"; +import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { Moves } from "#enums/moves"; +import { Nature } from "#enums/nature"; +import { Type } from "#app/data/type"; +import { BerryType } from "#enums/berry-type"; +import { Stat } from "#enums/stat"; +import { PartyHealPhase, ReturnPhase, ShowTrainerPhase } from "#app/phases"; +import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; +import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability"; +import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; + +/** the i18n namespace for the encounter */ +const namespace = "mysteryEncounter:theWinstrateChallenge"; + +/** + * The Winstrate Challenge encounter. + * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/136 | GitHub Issue #136} + * @see For biome requirements check {@linkcode mysteryEncountersByBiome} + */ +export const TheWinstrateChallengeEncounter: MysteryEncounter = + MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_WINSTRATE_CHALLENGE) + .withEncounterTier(MysteryEncounterTier.ROGUE) + .withSceneWaveRangeRequirement(80, 180) + .withIntroSpriteConfigs([ + { + spriteKey: "vito", + fileRoot: "trainer", + hasShadow: false, + x: 16, + y: -4 + }, + { + spriteKey: "vivi", + fileRoot: "trainer", + hasShadow: false, + x: -14, + y: -4 + }, + { + spriteKey: "victor", + fileRoot: "trainer", + hasShadow: true, + x: -32 + }, + { + spriteKey: "victoria", + fileRoot: "trainer", + hasShadow: true, + x: 40, + }, + { + spriteKey: "vicky", + fileRoot: "trainer", + hasShadow: true, + x: 3, + y: 5, + yShadow: 5 + }, + ]) + .withIntroDialogue([ + { + text: `${namespace}.intro`, + }, + { + speaker: `${namespace}.speaker`, + text: `${namespace}.intro_dialogue`, + }, + ]) + .withAutoHideIntroVisuals(false) + .withOnInit((scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + + // Loaded back to front for pop() operations + encounter.enemyPartyConfigs.push(getVitoTrainerConfig(scene)); + encounter.enemyPartyConfigs.push(getVickyTrainerConfig(scene)); + encounter.enemyPartyConfigs.push(getViviTrainerConfig(scene)); + encounter.enemyPartyConfigs.push(getVictoriaTrainerConfig(scene)); + encounter.enemyPartyConfigs.push(getVictorTrainerConfig(scene)); + + return true; + }) + .withTitle(`${namespace}.title`) + .withDescription(`${namespace}.description`) + .withQuery(`${namespace}.query`) + .withSimpleOption( + { + buttonLabel: `${namespace}.option.1.label`, + buttonTooltip: `${namespace}.option.1.tooltip`, + selected: [ + { + speaker: "trainerNames:victor", + text: `${namespace}.option.1.selected`, + }, + ], + }, + async (scene: BattleScene) => { + // Spawn 5 trainer battles back to back with Macho Brace in rewards + // scene.currentBattle.mysteryEncounter.continuousEncounter = true; + scene.currentBattle.mysteryEncounter.doContinueEncounter = (scene: BattleScene) => { + return endTrainerBattleAndShowDialogue(scene); + }; + await transitionMysteryEncounterIntroVisuals(scene, true, false); + await spawnNextTrainerOrEndEncounter(scene); + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}.option.2.label`, + buttonTooltip: `${namespace}.option.2.tooltip`, + selected: [ + { + speaker: `${namespace}:speaker`, + text: `${namespace}.option.2.selected`, + }, + ], + }, + async (scene: BattleScene) => { + // Refuse the challenge, they full heal the party and give the player a Rarer Candy + scene.unshiftPhase(new PartyHealPhase(scene, true)); + setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], fillRemaining: false }); + leaveEncounterWithoutBattle(scene); + } + ) + .build(); + +async function spawnNextTrainerOrEndEncounter(scene: BattleScene) { + const encounter = scene.currentBattle.mysteryEncounter; + const nextConfig = encounter.enemyPartyConfigs.pop(); + if (!nextConfig) { + 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; + leaveEncounterWithoutBattle(scene); + } else { + await initBattleWithEnemyConfig(scene, nextConfig); + } +} + +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); + } + }); + await spawnNextTrainerOrEndEncounter(scene); + resolve(); // Wait for all dialogue/post battle stuff to complete before resolving + } else { + scene.arena.resetArenaEffects(); + const playerField = scene.getPlayerField(); + playerField.forEach((_, p) => scene.unshiftPhase(new ReturnPhase(scene, p))); + + for (const pokemon of scene.getParty()) { + // Only trigger form change when Eiscue is in Noice form + // Hardcoded Eiscue for now in case it is fused with another pokemon + if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) { + scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger); + } + + pokemon.resetBattleData(); + applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); + } + + scene.unshiftPhase(new ShowTrainerPhase(scene)); + // Hide the trainer and init next battle + const trainer = scene.currentBattle.trainer; + // 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(); + } + }); + } + }); +} + +function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig { + return { + trainerType: TrainerType.VICTOR, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.SWELLOW), + isBoss: false, + abilityIndex: 0, // Guts + nature: Nature.ADAMANT, + moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.FOCUS_BAND) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + }, + ] + }, + { + species: getPokemonSpecies(Species.OBSTAGOON), + isBoss: false, + abilityIndex: 1, // Guts + nature: Nature.ADAMANT, + moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + } + ] + } + ] + }; +} + +function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig { + return { + trainerType: TrainerType.VICTORIA, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.ROSERADE), + isBoss: false, + abilityIndex: 0, // Natural Cure + nature: Nature.CALM, + moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + } + ] + }, + { + species: getPokemonSpecies(Species.GARDEVOIR), + isBoss: false, + formIndex: 1, + nature: Nature.TIMID, + moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.PSYCHIC]) as PokemonHeldItemModifierType, + stackCount: 1, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FAIRY]) as PokemonHeldItemModifierType, + stackCount: 1, + isTransferable: false + } + ] + } + ] + }; +} + +function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig { + return { + trainerType: TrainerType.VIVI, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.SEAKING), + isBoss: false, + abilityIndex: 3, // Lightning Rod + nature: Nature.ADAMANT, + moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, + stackCount: 4, + isTransferable: false + } + ] + }, + { + species: getPokemonSpecies(Species.BRELOOM), + isBoss: false, + abilityIndex: 1, // Poison Heal + nature: Nature.JOLLY, + moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, + stackCount: 4, + isTransferable: false + }, + { + modifierType: generateModifierType(scene, modifierTypes.TOXIC_ORB) as PokemonHeldItemModifierType, + isTransferable: false + } + ] + }, + { + species: getPokemonSpecies(Species.CAMERUPT), + isBoss: false, + formIndex: 1, + nature: Nature.CALM, + moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, + stackCount: 3, + isTransferable: false + }, + ] + } + ] + }; +} + +function getVickyTrainerConfig(scene: BattleScene): EnemyPartyConfig { + return { + trainerType: TrainerType.VICKY, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.MEDICHAM), + isBoss: false, + formIndex: 1, + nature: Nature.IMPISH, + moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType, + isTransferable: false + } + ] + } + ] + }; +} + +function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig { + return { + trainerType: TrainerType.VITO, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.HISUI_ELECTRODE), + isBoss: false, + abilityIndex: 0, // Soundproof + nature: Nature.MODEST, + moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.SPD]) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + } + ] + }, + { + species: getPokemonSpecies(Species.SWALOT), + isBoss: false, + abilityIndex: 2, // Gluttony + nature: Nature.QUIET, + moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.STARF]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SALAC]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LANSAT]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LIECHI]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.PETAYA]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, + stackCount: 2, + }, + { + modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LEPPA]) as PokemonHeldItemModifierType, + stackCount: 2, + } + ] + }, + { + species: getPokemonSpecies(Species.DODRIO), + isBoss: false, + abilityIndex: 2, // Tangled Feet + nature: Nature.JOLLY, + moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + } + ] + }, + { + species: getPokemonSpecies(Species.ALAKAZAM), + isBoss: false, + formIndex: 1, + nature: Nature.BOLD, + moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + }, + ] + }, + { + species: getPokemonSpecies(Species.DARMANITAN), + isBoss: false, + abilityIndex: 0, // Sheer Force + nature: Nature.IMPISH, + moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE], + modifierConfigs: [ + { + modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, + stackCount: 2, + isTransferable: false + }, + ] + } + ] + }; +} diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index c6cd93068b94..9e89fd24d1df 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -14,7 +14,7 @@ import { randSeedShuffle } from "#app/utils"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; 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"; @@ -28,7 +28,7 @@ const namespace = "mysteryEncounter:trainingSession"; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/43 | GitHub Issue #43} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const TrainingSessionEncounter: IMysteryEncounter = +export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TRAINING_SESSION) .withEncounterTier(MysteryEncounterTier.ULTRA) .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 @@ -444,7 +444,7 @@ function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon,segment formIndex: playerPokemon.formIndex, level: playerPokemon.level, dataSource: data, - modifierTypes: modifierTypes, + modifierConfigs: modifierTypes, }, ], }; 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 0ea9d42ca63e..4f21f70c0056 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -1,8 +1,8 @@ -import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { ModifierRewardPhase } from "#app/phases"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -28,7 +28,7 @@ const SOUND_EFFECT_WAIT_TIME = 700; * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/74 | GitHub Issue #74} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const TrashToTreasureEncounter: IMysteryEncounter = +export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TRASH_TO_TREASURE) .withEncounterTier(MysteryEncounterTier.ULTRA) .withSceneWaveRangeRequirement(10, 180) @@ -147,8 +147,8 @@ export const TrashToTreasureEncounter: IMysteryEncounter = .build(); async function tryApplyDigRewardItems(scene: BattleScene) { - const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType; - const leftovers = generateModifierTypeOption(scene, modifierTypes.LEFTOVERS).type as PokemonHeldItemModifierType; + const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType; + const leftovers = generateModifierType(scene, modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType; const party = scene.getParty(); diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index d556a3b0c829..e76f0af1dd65 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -2,7 +2,7 @@ import { Type } from "#app/data/type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; -import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; +import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { leaveEncounterWithoutBattle, setEncounterRewards, } from "../utils/encounter-phase-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -79,7 +79,7 @@ const excludedPokemon = [ * @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/137 | GitHub Issue #137} * @see For biome requirements check {@linkcode mysteryEncountersByBiome} */ -export const WeirdDreamEncounter: IMysteryEncounter = +export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.WEIRD_DREAM) .withEncounterTier(MysteryEncounterTier.ROGUE) .withIntroSpriteConfigs([ @@ -202,11 +202,6 @@ export const WeirdDreamEncounter: IMysteryEncounter = return true; } ) - .withOutroDialogue([ - { - text: `${namespace}.outro` - } - ]) .build(); interface PokemonTransformation { diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index b1b47cef8ef8..6d2bd27f88bf 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -6,25 +6,16 @@ import BattleScene from "#app/battle-scene"; import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import * as Utils from "#app/utils"; import { StatusEffect } from "../status-effect"; -import MysteryEncounterDialogue, { - OptionTextDisplay -} from "./mystery-encounter-dialogue"; +import MysteryEncounterDialogue, { OptionTextDisplay } from "./mystery-encounter-dialogue"; import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option"; -import { - EncounterPokemonRequirement, - EncounterSceneRequirement, - HealthRatioRequirement, - PartySizeRequirement, - StatusEffectRequirement, - WaveRangeRequirement -} from "./mystery-encounter-requirements"; +import { EncounterPokemonRequirement, EncounterSceneRequirement, HealthRatioRequirement, PartySizeRequirement, StatusEffectRequirement, WaveRangeRequirement } from "./mystery-encounter-requirements"; import { BattlerIndex } from "#app/battle"; import { EncounterAnim } from "#app/data/battle-anims"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -export interface StartOfBattleEffect { +export interface EncounterStartOfBattleEffect { sourcePokemon?: Pokemon; sourceBattlerIndex?: BattlerIndex; targets: BattlerIndex[]; @@ -33,7 +24,7 @@ export interface StartOfBattleEffect { followUp?: boolean; } -export default interface IMysteryEncounter { +export default interface MysteryEncounter { /** * Required params */ @@ -44,13 +35,44 @@ export default interface IMysteryEncounter { * Optional params */ encounterTier?: MysteryEncounterTier; + /** + * Custom battle animations that are configured for encounter effects and visuals + * Specify here so that assets are loaded on initialization of encounter + */ encounterAnimations?: EncounterAnim[]; + /** + * If true, hides "A Wild X Appeared" etc. messages + * Default true + */ hideBattleIntroMessage?: boolean; + /** + * If true, when an option is selected the field visuals will fade out automatically + * Default false + */ autoHideIntroVisuals?: boolean; + /** + * Intro visuals on the field will slide in from the right instead of the left + * Default false + */ enterIntroVisualsFromRight?: boolean; + /** + * If true, allows catching a wild pokemon during the encounter + * Default false + */ catchAllowed?: boolean; + /** + * If true, encounter will continuously run through multiple battles/puzzles/etc. instead of going to next wave + * MUST EVENTUALLY BE DISABLED TO CONTINUE TO NEXT WAVE + * Default false + */ + continuousEncounter?: boolean; + /** + * Maximum number of times the encounter can be seen per run + * Rogue tier encounters default to 1, others default to 3 + */ maxAllowedEncounters?: number; + /** * Event callback functions */ @@ -62,6 +84,8 @@ export default interface IMysteryEncounter { doEncounterExp?: (scene: BattleScene) => boolean; /** Will provide the player a rewards shop for that wave */ doEncounterRewards?: (scene: BattleScene) => boolean; + /** Will execute callback during VictoryPhase of a continuousEncounter */ + doContinueEncounter?: (scene: BattleScene) => Promise; /** * Requirements @@ -90,6 +114,7 @@ export default interface IMysteryEncounter { /** * Data used for setting up/initializing enemy party in battles * Can store multiple configs so that one can be chosen based on option selected + * Should usually be defined in `onInit()` or `onPreOptionPhase()` */ enemyPartyConfigs?: EnemyPartyConfig[]; /** @@ -131,7 +156,7 @@ export default interface IMysteryEncounter { /** * Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases */ - startOfBattleEffects?: StartOfBattleEffect[]; + startOfBattleEffects?: EncounterStartOfBattleEffect[]; /** * Can be set higher or lower based on the type of battle or exp gained for an option/encounter * Defaults to 1 @@ -149,14 +174,14 @@ export default interface IMysteryEncounter { * These objects will be saved as part of session data any time the player is on a floor with an encounter * Unless you know what you're doing, you should use MysteryEncounterBuilder to create an instance for this class */ -export default class IMysteryEncounter implements IMysteryEncounter { +export default class MysteryEncounter implements MysteryEncounter { /** * Used for keeping RNG consistent on session resets, but increments when cycling through multiple "Encounters" on the same wave * You should only need to interact via getter/update methods */ private seedOffset?: any; - constructor(encounter: IMysteryEncounter) { + constructor(encounter: MysteryEncounter) { if (!isNullOrUndefined(encounter)) { Object.assign(this, encounter); } @@ -170,6 +195,7 @@ export default class IMysteryEncounter implements IMysteryEncounter { this.hideBattleIntroMessage = this.hideBattleIntroMessage ?? false; this.autoHideIntroVisuals = this.autoHideIntroVisuals ?? true; this.enterIntroVisualsFromRight = this.enterIntroVisualsFromRight ?? false; + this.continuousEncounter = this.continuousEncounter ?? false; // Reset any dirty flags or encounter data this.startOfBattleEffectsComplete = false; @@ -238,11 +264,11 @@ export default class IMysteryEncounter implements IMysteryEncounter { } if (truePrimaryPool.length > 0) { - // always choose from the non-overlapping pokemon first + // Always choose from the non-overlapping pokemon first this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)]; return true; } else { - // if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool + // If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool if (overlap.length > 1 || (this.secondaryPokemon.length - overlap.length >= 1)) { // is this working? this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)]; @@ -371,7 +397,7 @@ export default class IMysteryEncounter implements IMysteryEncounter { } /** - * If an encounter uses {@link MysteryEncounterMode.CONTINUOUS_ENCOUNTER}, + * If an encounter uses {@link MysteryEncounterMode.continuousEncounter}, * should rely on this value for seed offset instead of wave index. * * This offset is incremented for each new {@link MysteryEncounterPhase} that occurs, @@ -396,7 +422,11 @@ export default class IMysteryEncounter implements IMysteryEncounter { } } -export class MysteryEncounterBuilder implements Partial { +/** + * 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; options?: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [null, null]; spriteConfigs?: MysteryEncounterSpriteConfig[]; @@ -418,7 +448,7 @@ export class MysteryEncounterBuilder implements Partial { hideBattleIntroMessage?: boolean; hideIntroVisuals?: boolean; enterIntroVisualsFromRight?: boolean; - enemyPartyConfigs?: EnemyPartyConfig[] = []; + continuousEncounter?: boolean; /** * REQUIRED @@ -429,7 +459,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: encounterType }); } @@ -442,7 +472,7 @@ export class MysteryEncounterBuilder implements Partial { * @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance * @returns */ - withOption(option: MysteryEncounterOption): this & Pick { + 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) { @@ -464,7 +494,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(new MysteryEncounterOptionBuilder().withOptionMode(MysteryEncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build()); } @@ -478,7 +508,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(new MysteryEncounterOptionBuilder() .withOptionMode(MysteryEncounterOptionMode.DEFAULT) .withHasDexProgress(true) @@ -492,7 +522,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 }); } @@ -521,28 +551,38 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterTier * @returns */ - withEncounterTier(encounterTier: MysteryEncounterTier): this & Required> { + withEncounterTier(encounterTier: MysteryEncounterTier): this & Required> { return Object.assign(this, { encounterTier: encounterTier }); } /** * Defines any EncounterAnim animations that are intended to be used during the encounter - * EncounterAnims can be played at any point during an encounter or callback + * EncounterAnims are custom battle animations (think Ice Beam) that can be played at any point during an encounter or callback * They just need to be specified here so that resources are loaded on encounter init * @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 }); } + /** + * If true, encounter will continuously run through multiple battles/puzzles/etc. instead of going to next wave + * MUST EVENTUALLY BE DISABLED TO CONTINUE TO NEXT WAVE + * Default false + * @param continuousEncounter + */ + withContinuousEncounter(continuousEncounter: boolean): this & Required> { + return Object.assign(this, { continuousEncounter: continuousEncounter }); + } + /** * Sets the maximum number of times that an encounter can spawn in a given Classic run * @param maxAllowedEncounters * @returns */ - withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required> { + withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required> { return Object.assign(this, { maxAllowedEncounters: maxAllowedEncounters }); } @@ -553,7 +593,7 @@ 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."); } @@ -568,7 +608,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])); } @@ -580,7 +620,7 @@ export class MysteryEncounterBuilder implements Partial { * @param excludeFainted - if true, only counts unfainted mons * @returns */ - withScenePartySizeRequirement(min: number, max?: number, excludeFainted?: boolean): this & Required> { + withScenePartySizeRequirement(min: number, max?: number, excludeFainted?: boolean): this & Required> { return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min], excludeFainted)); } @@ -590,7 +630,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."); } @@ -607,7 +647,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)); } @@ -619,14 +659,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."); } @@ -646,7 +686,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 }); } @@ -660,7 +700,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 }); } @@ -671,7 +711,7 @@ 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> { + withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> { return Object.assign(this, { onInit: onInit }); } @@ -681,27 +721,17 @@ 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 }); } - /** - * Defines any enemies to use for a battle from the mystery encounter - * @param enemyPartyConfig - * @returns - */ - withEnemyPartyConfig(enemyPartyConfig: EnemyPartyConfig): this & Required> { - this.enemyPartyConfigs.push(enemyPartyConfig); - return Object.assign(this, { enemyPartyConfigs: this.enemyPartyConfigs }); - } - /** * Can set whether catching is allowed or not on the encounter * This flag can also be programmatically set inside option event functions or elsewhere * @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 }); } @@ -709,7 +739,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 }); } @@ -717,7 +747,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 }); } @@ -726,7 +756,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 }); } @@ -806,7 +836,7 @@ export class MysteryEncounterBuilder implements Partial { * * @returns */ - build(this: IMysteryEncounter): IMysteryEncounter { - return new IMysteryEncounter(this); + build(this: MysteryEncounter): MysteryEncounter { + return new MysteryEncounter(this); } } diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index f73673706ea1..44f4ecf24201 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -10,7 +10,7 @@ import { MysteriousChestEncounter } from "./encounters/mysterious-chest-encounte import { ShadyVitaminDealerEncounter } from "./encounters/shady-vitamin-dealer-encounter"; import { SlumberingSnorlaxEncounter } from "./encounters/slumbering-snorlax-encounter"; import { TrainingSessionEncounter } from "./encounters/training-session-encounter"; -import IMysteryEncounter from "./mystery-encounter"; +import MysteryEncounter from "./mystery-encounter"; import { SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter"; import { FieryFalloutEncounter } from "#app/data/mystery-encounters/encounters/fiery-fallout-encounter"; import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter"; @@ -25,6 +25,7 @@ import { ClowningAroundEncounter } from "#app/data/mystery-encounters/encounters import { PartTimerEncounter } from "#app/data/mystery-encounters/encounters/part-timer-encounter"; import { DancingLessonsEncounter } from "#app/data/mystery-encounters/encounters/dancing-lessons-encounter"; import { WeirdDreamEncounter } from "#app/data/mystery-encounters/encounters/weird-dream-encounter"; +import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-encounter"; // Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * ) / 256 export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1; @@ -132,7 +133,7 @@ export const CIVILIZATION_ENCOUNTER_BIOMES = [ Biome.ISLAND ]; -export const allMysteryEncounters: { [encounterType: number]: IMysteryEncounter } = {}; +export const allMysteryEncounters: { [encounterType: number]: MysteryEncounter } = {}; const extremeBiomeEncounters: MysteryEncounterType[] = []; @@ -147,6 +148,7 @@ const humanTransitableBiomeEncounters: MysteryEncounterType[] = [ MysteryEncounterType.SHADY_VITAMIN_DEALER, MysteryEncounterType.THE_POKEMON_SALESMAN, MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, + MysteryEncounterType.THE_WINSTRATE_CHALLENGE ]; const civilizationBiomeEncounters: MysteryEncounterType[] = [ @@ -270,6 +272,7 @@ export function initMysteryEncounters() { allMysteryEncounters[MysteryEncounterType.PART_TIMER] = PartTimerEncounter; allMysteryEncounters[MysteryEncounterType.DANCING_LESSONS] = DancingLessonsEncounter; allMysteryEncounters[MysteryEncounterType.WEIRD_DREAM] = WeirdDreamEncounter; + allMysteryEncounters[MysteryEncounterType.THE_WINSTRATE_CHALLENGE] = TheWinstrateChallengeEncounter; // Add extreme encounters to biome map extremeBiomeEncounters.forEach(encounter => { diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index a4be81a3e089..4d3d89b1abc0 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -3,9 +3,9 @@ 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"; import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import Pokemon, { FieldPosition, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; +import Pokemon, { FieldPosition, PlayerPokemon, PokemonMove, PokemonSummonData } from "#app/field/pokemon"; import { ExpBalanceModifier, ExpShareModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier } from "#app/modifier/modifier"; -import { CustomModifierSettings, ModifierPoolType, ModifierType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, PokemonHeldItemModifierType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; +import { CustomModifierSettings, ModifierPoolType, ModifierType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; import { BattleEndPhase, EggLapsePhase, ExpPhase, GameOverPhase, MovePhase, SelectModifierPhase, ShowPartyExpBarPhase, TrainerVictoryPhase } from "#app/phases"; import { MysteryEncounterBattlePhase, MysteryEncounterBattleStartCleanupPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; import PokemonData from "#app/system/pokemon-data"; @@ -30,8 +30,8 @@ import { TrainerConfig, trainerConfigs, TrainerSlot } from "#app/data/trainer-co import PokemonSpecies from "#app/data/pokemon-species"; import Overrides from "#app/overrides"; import { Egg, IEggOptions } from "#app/data/egg"; -import { Abilities } from "#enums/abilities"; import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data"; +import HeldModifierConfig from "#app/interfaces/held-modifier-config"; /** * Animates exclamation sprite over trainer's head at start of encounter @@ -67,18 +67,18 @@ export interface EnemyPokemonConfig { bossSegmentModifier?: number; // Additive to the determined segment number mysteryEncounterData?: MysteryEncounterPokemonData; formIndex?: number; + abilityIndex?: number; level?: number; gender?: Gender; passive?: boolean; moveSet?: Moves[]; nature?: Nature; ivs?: [integer, integer, integer, integer, integer, integer]; - ability?: Abilities; shiny?: boolean; /** Can set just the status, or pass a timer on the status turns */ status?: StatusEffect | [StatusEffect, number]; mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void; - modifierTypes?: PokemonHeldItemModifierType[]; + modifierConfigs?: HeldModifierConfig[]; tags?: BattlerTagType[]; dataSource?: PokemonData; } @@ -258,10 +258,13 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: } // Set summon data fields + if (!enemyPokemon.summonData) { + enemyPokemon.summonData = new PokemonSummonData(); + } // Set ability - if (!isNullOrUndefined(config.ability)) { - enemyPokemon.summonData.ability = config.ability; + if (!isNullOrUndefined(config.abilityIndex)) { + enemyPokemon.abilityIndex = config.abilityIndex; } // Set gender @@ -293,6 +296,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: enemyPokemon.initBattleInfo(); enemyPokemon.getBattleInfo().initInfo(enemyPokemon); + enemyPokemon.generateName(); } loadEnemyAssets.push(enemyPokemon.loadAssets()); @@ -315,8 +319,8 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: }); if (!loaded) { regenerateModifierPoolThresholds(scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); - const customModifiers = partyConfig?.pokemonConfigs?.map(config => config?.modifierTypes); - scene.generateEnemyModifiers(customModifiers); + const customModifierTypes = partyConfig?.pokemonConfigs?.map(config => config?.modifierConfigs); + scene.generateEnemyModifiers(customModifierTypes); } } @@ -363,7 +367,7 @@ export function updatePlayerMoney(scene: BattleScene, changeValue: number, playS * @param modifier * @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc. */ -export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption { +export function generateModifierType(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierType { const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier); let result: ModifierType = modifierTypes[modifierId]?.(); @@ -373,6 +377,17 @@ export function generateModifierTypeOption(scene: BattleScene, modifier: () => M .withTierFromPool(); result = result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result; + return result; +} + +/** + * Converts modifier bullshit to an actual item + * @param scene - Battle Scene + * @param modifier + * @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc. + */ +export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption { + const result = generateModifierType(scene, modifier, pregenArgs); return new ModifierTypeOption(result, 0); } @@ -644,14 +659,15 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase: // If in repeated encounter variant, do nothing // Variant must eventually be swapped in order to handle "true" end of the encounter - if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.CONTINUOUS_ENCOUNTER || doNotContinue) { + const encounter = scene.currentBattle.mysteryEncounter; + if (encounter.continuousEncounter || doNotContinue) { return; - } else if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.NO_BATTLE) { + } else if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) { scene.pushPhase(new EggLapsePhase(scene)); scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase)); - } else if (!scene.getEnemyParty().find(p => scene.currentBattle.mysteryEncounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) { + } else if (!scene.getEnemyParty().find(p => encounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) { scene.pushPhase(new BattleEndPhase(scene)); - if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { + if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { scene.pushPhase(new TrainerVictoryPhase(scene)); } if (scene.gameMode.isEndless || !scene.gameMode.isWaveFinal(scene.currentBattle.waveIndex)) { diff --git a/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts b/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts index 271cdaf391e0..9da36ee6846c 100644 --- a/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts +++ b/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts @@ -11,13 +11,13 @@ export enum TransformationScreenPosition { } /** - * Initiates an "evolution-like" animation to transform a pokemon (presumably from the player's party) into a new one, not necessarily an evolution species. + * Initiates an "evolution-like" animation to transform a previousPokemon (presumably from the player's party) into a new one, not necessarily an evolution species. * @param scene - * @param pokemon - * @param transformedPokemon + * @param previousPokemon + * @param transformPokemon * @param screenPosition */ -export function doPokemonTransformationSequence(scene: BattleScene, pokemon: PlayerPokemon, transformedPokemon: PlayerPokemon, screenPosition: TransformationScreenPosition) { +export function doPokemonTransformationSequence(scene: BattleScene, previousPokemon: PlayerPokemon, transformPokemon: PlayerPokemon, screenPosition: TransformationScreenPosition) { return new Promise(resolve => { const transformationContainer = scene.fieldUI.getByName("Dream Background") as Phaser.GameObjects.Container; const transformationBaseBg = scene.add.image(0, 0, "default_bg"); @@ -36,7 +36,7 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla const yOffset = screenPosition !== TransformationScreenPosition.CENTER ? -15 : 0; const getPokemonSprite = () => { - const ret = scene.addPokemonSprite(pokemon, transformationBaseBg.displayWidth / 2 + xOffset, transformationBaseBg.displayHeight / 2 + yOffset, "pkmn__sub"); + const ret = scene.addPokemonSprite(previousPokemon, transformationBaseBg.displayWidth / 2 + xOffset, transformationBaseBg.displayHeight / 2 + yOffset, "pkmn__sub"); ret.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true }); return ret; }; @@ -54,31 +54,31 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla pokemonEvoTintSprite.setTintFill(0xFFFFFF); [ pokemonSprite, pokemonTintSprite, pokemonEvoSprite, pokemonEvoTintSprite ].map(sprite => { - sprite.play(pokemon.getSpriteKey(true)); - sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(pokemon.getTeraType()) }); + sprite.play(previousPokemon.getSpriteKey(true)); + sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(previousPokemon.getTeraType()) }); sprite.setPipelineData("ignoreTimeTint", true); - sprite.setPipelineData("spriteKey", pokemon.getSpriteKey()); - sprite.setPipelineData("shiny", pokemon.shiny); - sprite.setPipelineData("variant", pokemon.variant); + sprite.setPipelineData("spriteKey", previousPokemon.getSpriteKey()); + sprite.setPipelineData("shiny", previousPokemon.shiny); + sprite.setPipelineData("variant", previousPokemon.variant); [ "spriteColors", "fusionSpriteColors" ].map(k => { - if (pokemon.summonData?.speciesForm) { + if (previousPokemon.summonData?.speciesForm) { k += "Base"; } - sprite.pipelineData[k] = pokemon.getSprite().pipelineData[k]; + sprite.pipelineData[k] = previousPokemon.getSprite().pipelineData[k]; }); }); [ pokemonEvoSprite, pokemonEvoTintSprite ].map(sprite => { - sprite.play(transformedPokemon.getSpriteKey(true)); + sprite.play(transformPokemon.getSpriteKey(true)); sprite.setPipelineData("ignoreTimeTint", true); - sprite.setPipelineData("spriteKey", transformedPokemon.getSpriteKey()); - sprite.setPipelineData("shiny", transformedPokemon.shiny); - sprite.setPipelineData("variant", transformedPokemon.variant); + sprite.setPipelineData("spriteKey", transformPokemon.getSpriteKey()); + sprite.setPipelineData("shiny", transformPokemon.shiny); + sprite.setPipelineData("variant", transformPokemon.variant); [ "spriteColors", "fusionSpriteColors" ].map(k => { - if (transformedPokemon.summonData?.speciesForm) { + if (transformPokemon.summonData?.speciesForm) { k += "Base"; } - sprite.pipelineData[k] = transformedPokemon.getSprite().pipelineData[k]; + sprite.pipelineData[k] = transformPokemon.getSprite().pipelineData[k]; }); }); @@ -123,9 +123,11 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla duration: 2000, delay: 150, easing: "Sine.easeIn", - // onComplete: () => { - // transformedPokemon.destroy(); - // } + onComplete: () => { + previousPokemon.destroy(); + transformPokemon.setVisible(false); + transformPokemon.setAlpha(1); + } }); }); } diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index f3e6009e02e9..fff80d3e7501 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1958,4 +1958,19 @@ export const trainerConfigs: TrainerConfigs = { } p.pokeball = PokeballType.MASTER_BALL; })), + [TrainerType.VICTOR]: new TrainerConfig(++t).setName("Victor").setTitle("The Winstrates") + .setMoneyMultiplier(0.4) // The 5 Winstrate trainers have total money multiplier of 2.6 + .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), + [TrainerType.VICTORIA]: new TrainerConfig(++t).setName("Victoria").setTitle("The Winstrates") + .setMoneyMultiplier(0.4) + .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), + [TrainerType.VIVI]: new TrainerConfig(++t).setName("Vivi").setTitle("The Winstrates") + .setMoneyMultiplier(0.4) + .setPartyTemplates(trainerPartyTemplates.TWO_AVG_ONE_STRONG), + [TrainerType.VICKY]: new TrainerConfig(++t).setName("Vicky").setTitle("The Winstrates") + .setMoneyMultiplier(0.4) + .setPartyTemplates(trainerPartyTemplates.ONE_STRONG), + [TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates") + .setMoneyMultiplier(1) + .setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG))) }; diff --git a/src/enums/mystery-encounter-mode.ts b/src/enums/mystery-encounter-mode.ts index 03094040ce07..3acab7b47979 100644 --- a/src/enums/mystery-encounter-mode.ts +++ b/src/enums/mystery-encounter-mode.ts @@ -2,8 +2,7 @@ export enum MysteryEncounterMode { DEFAULT, TRAINER_BATTLE, WILD_BATTLE, + /** Enables wild boss music during encounter */ BOSS_BATTLE, - NO_BATTLE, - /** For spawning new encounter queries instead of continuing to next wave */ - CONTINUOUS_ENCOUNTER + NO_BATTLE } diff --git a/src/enums/mystery-encounter-type.ts b/src/enums/mystery-encounter-type.ts index 0db41e71ac5d..f9871a1a3dd5 100644 --- a/src/enums/mystery-encounter-type.ts +++ b/src/enums/mystery-encounter-type.ts @@ -22,5 +22,6 @@ export enum MysteryEncounterType { CLOWNING_AROUND, PART_TIMER, DANCING_LESSONS, - WEIRD_DREAM + WEIRD_DREAM, + THE_WINSTRATE_CHALLENGE } diff --git a/src/enums/trainer-type.ts b/src/enums/trainer-type.ts index 0d3a0771604e..65c3370b5102 100644 --- a/src/enums/trainer-type.ts +++ b/src/enums/trainer-type.ts @@ -75,6 +75,11 @@ export enum TrainerType { MARLEY, MIRA, RILEY, + VICTOR, + VICTORIA, + VIVI, + VICKY, + VITO, BROCK = 200, MISTY, diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts index 0f13f486eb26..1192e1b53695 100644 --- a/src/field/mystery-encounter-intro.ts +++ b/src/field/mystery-encounter-intro.ts @@ -1,6 +1,6 @@ import { GameObjects } from "phaser"; import BattleScene from "../battle-scene"; -import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter"; +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"; @@ -70,11 +70,11 @@ export class MysteryEncounterSpriteConfig { * Note: intro visuals are not "Trainers" or any other specific game object, though they may contain trainer sprites */ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container { - public encounter: IMysteryEncounter; + public encounter: MysteryEncounter; public spriteConfigs: MysteryEncounterSpriteConfig[]; public enterFromRight: boolean; - constructor(scene: BattleScene, encounter: IMysteryEncounter) { + constructor(scene: BattleScene, encounter: MysteryEncounter) { super(scene, -72, 76); this.encounter = encounter; this.enterFromRight = encounter.enterIntroVisualsFromRight ?? false; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index feca608038a1..37aa9b1afef2 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -10,7 +10,7 @@ import * as Utils from "../utils"; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type"; import { getLevelTotalExp } from "../data/exp"; import { Stat } from "../data/pokemon-stat"; -import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatTotalModifier } from "../modifier/modifier"; +import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatTotalModifier, PokemonIncrementingStatModifier } from "../modifier/modifier"; import { PokeballType } from "../data/pokeball"; import { Gender } from "../data/gender"; import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims"; @@ -804,6 +804,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } this.stats[s] = value; } + this.scene.applyModifier(PokemonIncrementingStatModifier, this.isPlayer(), this, this.stats); } getNature(): Nature { diff --git a/src/interfaces/held-modifier-config.ts b/src/interfaces/held-modifier-config.ts new file mode 100644 index 000000000000..304de72f01b0 --- /dev/null +++ b/src/interfaces/held-modifier-config.ts @@ -0,0 +1,7 @@ +import { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; + +export default interface HeldModifierConfig { + modifierType: PokemonHeldItemModifierType; + stackCount?: number; + isTransferable?: boolean; +} diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index 50dee0337822..a8be04c8718f 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -627,6 +627,51 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You put up quite the display.\nBetter luck next time." } }, + "winstrates_victor": { + "encounter": { + 1: "That's the spirit! I like you!", + }, + "victory": { + 1: "A-ha! You're stronger than I thought!" + } + }, + "winstrates_victoria": { + "encounter": { + 1: `My goodness! Aren't you young? + $You must be quite the trainer to beat my husband, though. + $Now I suppose it's my turn to battle!`, + }, + "victory": { + 1: "Uwah! Just how strong are you?!" + } + }, + "winstrates_vivi": { + "encounter": { + 1: `You're stronger than Mom? Wow! + $But I'm strong, too!\nReally! Honestly!`, + }, + "victory": { + 1: "Huh? Did I really lose?\nSnivel... Grandmaaa!" + } + }, + "winstrates_vicky": { + "encounter": { + 1: `How dare you make my precious\ngranddaughter cry! + $I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!`, + }, + "victory": { + 1: "Whoa! So strong!\nMy granddaughter wasn't lying." + } + }, + "winstrates_vito": { + "encounter": { + 1: `I trained together with my whole family,\nevery one of us! + $I'm not losing to anyone!`, + }, + "victory": { + 1: "I was better than everyone in my family.\nI've never lost before..." + } + }, "brock": { "encounter": { 1: "My expertise on Rock-type Pokémon will take you down! Come on!", diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts index 1266f6442e9e..cc54a0c5c08f 100644 --- a/src/locales/en/modifier-type.ts +++ b/src/locales/en/modifier-type.ts @@ -262,6 +262,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "MYSTERY_ENCOUNTER_SHUCKLE_JUICE": { name: "Shuckle Juice" }, "MYSTERY_ENCOUNTER_BLACK_SLUDGE": { name: "Black Sludge", description: "The stench is so powerful that healing items are no longer available to purchase in shops." }, + "MYSTERY_ENCOUNTER_MACHO_BRACE": { name: "Macho Brace", description: "Defeating a Pokémon grants the holder a Macho Brace stack. Each stack slightly boosts stats, with an extra bonus at max stacks." }, "MYSTERY_ENCOUNTER_OLD_GATEAU": { name: "Old Gateau", description: "Increases the holder's {{stats}} stats by {{statValue}}." }, }, SpeciesBoosterItem: { diff --git a/src/locales/en/mystery-encounter.ts b/src/locales/en/mystery-encounter.ts index 1358c8949a04..2779900eeff6 100644 --- a/src/locales/en/mystery-encounter.ts +++ b/src/locales/en/mystery-encounter.ts @@ -22,6 +22,7 @@ import { clowningAroundDialogue } from "#app/locales/en/mystery-encounters/clown import { partTimerDialogue } from "#app/locales/en/mystery-encounters/part-timer-dialogue"; import { dancingLessonsDialogue } from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue"; import { weirdDreamDialogue } from "#app/locales/en/mystery-encounters/weird-dream-dialogue"; +import { theWinstrateChallengeDialogue } from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue"; /** * Injection patterns that can be used: @@ -71,5 +72,6 @@ export const mysteryEncounter = { clowningAround: clowningAroundDialogue, partTimer: partTimerDialogue, dancingLessons: dancingLessonsDialogue, - weirdDream: weirdDreamDialogue + weirdDream: weirdDreamDialogue, + theWinstrateChallenge: theWinstrateChallengeDialogue } as const; diff --git a/src/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.ts b/src/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.ts new file mode 100644 index 000000000000..bd5d5560315d --- /dev/null +++ b/src/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.ts @@ -0,0 +1,24 @@ +export const theWinstrateChallengeDialogue = { + intro: "It's a family standing outside their house!", + speaker: "The Winstrates", + intro_dialogue: `We're the Winstrates! + $What do you say to taking on our family in a series of Pokémon battles?`, + title: "The Winstrate Challenge", + description: "The Winstrates are a family of 5 trainers, and they want to battle! If you beat all of them back-to-back, they'll give you a grand prize. But can you handle the heat?", + query: "What will you do?", + option: { + 1: { + label: "Accept the Challenge", + tooltip: "(-) Brutal Battle\n(+) Special Item Reward", + selected: "That's the spirit! I like you!", + }, + 2: { + label: "Refuse the Challenge", + tooltip: "(+) Full Heal Party\n(+) Gain a Rarer Candy", + selected: "That's too bad. Say, your team looks worn out, why don't you stay awhile and rest?" + }, + }, + victory: `Congratulations on beating our challenge! + $Our family uses this Macho Brace to strengthen our Pokémon more effectively during their training. + $You may not need it, considering that you beat the whole lot of us, but we hope you'll accept it anyway!`, +}; diff --git a/src/locales/en/trainers.ts b/src/locales/en/trainers.ts index 0581a6698dee..2adc2da9d5e4 100644 --- a/src/locales/en/trainers.ts +++ b/src/locales/en/trainers.ts @@ -19,6 +19,7 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Team Galactic Boss", "plasma_boss": "Team Plasma Boss", "flare_boss": "Team Flare Boss", + "the_winstrates": "The Winstrates'" // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -275,6 +276,11 @@ export const trainerNames: SimpleTranslationEntries = { "marley": "Marley", "mira": "Mira", "riley": "Riley", + "victor": "Victor", + "victoria": "Victoria", + "vivi": "Vivi", + "vicky": "Vicky", + "vito": "Vito", // Double Names "blue_red_double": "Blue & Red", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index f783e2baa995..791db6facc74 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1506,6 +1506,7 @@ export const modifierTypes = { return new PokemonBaseStatFlatModifierType(Utils.randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]); }), MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.RemoveHealShopModifier(type)), + MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new Modifiers.PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)), }; interface ModifierPool { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 3778310c8f58..e0a8ec0d493f 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -793,6 +793,54 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier { } } +export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { + readonly isTransferrable: boolean = false; + + constructor (type: ModifierType, pokemonId: integer, stackCount?: integer) { + super(type, pokemonId, stackCount); + } + + matchType(modifier: Modifier): boolean { + return modifier instanceof PokemonIncrementingStatModifier; + } + + clone(): PersistentModifier { + return new PokemonIncrementingStatModifier(this.type, this.pokemonId); + } + + getArgs(): any[] { + return super.getArgs(); + } + + shouldApply(args: any[]): boolean { + return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array; + } + + apply(args: any[]): boolean { + // Modifies the passed in stats[] array by +1 per stack for HP, +2 per stack for other stats + // If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats + args[1].forEach((v, i) => { + const isHp = i === 0; + let mult = 1; + if (this.stackCount === this.getMaxHeldItemCount(null)) { + mult = isHp ? 1.05 : 1.1; + } + const newVal = Math.floor((v + this.stackCount * (isHp ? 1 : 2)) * mult); + args[1][i] = Math.min(Math.max(newVal, 1), 999999); + }); + + return true; + } + + getScoreMultiplier(): number { + return 1.2; + } + + getMaxHeldItemCount(pokemon: Pokemon): integer { + return 50; + } +} + /** * Modifier used for held items that apply {@linkcode Stat} boost(s) * using a multiplier. diff --git a/src/phases.ts b/src/phases.ts index 24cf33a98f6c..6d9054da3276 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -6,7 +6,7 @@ import { allMoves, applyFilteredMoveAttrs, applyMoveAttrs, AttackMove, BypassRed import { Mode } from "./ui/ui"; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; -import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PokemonMultiHitModifier, PokemonResetNegativeStatStageModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } from "./modifier/modifier"; +import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonMultiHitModifier, PokemonResetNegativeStatStageModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } 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"; @@ -1302,8 +1302,7 @@ export class NextEncounterPhase extends EncounterPhase { this.scene.lastEnemyTrainer.destroy(); } if (lastEncounterVisuals) { - this.scene.field.remove(lastEncounterVisuals); - lastEncounterVisuals.destroy(); + this.scene.field.remove(lastEncounterVisuals, true); this.scene.lastMysteryEncounter.introVisuals = null; } @@ -1583,7 +1582,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { onComplete: () => this.scene.trainer.setVisible(false) }); this.scene.time.delayedCall(750, () => this.summon()); - } else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene?.currentBattle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { + } else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { const trainerName = this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); const pokemonName = getPokemonNameWithAffix(this.getPokemon()); const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName }); @@ -2287,7 +2286,7 @@ export class CommandPhase extends FieldPhase { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); - } else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) { + } else if (!isSwitch && (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE)) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noEscapeTrainer"), null, () => { @@ -4138,6 +4137,12 @@ export class VictoryPhase extends PokemonPhase { const participated = participantIds.has(pId); if (participated) { partyMember.addFriendship(2); + const machoBraceModifier = partyMember.getHeldItems().find(m => m instanceof PokemonIncrementingStatModifier); + if (!isNullOrUndefined(machoBraceModifier) && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount(this.scene)) { + machoBraceModifier.stackCount++; + this.scene.updateModifiers(true, true); + partyMember.updateInfo(); + } } if (!expPartyMembers.includes(partyMember)) { continue; diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index fe6de6973dac..160a081fda10 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -381,6 +381,10 @@ export class MysteryEncounterBattlePhase extends Phase { /** * Will handle (in order): + * - doContinueEncounter() callback for continuous encounters with back-to-back battles (this should push/shift its own phases as needed) + * + * OR + * * - Any encounter reward logic that is set within MysteryEncounter doEncounterExp * - Any encounter reward logic that is set within MysteryEncounter doEncounterRewards * - Otherwise, can add a no-reward-item shop with only Potions, etc. if addHealPhase is true @@ -396,23 +400,30 @@ export class MysteryEncounterRewardsPhase extends Phase { start() { super.start(); + const encounter = this.scene.currentBattle.mysteryEncounter; - this.scene.executeWithSeedOffset(() => { - if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) { - this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene); - } + if (encounter.doContinueEncounter) { + encounter.doContinueEncounter(this.scene).then(() => { + this.end(); + }); + } else { + this.scene.executeWithSeedOffset(() => { + if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) { + this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene); + } - if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) { - 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 })); - } - // Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave) - }, this.scene.currentBattle.waveIndex * 1000); + if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) { + 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 })); + } + // Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave) + }, this.scene.currentBattle.waveIndex * 1000); - this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene)); - this.end(); + this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene)); + this.end(); + } } } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index af465278e390..62c8c6b8aefe 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -43,7 +43,7 @@ import { Species } from "#enums/species"; import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import { Abilities } from "#app/enums/abilities.js"; import { MysteryEncounterData } from "../data/mystery-encounters/mystery-encounter-data"; -import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter"; +import MysteryEncounter from "../data/mystery-encounters/mystery-encounter"; export const defaultStarterSpecies: Species[] = [ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, @@ -126,7 +126,7 @@ export interface SessionSaveData { gameVersion: string; timestamp: integer; challenges: ChallengeData[]; - mysteryEncounter: IMysteryEncounter; + mysteryEncounter: MysteryEncounter; mysteryEncounterData: MysteryEncounterData; } @@ -1167,7 +1167,7 @@ export class GameData { } if (k === "mysteryEncounter") { - return new IMysteryEncounter(v); + return new MysteryEncounter(v); } if (k === "mysteryEncounterData") { 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 3acd8d1ef993..80f022a3e3ec 100644 --- a/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/clowning-around-encounter.test.ts @@ -7,7 +7,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite import { getPokemonSpecies } from "#app/data/pokemon-species"; import * as BattleAnims from "#app/data/battle-anims"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { generateModifierTypeOption } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils"; import { CommandPhase, MovePhase, NewBattlePhase, SelectModifierPhase } from "#app/phases"; import { Moves } from "#enums/moves"; @@ -123,7 +123,6 @@ describe("Clowning Around - Mystery Encounter", () => { }); expect(config.pokemonConfigs[1]).toEqual({ species: getPokemonSpecies(Species.BLACEPHALON), - ability: expect.any(Number), mysteryEncounterData: expect.anything(), isBoss: true, moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] @@ -145,8 +144,8 @@ describe("Clowning Around - Mystery Encounter", () => { Abilities.MAGICIAN, Abilities.SHEER_FORCE, Abilities.PRANKSTER - ]).toContain(config.pokemonConfigs[1].ability); - expect(ClowningAroundEncounter.misc.ability).toBe(config.pokemonConfigs[1].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); @@ -258,26 +257,26 @@ describe("Clowning Around - Mystery Encounter", () => { // 2 Sitrus Berries on lead scene.modifiers = []; - let itemType = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type as PokemonHeldItemModifierType; + let itemType = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 2, itemType); // 2 Ganlon Berries on lead - itemType = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.GANLON]).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 2, itemType); // 5 Golden Punch on lead (ultra) - itemType = generateModifierTypeOption(scene, modifierTypes.GOLDEN_PUNCH).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.GOLDEN_PUNCH) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 5, itemType); // 5 Lucky Egg on lead (ultra) - itemType = generateModifierTypeOption(scene, modifierTypes.LUCKY_EGG).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 5, itemType); // 5 Soul Dew on lead (rogue) - itemType = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 5, itemType); // 2 Golden Egg on lead (rogue) - itemType = generateModifierTypeOption(scene, modifierTypes.GOLDEN_EGG).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.GOLDEN_EGG) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[0], 2, itemType); // 5 Soul Dew on second party pokemon (these should not change) - itemType = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type as PokemonHeldItemModifierType; + itemType = generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType; await addItemToPokemon(scene, scene.getParty()[1], 5, itemType); await runMysteryEncounterToEnd(game, 2); diff --git a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts index 8934dbb5f5c6..43f9c5612db0 100644 --- a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts @@ -13,7 +13,7 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encount import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; -import { generateModifierTypeOption } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes } from "#app/modifier/modifier-type"; import { BerryType } from "#enums/berry-type"; @@ -137,7 +137,7 @@ describe("Delibird-y - Mystery Encounter", () => { // 5 Healing Charms scene.modifiers = []; - const abilityCharm = generateModifierTypeOption(scene, modifierTypes.ABILITY_CHARM).type.newModifier() as HiddenAbilityRateBoosterModifier; + const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM).newModifier() as HiddenAbilityRateBoosterModifier; abilityCharm.stackCount = 4; await scene.addModifier(abilityCharm, true, false, false, true); await scene.updateModifiers(true); @@ -206,7 +206,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 2 Sitrus berries on party lead scene.modifiers = []; - const sitrus = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type; + const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]); const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier; sitrusMod.stackCount = 2; await scene.addModifier(sitrusMod, true, false, false, true); @@ -227,7 +227,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 1 Reviver Seed on party lead scene.modifiers = []; - const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type; + const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED); const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); @@ -248,10 +248,10 @@ describe("Delibird-y - Mystery Encounter", () => { // 99 Candy Jars scene.modifiers = []; - const candyJar = generateModifierTypeOption(scene, modifierTypes.CANDY_JAR).type.newModifier() as LevelIncrementBoosterModifier; + const candyJar = generateModifierType(scene, modifierTypes.CANDY_JAR).newModifier() as LevelIncrementBoosterModifier; candyJar.stackCount = 99; await scene.addModifier(candyJar, true, false, false, true); - const sitrus = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type; + const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]); // Sitrus berries on party const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier; @@ -277,12 +277,12 @@ describe("Delibird-y - Mystery Encounter", () => { // 5 Healing Charms scene.modifiers = []; - const healingCharm = generateModifierTypeOption(scene, modifierTypes.HEALING_CHARM).type.newModifier() as HealingBoosterModifier; + const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM).newModifier() as HealingBoosterModifier; healingCharm.stackCount = 5; await scene.addModifier(healingCharm, true, false, false, true); // Set 1 Reviver Seed on party lead - const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type; + const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED); const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); @@ -306,7 +306,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 1 Soul Dew on party lead scene.modifiers = []; - const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type; + const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW); const modifier = soulDew.newModifier(scene.getParty()[0]); await scene.addModifier(modifier, true, false, false, true); await scene.updateModifiers(true); @@ -334,7 +334,7 @@ describe("Delibird-y - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); // Set 1 Reviver Seed on party lead - const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type; + const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED); const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); @@ -368,7 +368,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 2 Soul Dew on party lead scene.modifiers = []; - const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type; + const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW); const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier; modifier.stackCount = 2; await scene.addModifier(modifier, true, false, false, true); @@ -389,7 +389,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 1 Soul Dew on party lead scene.modifiers = []; - const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type; + const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW); const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); @@ -410,12 +410,12 @@ describe("Delibird-y - Mystery Encounter", () => { // 5 Healing Charms scene.modifiers = []; - const healingCharm = generateModifierTypeOption(scene, modifierTypes.BERRY_POUCH).type.newModifier() as PreserveBerryModifier; + const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH).newModifier() as PreserveBerryModifier; healingCharm.stackCount = 3; await scene.addModifier(healingCharm, true, false, false, true); // Set 1 Soul Dew on party lead - const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type; + const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW); const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); @@ -439,7 +439,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 1 Reviver Seed on party lead scene.modifiers = []; - const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type; + const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED); const modifier = revSeed.newModifier(scene.getParty()[0]); await scene.addModifier(modifier, true, false, false, true); await scene.updateModifiers(true); @@ -468,7 +468,7 @@ describe("Delibird-y - Mystery Encounter", () => { // Set 1 Soul Dew on party lead scene.modifiers = []; - const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type; + const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW); const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier; modifier.stackCount = 1; await scene.addModifier(modifier, true, false, false, true); 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 7fe6b1a3f95b..31fb03cb7d32 100644 --- a/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts @@ -18,7 +18,7 @@ import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyTemplate } fro import { PartyMemberStrength } from "#enums/party-member-strength"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import IMysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; const namespace = "mysteryEncounter:mysteriousChallengers"; const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; @@ -96,7 +96,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { it("should initialize fully", async () => { initSceneWithoutEncounterPhase(scene, defaultParty); - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(MysteriousChallengersEncounter); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(MysteriousChallengersEncounter); const encounter = scene.currentBattle.mysteryEncounter; scene.currentBattle.waveIndex = defaultWave; 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 21d0678c858e..5c526ddeb579 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 @@ -123,7 +123,7 @@ describe("The Strong Stuff - Mystery Encounter", () => { mysteryEncounterData: new MysteryEncounterPokemonData(1.5), nature: Nature.BOLD, moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER], - modifierTypes: expect.any(Array), + modifierConfigs: expect.any(Array), tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: expect.any(Function) } diff --git a/src/test/mystery-encounter/mystery-encounter-utils.test.ts b/src/test/mystery-encounter/mystery-encounter-utils.test.ts index a336af41b6bc..a0e055e3bcfb 100644 --- a/src/test/mystery-encounter/mystery-encounter-utils.test.ts +++ b/src/test/mystery-encounter/mystery-encounter-utils.test.ts @@ -5,7 +5,7 @@ import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; import { StatusEffect } from "#app/data/status-effect"; -import IMysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MessagePhase } from "#app/phases"; import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { Type } from "#app/data/type"; @@ -250,7 +250,7 @@ describe("Mystery Encounter Utils", () => { describe("getTextWithEncounterDialogueTokens", () => { it("injects dialogue tokens and color styling", () => { - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const result = getEncounterText(scene, "mysteryEncounter:unit_test_dialogue"); @@ -258,7 +258,7 @@ describe("Mystery Encounter Utils", () => { }); it("can perform nested dialogue token injection", () => { - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); scene.currentBattle.mysteryEncounter.setDialogueToken("testvalue", "new"); @@ -269,7 +269,7 @@ describe("Mystery Encounter Utils", () => { describe("queueEncounterMessage", () => { it("queues a message with encounter dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene, "queueMessage"); const phaseSpy = vi.spyOn(game.scene, "unshiftPhase"); @@ -282,7 +282,7 @@ describe("Mystery Encounter Utils", () => { describe("showEncounterText", () => { it("showText with dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene.ui, "showText"); @@ -293,7 +293,7 @@ describe("Mystery Encounter Utils", () => { describe("showEncounterDialogue", () => { it("showText with dialogue tokens", async () => { - scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(null); scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value"); const spy = vi.spyOn(game.scene.ui, "showDialogue"); From 8826183777b6f3d6154646a4fa162dd62be144e5 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Mon, 19 Aug 2024 10:58:17 -0400 Subject: [PATCH 2/4] small cleanup for winstrates --- src/battle-scene.ts | 4 ---- src/data/trainer-config.ts | 10 +++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d35c73c2a0dd..cac73d6791b1 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1067,10 +1067,6 @@ export default class BattleScene extends SceneBase { newBattleType = battleType; } - if (waveIndex === 64) { - newBattleType = BattleType.TRAINER; - } - if (newBattleType === BattleType.TRAINER) { const trainerType = this.arena.randomTrainerType(newWaveIndex); let doubleTrainer = false; diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index fff80d3e7501..54efc6bd9002 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1959,18 +1959,18 @@ export const trainerConfigs: TrainerConfigs = { p.pokeball = PokeballType.MASTER_BALL; })), [TrainerType.VICTOR]: new TrainerConfig(++t).setName("Victor").setTitle("The Winstrates") - .setMoneyMultiplier(0.4) // The 5 Winstrate trainers have total money multiplier of 2.6 + .setMoneyMultiplier(1) // The Winstrate trainers have total money multiplier of 6 .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), [TrainerType.VICTORIA]: new TrainerConfig(++t).setName("Victoria").setTitle("The Winstrates") - .setMoneyMultiplier(0.4) + .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), [TrainerType.VIVI]: new TrainerConfig(++t).setName("Vivi").setTitle("The Winstrates") - .setMoneyMultiplier(0.4) + .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.TWO_AVG_ONE_STRONG), [TrainerType.VICKY]: new TrainerConfig(++t).setName("Vicky").setTitle("The Winstrates") - .setMoneyMultiplier(0.4) + .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.ONE_STRONG), [TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates") - .setMoneyMultiplier(1) + .setMoneyMultiplier(2) .setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG))) }; From 64811239d7cce9e3566feb7534b27d124d9e40d8 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Mon, 19 Aug 2024 12:28:22 -0400 Subject: [PATCH 3/4] add unit tests for Winstrate Challenge --- .../encounters/a-trainers-test-encounter.ts | 2 +- .../encounters/delibirdy-encounter.ts | 2 +- .../encounters/part-timer-encounter.ts | 4 +- .../shady-vitamin-dealer-encounter.ts | 2 +- .../the-winstrate-challenge-encounter.ts | 4 +- .../utils/encounter-phase-utils.ts | 5 +- .../the-winstrate-challenge-encounter.test.ts | 385 ++++++++++++++++++ src/test/utils/gameWrapper.ts | 1 + 8 files changed, 397 insertions(+), 8 deletions(-) create mode 100644 src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts 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 132c7e34e080..d42d4051aa6a 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -178,7 +178,7 @@ export const ATrainersTestEncounter: MysteryEncounter = ) .withOutroDialogue([ { - text: `${namespace}:outro`, + text: `${namespace}.outro`, }, ]) .build(); diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 18b6883b529e..2c7f8b9fe7e1 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -169,7 +169,7 @@ 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`); } return null; diff --git a/src/data/mystery-encounters/encounters/part-timer-encounter.ts b/src/data/mystery-encounters/encounters/part-timer-encounter.ts index 94318ac69267..c66a8efe5f73 100644 --- a/src/data/mystery-encounters/encounters/part-timer-encounter.ts +++ b/src/data/mystery-encounters/encounters/part-timer-encounter.ts @@ -115,7 +115,7 @@ 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`); } return null; @@ -194,7 +194,7 @@ 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`); } return null; 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 6ce4474206d3..836c0cb1f98d 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -95,7 +95,7 @@ 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`); } return null; 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 434cabb4a429..e3da86ca2992 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -118,7 +118,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = buttonTooltip: `${namespace}.option.2.tooltip`, selected: [ { - speaker: `${namespace}:speaker`, + speaker: `${namespace}.speaker`, text: `${namespace}.option.2.selected`, }, ], @@ -137,7 +137,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) { const nextConfig = encounter.enemyPartyConfigs.pop(); if (!nextConfig) { await transitionMysteryEncounterIntroVisuals(scene, false, false); - await showEncounterDialogue(scene, `${namespace}:victory`, `${namespace}:speaker`); + await showEncounterDialogue(scene, `${namespace}.victory`, `${namespace}.speaker`); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE], fillRemaining: false }); encounter.doContinueEncounter = null; leaveEncounterWithoutBattle(scene); diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 4d3d89b1abc0..5a98d7737c08 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -671,7 +671,10 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase: scene.pushPhase(new TrainerVictoryPhase(scene)); } if (scene.gameMode.isEndless || !scene.gameMode.isWaveFinal(scene.currentBattle.waveIndex)) { - scene.pushPhase(new EggLapsePhase(scene)); + if (!encounter.doContinueEncounter) { + // Only lapse eggs once for multi-battle encounters + scene.pushPhase(new EggLapsePhase(scene)); + } scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase)); } } 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 new file mode 100644 index 000000000000..667c2d2ec3d1 --- /dev/null +++ b/src/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts @@ -0,0 +1,385 @@ +import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; +import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters"; +import { Biome } from "#app/enums/biome"; +import { MysteryEncounterType } from "#app/enums/mystery-encounter-type"; +import { Species } from "#app/enums/species"; +import GameManager from "#app/test/utils/gameManager"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils"; +import { CommandPhase, PartyHealPhase, SelectModifierPhase, VictoryPhase } from "#app/phases"; +import BattleScene from "#app/battle-scene"; +import { Mode } from "#app/ui/ui"; +import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; +import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; +import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; +import { TrainerType } from "#enums/trainer-type"; +import { Nature } from "#enums/nature"; +import { Moves } from "#enums/moves"; +import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-encounter"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases"; + +const namespace = "mysteryEncounter:theWinstrateChallenge"; +const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; +const defaultBiome = Biome.CAVE; +const defaultWave = 45; + +describe("The Winstrate Challenge - Mystery Encounter", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + let scene: BattleScene; + + beforeAll(() => { + phaserGame = new Phaser.Game({ type: Phaser.HEADLESS }); + }); + + beforeEach(async () => { + game = new GameManager(phaserGame); + scene = game.scene; + game.override.mysteryEncounterChance(100); + game.override.startingWave(defaultWave); + game.override.startingBiome(defaultBiome); + game.override.disableTrainerWaves(true); + + const biomeMap = new Map([ + [Biome.VOLCANO, [MysteryEncounterType.FIGHT_OR_FLIGHT]], + ]); + HUMAN_TRANSITABLE_BIOMES.forEach(biome => { + biomeMap.set(biome, [MysteryEncounterType.THE_WINSTRATE_CHALLENGE]); + }); + vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it("should have the correct properties", async () => { + await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty); + + expect(TheWinstrateChallengeEncounter.encounterType).toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE); + expect(TheWinstrateChallengeEncounter.encounterTier).toBe(MysteryEncounterTier.ROGUE); + expect(TheWinstrateChallengeEncounter.dialogue).toBeDefined(); + expect(TheWinstrateChallengeEncounter.dialogue.intro).toStrictEqual([ + { text: `${namespace}.intro` }, + { + speaker: `${namespace}.speaker`, + 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.options.length).toBe(2); + }); + + it("should not spawn outside of HUMAN_TRANSITABLE_BIOMES", async () => { + game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT); + game.override.startingBiome(Biome.VOLCANO); + await game.runToMysteryEncounter(); + + expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE); + }); + + it("should not run below wave 10", async () => { + game.override.startingWave(9); + + await game.runToMysteryEncounter(); + + expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE); + }); + + it("should not run above wave 179", async () => { + game.override.startingWave(181); + + await game.runToMysteryEncounter(); + + expect(scene.currentBattle.mysteryEncounter).toBeUndefined(); + }); + + it("should initialize fully", async () => { + initSceneWithoutEncounterPhase(scene, defaultParty); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(TheWinstrateChallengeEncounter); + const encounter = scene.currentBattle.mysteryEncounter; + scene.currentBattle.waveIndex = defaultWave; + + const { onInit } = encounter; + + expect(encounter.onInit).toBeDefined(); + + encounter.populateDialogueTokensFromRequirements(scene); + const onInitResult = onInit(scene); + + expect(encounter.enemyPartyConfigs).toBeDefined(); + expect(encounter.enemyPartyConfigs.length).toBe(5); + expect(encounter.enemyPartyConfigs).toEqual([ + { + trainerType: TrainerType.VITO, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.HISUI_ELECTRODE), + isBoss: false, + abilityIndex: 0, // Soundproof + nature: Nature.MODEST, + moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.SWALOT), + isBoss: false, + abilityIndex: 2, // Gluttony + nature: Nature.QUIET, + moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.DODRIO), + isBoss: false, + abilityIndex: 2, // Tangled Feet + nature: Nature.JOLLY, + moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.ALAKAZAM), + isBoss: false, + formIndex: 1, + nature: Nature.BOLD, + moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.DARMANITAN), + isBoss: false, + abilityIndex: 0, // Sheer Force + nature: Nature.IMPISH, + moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE], + modifierConfigs: expect.any(Array) + } + ] + }, + { + trainerType: TrainerType.VICKY, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.MEDICHAM), + isBoss: false, + formIndex: 1, + nature: Nature.IMPISH, + moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH], + modifierConfigs: expect.any(Array) + } + ] + }, + { + trainerType: TrainerType.VIVI, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.SEAKING), + isBoss: false, + abilityIndex: 3, // Lightning Rod + nature: Nature.ADAMANT, + moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.BRELOOM), + isBoss: false, + abilityIndex: 1, // Poison Heal + nature: Nature.JOLLY, + moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.CAMERUPT), + isBoss: false, + formIndex: 1, + nature: Nature.CALM, + moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT], + modifierConfigs: expect.any(Array) + } + ] + }, + { + trainerType: TrainerType.VICTORIA, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.ROSERADE), + isBoss: false, + abilityIndex: 0, // Natural Cure + nature: Nature.CALM, + moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.GARDEVOIR), + isBoss: false, + formIndex: 1, + nature: Nature.TIMID, + moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP], + modifierConfigs: expect.any(Array) + } + ] + }, + { + trainerType: TrainerType.VICTOR, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.SWELLOW), + isBoss: false, + abilityIndex: 0, // Guts + nature: Nature.ADAMANT, + moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK], + modifierConfigs: expect.any(Array) + }, + { + species: getPokemonSpecies(Species.OBSTAGOON), + isBoss: false, + abilityIndex: 1, // Guts + nature: Nature.ADAMANT, + moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH], + modifierConfigs: expect.any(Array) + } + ] + } + ]); + expect(encounter.spriteConfigs).toBeDefined(); + expect(encounter.spriteConfigs.length).toBe(5); + expect(onInitResult).toBe(true); + }); + + describe("Option 1 - Normal Battle", () => { + it("should have the correct properties", () => { + const option = TheWinstrateChallengeEncounter.options[0]; + expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); + expect(option.dialogue).toBeDefined(); + expect(option.dialogue).toStrictEqual({ + buttonLabel: `${namespace}.option.1.label`, + buttonTooltip: `${namespace}.option.1.tooltip`, + selected: [ + { + speaker: "trainerNames:victor", + text: `${namespace}.option.1.selected`, + }, + ], + }); + }); + + 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); + + 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.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.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.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.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.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); + await game.phaseInterceptor.run(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(1); + expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("MYSTERY_ENCOUNTER_MACHO_BRACE"); + }, 15000); + }); + + describe("Option 2 - Refuse the Challenge", () => { + it("should have the correct properties", () => { + const option = TheWinstrateChallengeEncounter.options[1]; + expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); + expect(option.dialogue).toBeDefined(); + expect(option.dialogue).toStrictEqual({ + buttonLabel: `${namespace}.option.2.label`, + buttonTooltip: `${namespace}.option.2.tooltip`, + selected: [ + { + speaker: `${namespace}.speaker`, + text: `${namespace}.option.2.selected`, + }, + ], + }); + }); + + it("Should fully heal the party", async () => { + const phaseSpy = vi.spyOn(scene, "unshiftPhase"); + + await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty); + await runMysteryEncounterToEnd(game, 2); + + const partyHealPhases = phaseSpy.mock.calls.filter(p => p[0] instanceof PartyHealPhase).map(p => p[0]); + expect(partyHealPhases.length).toBe(1); + }); + + 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); + await game.phaseInterceptor.run(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(1); + expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("RARER_CANDY"); + }); + }); +}); + +/** + * For any MysteryEncounter that has a battle, can call this to skip battle and proceed to MysteryEncounterRewardsPhase + * @param game + * @param isFinalBattle + */ +async function skipBattleToNextBattle(game: GameManager, isFinalBattle: boolean = false) { + game.scene.clearPhaseQueue(); + game.scene.clearPhaseQueueSplice(); + const commandUiHandler = game.scene.ui.handlers[Mode.COMMAND]; + commandUiHandler.clear(); + game.scene.getEnemyParty().forEach(p => { + p.hp = 0; + p.status = new Status(StatusEffect.FAINT); + game.scene.field.remove(p); + }); + game.phaseInterceptor["onHold"] = []; + game.scene.pushPhase(new VictoryPhase(game.scene, 0)); + game.phaseInterceptor.superEndPhase(); + if (isFinalBattle) { + await game.phaseInterceptor.to(MysteryEncounterRewardsPhase); + } else { + await game.phaseInterceptor.to(CommandPhase); + } +} diff --git a/src/test/utils/gameWrapper.ts b/src/test/utils/gameWrapper.ts index b1b00c8e15dd..2eb924a6f194 100644 --- a/src/test/utils/gameWrapper.ts +++ b/src/test/utils/gameWrapper.ts @@ -127,6 +127,7 @@ export default class GameWrapper { manager: { game: this.game, }, + destroy: () => null, setVolume: () => null, stopByKey: () => null, on: (evt, callback) => callback(), From c831baa37521e28579df7efe0445eb26dbff2179 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Mon, 19 Aug 2024 12:56:50 -0400 Subject: [PATCH 4/4] fix pokemon not returning after winstrate battle --- .../encounters/the-winstrate-challenge-encounter.ts | 3 ++- src/data/mystery-encounters/utils/encounter-phase-utils.ts | 5 +++-- src/data/trainer-config.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) 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 e3da86ca2992..c0886ed9f6b6 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -17,6 +17,7 @@ import { PartyHealPhase, ReturnPhase, ShowTrainerPhase } from "#app/phases"; import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability"; import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; +import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:theWinstrateChallenge"; @@ -140,7 +141,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) { await showEncounterDialogue(scene, `${namespace}.victory`, `${namespace}.speaker`); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE], fillRemaining: false }); encounter.doContinueEncounter = null; - leaveEncounterWithoutBattle(scene); + leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.TRAINER_BATTLE); } else { await initBattleWithEnemyConfig(scene, nextConfig); } diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 5a98d7737c08..c58e0fbad1fd 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -634,9 +634,10 @@ export function initSubsequentOptionSelect(scene: BattleScene, optionSelectSetti * Will skip any shops and rewards, and queue the next encounter phase as normal * @param scene * @param addHealPhase - when true, will add a shop phase to end of encounter with 0 rewards but healing items are available + * @param encounterMode - Can set custom encounter mode if necessary (may be required for forcing Pokemon to return before next phase) */ -export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false) { - scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.NO_BATTLE; +export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false, encounterMode: MysteryEncounterMode = MysteryEncounterMode.NO_BATTLE) { + scene.currentBattle.mysteryEncounter.encounterMode = encounterMode; scene.clearPhaseQueue(); scene.clearPhaseQueueSplice(); handleMysteryEncounterVictory(scene, addHealPhase); diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 54efc6bd9002..eeffd02bc150 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1969,7 +1969,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyTemplates(trainerPartyTemplates.TWO_AVG_ONE_STRONG), [TrainerType.VICKY]: new TrainerConfig(++t).setName("Vicky").setTitle("The Winstrates") .setMoneyMultiplier(1) - .setPartyTemplates(trainerPartyTemplates.ONE_STRONG), + .setPartyTemplates(trainerPartyTemplates.ONE_AVG), [TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates") .setMoneyMultiplier(2) .setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG)))