From a13550ec4464b9147622aa87d9ce32fc32446d34 Mon Sep 17 00:00:00 2001 From: Moka <54149968+MokaStitcher@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:46:57 +0200 Subject: [PATCH] [Balance][ME] Various ME Balance changes (#4700) * balance changes and updates to various MEs * fix import to new item * fix import to new item * Update src/data/mystery-encounters/utils/encounter-pokemon-utils.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/phases/select-modifier-phase.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/modifier/modifier.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/modifier/modifier.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * revert item atlas changes * eslint * revert 'revert item atlas' * update locale repo to latest commit * Fix fiery fallout missing argument * [balance] Training session ME does not update Seen/Defeated GameStats * [balance] update Weird Dream ME maximum spawn wave * [ME] update CombinationRequirements to allow AND or OR combinations * refactor: CombinationPokemonRequirement `.Some()` and `Every()` * chore: rename `orRequirements` to `requirements` * fix: returns of `Some()` and `Any()` * apply `Some()` / `Any()` pattern to `CombinationSceneRequirement` too * revert 'offer you can't refuse' giving Silver Pokeball' * Apply code review suggestions * [me] Weird Dream: apply same old gateau logic to team in options 1 and 2 --------- Co-authored-by: ImperialSympathizer Co-authored-by: ImperialSympathizer <110984302+ben-lear@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: innerthunder --- public/images/items.json | 797 +++++++++--------- public/images/items.png | Bin 58527 -> 58657 bytes public/images/items/pb_silver.png | Bin 0 -> 556 bytes public/images/trainer/future_self_f.json | 41 + public/images/trainer/future_self_f.png | Bin 0 -> 664 bytes public/images/trainer/future_self_m.json | 41 + public/images/trainer/future_self_m.png | Bin 0 -> 695 bytes public/locales | 2 +- src/data/balance/pokemon-evolutions.ts | 6 +- .../an-offer-you-cant-refuse-encounter.ts | 15 +- .../encounters/bug-type-superfan-encounter.ts | 26 +- .../encounters/clowning-around-encounter.ts | 15 +- .../encounters/dark-deal-encounter.ts | 10 +- .../encounters/delibirdy-encounter.ts | 25 +- .../encounters/fiery-fallout-encounter.ts | 78 +- .../mysterious-challengers-encounter.ts | 8 +- .../shady-vitamin-dealer-encounter.ts | 2 +- .../the-expert-pokemon-breeder-encounter.ts | 27 +- .../encounters/training-session-encounter.ts | 1 + .../encounters/trash-to-treasure-encounter.ts | 2 +- .../encounters/weird-dream-encounter.ts | 381 ++++++--- .../mystery-encounter-requirements.ts | 127 ++- .../mystery-encounters/mystery-encounter.ts | 14 + .../requirements/requirement-groups.ts | 17 + .../utils/encounter-pokemon-utils.ts | 20 + src/data/trainer-config.ts | 18 +- src/enums/trainer-type.ts | 2 + src/field/pokemon.ts | 2 - src/modifier/modifier-type.ts | 9 +- src/modifier/modifier.ts | 66 +- src/phases/select-modifier-phase.ts | 11 +- src/phases/victory-phase.ts | 9 +- src/system/game-data.ts | 4 + src/system/pokemon-data.ts | 3 +- .../encounters/delibirdy-encounter.test.ts | 48 +- .../fiery-fallout-encounter.test.ts | 47 +- .../trash-to-treasure-encounter.test.ts | 2 +- .../encounters/weird-dream-encounter.test.ts | 67 +- 38 files changed, 1244 insertions(+), 699 deletions(-) create mode 100644 public/images/items/pb_silver.png create mode 100644 public/images/trainer/future_self_f.json create mode 100644 public/images/trainer/future_self_f.png create mode 100644 public/images/trainer/future_self_m.json create mode 100644 public/images/trainer/future_self_m.png diff --git a/public/images/items.json b/public/images/items.json index 05d021b6a06..3c9cff7a35a 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -6583,7 +6583,7 @@ } }, { - "filename": "rb", + "filename": "pb_silver", "rotated": false, "trimmed": true, "sourceSize": { @@ -6666,6 +6666,27 @@ "h": 19 } }, + { + "filename": "rb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 254, + "y": 320, + "w": 20, + "h": 20 + } + }, { "filename": "smooth_meteorite", "rotated": false, @@ -6680,27 +6701,6 @@ "w": 20, "h": 20 }, - "frame": { - "x": 254, - "y": 320, - "w": 20, - "h": 20 - } - }, - { - "filename": "strange_ball", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, "frame": { "x": 274, "y": 325, @@ -6709,7 +6709,7 @@ } }, { - "filename": "ub", + "filename": "strange_ball", "rotated": false, "trimmed": true, "sourceSize": { @@ -6751,7 +6751,7 @@ } }, { - "filename": "apicot_berry", + "filename": "ub", "rotated": false, "trimmed": true, "sourceSize": { @@ -6761,13 +6761,13 @@ "spriteSourceSize": { "x": 6, "y": 6, - "w": 19, + "w": 20, "h": 20 }, "frame": { "x": 221, "y": 337, - "w": 19, + "w": 20, "h": 20 } }, @@ -6793,7 +6793,7 @@ } }, { - "filename": "big_mushroom", + "filename": "apicot_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -6804,13 +6804,13 @@ "x": 6, "y": 6, "w": 19, - "h": 19 + "h": 20 }, "frame": { "x": 343, "y": 287, "w": 19, - "h": 19 + "h": 20 } }, { @@ -6834,6 +6834,27 @@ "h": 20 } }, + { + "filename": "big_mushroom", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 19 + }, + "frame": { + "x": 318, + "y": 306, + "w": 19, + "h": 19 + } + }, { "filename": "hard_stone", "rotated": false, @@ -6849,33 +6870,12 @@ "h": 20 }, "frame": { - "x": 318, - "y": 306, + "x": 314, + "y": 325, "w": 19, "h": 20 } }, - { - "filename": "miracle_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 19, - "h": 19 - }, - "frame": { - "x": 337, - "y": 306, - "w": 19, - "h": 19 - } - }, { "filename": "wl_ability_urge", "rotated": false, @@ -6891,12 +6891,33 @@ "h": 18 }, "frame": { - "x": 314, - "y": 326, + "x": 337, + "y": 307, "w": 20, "h": 18 } }, + { + "filename": "miracle_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 333, + "y": 325, + "w": 19, + "h": 19 + } + }, { "filename": "wl_antidote", "rotated": false, @@ -6912,12 +6933,54 @@ "h": 18 }, "frame": { - "x": 356, + "x": 357, "y": 307, "w": 20, "h": 18 } }, + { + "filename": "wl_awakening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 352, + "y": 325, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_burn_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 241, + "y": 340, + "w": 20, + "h": 18 + } + }, { "filename": "golden_egg", "rotated": false, @@ -6933,33 +6996,12 @@ "h": 20 }, "frame": { - "x": 376, - "y": 307, + "x": 372, + "y": 325, "w": 17, "h": 20 } }, - { - "filename": "wl_awakening", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 393, - "y": 241, - "w": 20, - "h": 18 - } - }, { "filename": "toxic_orb", "rotated": false, @@ -6975,96 +7017,12 @@ "h": 18 }, "frame": { - "x": 413, - "y": 258, + "x": 377, + "y": 307, "w": 18, "h": 18 } }, - { - "filename": "wl_burn_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 393, - "y": 259, - "w": 20, - "h": 18 - } - }, - { - "filename": "ampharosite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 377, - "y": 243, - "w": 16, - "h": 16 - } - }, - { - "filename": "audinite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 377, - "y": 259, - "w": 16, - "h": 16 - } - }, - { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 377, - "y": 275, - "w": 15, - "h": 11 - } - }, { "filename": "lucky_egg", "rotated": false, @@ -7080,8 +7038,8 @@ "h": 20 }, "frame": { - "x": 381, - "y": 286, + "x": 389, + "y": 325, "w": 17, "h": 20 } @@ -7101,8 +7059,8 @@ "h": 18 }, "frame": { - "x": 398, - "y": 277, + "x": 352, + "y": 343, "w": 20, "h": 18 } @@ -7122,8 +7080,8 @@ "h": 18 }, "frame": { - "x": 398, - "y": 295, + "x": 372, + "y": 345, "w": 20, "h": 18 } @@ -7143,8 +7101,8 @@ "h": 18 }, "frame": { - "x": 393, - "y": 313, + "x": 392, + "y": 345, "w": 20, "h": 18 } @@ -7164,14 +7122,14 @@ "h": 18 }, "frame": { - "x": 240, - "y": 340, + "x": 378, + "y": 241, "w": 20, "h": 18 } }, { - "filename": "banettite", + "filename": "relic_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -7179,16 +7137,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 + "x": 9, + "y": 11, + "w": 15, + "h": 11 }, "frame": { - "x": 413, - "y": 313, - "w": 16, - "h": 16 + "x": 398, + "y": 241, + "w": 15, + "h": 11 } }, { @@ -7206,8 +7164,8 @@ "h": 18 }, "frame": { - "x": 202, - "y": 358, + "x": 377, + "y": 259, "w": 20, "h": 18 } @@ -7227,8 +7185,8 @@ "h": 18 }, "frame": { - "x": 201, - "y": 376, + "x": 381, + "y": 277, "w": 20, "h": 18 } @@ -7248,8 +7206,8 @@ "h": 18 }, "frame": { - "x": 201, - "y": 394, + "x": 397, + "y": 259, "w": 20, "h": 18 } @@ -7269,33 +7227,12 @@ "h": 18 }, "frame": { - "x": 201, - "y": 412, + "x": 401, + "y": 277, "w": 20, "h": 18 } }, - { - "filename": "beedrillite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 222, - "y": 357, - "w": 16, - "h": 16 - } - }, { "filename": "wl_ice_heal", "rotated": false, @@ -7311,14 +7248,14 @@ "h": 18 }, "frame": { - "x": 238, - "y": 358, + "x": 395, + "y": 295, "w": 20, "h": 18 } }, { - "filename": "blastoisinite", + "filename": "ampharosite", "rotated": false, "trimmed": true, "sourceSize": { @@ -7332,8 +7269,29 @@ "h": 16 }, "frame": { - "x": 222, - "y": 373, + "x": 415, + "y": 295, + "w": 16, + "h": 16 + } + }, + { + "filename": "audinite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 415, + "y": 311, "w": 16, "h": 16 } @@ -7353,12 +7311,33 @@ "h": 18 }, "frame": { - "x": 221, - "y": 389, + "x": 406, + "y": 327, "w": 20, "h": 18 } }, + { + "filename": "banettite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 412, + "y": 345, + "w": 16, + "h": 16 + } + }, { "filename": "wl_item_urge", "rotated": false, @@ -7375,7 +7354,7 @@ }, "frame": { "x": 221, - "y": 407, + "y": 357, "w": 20, "h": 18 } @@ -7396,7 +7375,7 @@ }, "frame": { "x": 241, - "y": 376, + "y": 358, "w": 20, "h": 18 } @@ -7416,8 +7395,8 @@ "h": 18 }, "frame": { - "x": 241, - "y": 394, + "x": 201, + "y": 360, "w": 20, "h": 18 } @@ -7437,8 +7416,8 @@ "h": 18 }, "frame": { - "x": 241, - "y": 412, + "x": 201, + "y": 378, "w": 20, "h": 18 } @@ -7458,8 +7437,8 @@ "h": 18 }, "frame": { - "x": 258, - "y": 358, + "x": 221, + "y": 375, "w": 20, "h": 18 } @@ -7479,8 +7458,8 @@ "h": 18 }, "frame": { - "x": 261, - "y": 376, + "x": 201, + "y": 396, "w": 20, "h": 18 } @@ -7500,8 +7479,8 @@ "h": 18 }, "frame": { - "x": 261, - "y": 394, + "x": 221, + "y": 393, "w": 20, "h": 18 } @@ -7521,8 +7500,8 @@ "h": 18 }, "frame": { - "x": 261, - "y": 412, + "x": 241, + "y": 376, "w": 20, "h": 18 } @@ -7542,12 +7521,33 @@ "h": 18 }, "frame": { - "x": 278, - "y": 345, + "x": 241, + "y": 394, "w": 20, "h": 18 } }, + { + "filename": "beedrillite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 201, + "y": 414, + "w": 16, + "h": 16 + } + }, { "filename": "wl_super_potion", "rotated": false, @@ -7563,12 +7563,33 @@ "h": 18 }, "frame": { - "x": 298, + "x": 261, "y": 345, "w": 20, "h": 18 } }, + { + "filename": "blastoisinite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 261, + "y": 363, + "w": 16, + "h": 16 + } + }, { "filename": "blazikenite", "rotated": false, @@ -7584,8 +7605,8 @@ "h": 16 }, "frame": { - "x": 318, - "y": 344, + "x": 281, + "y": 345, "w": 16, "h": 16 } @@ -7605,8 +7626,8 @@ "h": 16 }, "frame": { - "x": 334, - "y": 326, + "x": 261, + "y": 379, "w": 16, "h": 16 } @@ -7626,8 +7647,8 @@ "h": 16 }, "frame": { - "x": 334, - "y": 342, + "x": 297, + "y": 345, "w": 16, "h": 16 } @@ -7647,8 +7668,8 @@ "h": 16 }, "frame": { - "x": 350, - "y": 325, + "x": 261, + "y": 395, "w": 16, "h": 16 } @@ -7668,8 +7689,8 @@ "h": 16 }, "frame": { - "x": 350, - "y": 341, + "x": 313, + "y": 345, "w": 16, "h": 16 } @@ -7689,8 +7710,8 @@ "h": 16 }, "frame": { - "x": 366, - "y": 327, + "x": 217, + "y": 414, "w": 16, "h": 16 } @@ -7710,8 +7731,8 @@ "h": 16 }, "frame": { - "x": 366, - "y": 343, + "x": 233, + "y": 412, "w": 16, "h": 16 } @@ -7731,8 +7752,8 @@ "h": 16 }, "frame": { - "x": 382, - "y": 331, + "x": 249, + "y": 412, "w": 16, "h": 16 } @@ -7752,8 +7773,8 @@ "h": 16 }, "frame": { - "x": 398, - "y": 331, + "x": 265, + "y": 411, "w": 16, "h": 16 } @@ -7773,8 +7794,8 @@ "h": 16 }, "frame": { - "x": 414, - "y": 329, + "x": 329, + "y": 345, "w": 16, "h": 16 } @@ -7794,8 +7815,8 @@ "h": 16 }, "frame": { - "x": 382, - "y": 347, + "x": 277, + "y": 363, "w": 16, "h": 16 } @@ -7815,8 +7836,8 @@ "h": 16 }, "frame": { - "x": 398, - "y": 347, + "x": 277, + "y": 379, "w": 16, "h": 16 } @@ -7836,8 +7857,8 @@ "h": 16 }, "frame": { - "x": 414, - "y": 345, + "x": 277, + "y": 395, "w": 16, "h": 16 } @@ -7857,8 +7878,8 @@ "h": 16 }, "frame": { - "x": 281, - "y": 363, + "x": 293, + "y": 361, "w": 16, "h": 16 } @@ -7878,8 +7899,8 @@ "h": 16 }, "frame": { - "x": 281, - "y": 379, + "x": 309, + "y": 361, "w": 16, "h": 16 } @@ -7899,8 +7920,8 @@ "h": 16 }, "frame": { - "x": 297, - "y": 363, + "x": 293, + "y": 377, "w": 16, "h": 16 } @@ -7920,8 +7941,8 @@ "h": 16 }, "frame": { - "x": 281, - "y": 395, + "x": 325, + "y": 361, "w": 16, "h": 16 } @@ -7941,8 +7962,8 @@ "h": 16 }, "frame": { - "x": 297, - "y": 379, + "x": 293, + "y": 393, "w": 16, "h": 16 } @@ -7961,6 +7982,90 @@ "w": 16, "h": 16 }, + "frame": { + "x": 309, + "y": 377, + "w": 16, + "h": 16 + } + }, + { + "filename": "mawilite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 309, + "y": 393, + "w": 16, + "h": 16 + } + }, + { + "filename": "medichamite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 325, + "y": 377, + "w": 16, + "h": 16 + } + }, + { + "filename": "metagrossite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 325, + "y": 393, + "w": 16, + "h": 16 + } + }, + { + "filename": "mewtwonite_x", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, "frame": { "x": 281, "y": 411, @@ -7968,90 +8073,6 @@ "h": 16 } }, - { - "filename": "mawilite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 297, - "y": 395, - "w": 16, - "h": 16 - } - }, - { - "filename": "medichamite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 297, - "y": 411, - "w": 16, - "h": 16 - } - }, - { - "filename": "metagrossite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 313, - "y": 363, - "w": 16, - "h": 16 - } - }, - { - "filename": "mewtwonite_x", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 313, - "y": 379, - "w": 16, - "h": 16 - } - }, { "filename": "mewtwonite_y", "rotated": false, @@ -8067,8 +8088,8 @@ "h": 16 }, "frame": { - "x": 313, - "y": 395, + "x": 297, + "y": 409, "w": 16, "h": 16 } @@ -8089,7 +8110,7 @@ }, "frame": { "x": 313, - "y": 411, + "y": 409, "w": 16, "h": 16 } @@ -8109,8 +8130,8 @@ "h": 16 }, "frame": { - "x": 350, - "y": 357, + "x": 329, + "y": 409, "w": 16, "h": 16 } @@ -8130,8 +8151,8 @@ "h": 16 }, "frame": { - "x": 366, - "y": 359, + "x": 341, + "y": 361, "w": 16, "h": 16 } @@ -8151,8 +8172,8 @@ "h": 16 }, "frame": { - "x": 334, - "y": 358, + "x": 341, + "y": 377, "w": 16, "h": 16 } @@ -8172,8 +8193,8 @@ "h": 16 }, "frame": { - "x": 382, - "y": 363, + "x": 341, + "y": 393, "w": 16, "h": 16 } @@ -8193,8 +8214,8 @@ "h": 16 }, "frame": { - "x": 398, - "y": 363, + "x": 345, + "y": 409, "w": 16, "h": 16 } @@ -8214,7 +8235,7 @@ "h": 16 }, "frame": { - "x": 414, + "x": 412, "y": 361, "w": 16, "h": 16 @@ -8235,8 +8256,8 @@ "h": 16 }, "frame": { - "x": 329, - "y": 374, + "x": 357, + "y": 363, "w": 16, "h": 16 } @@ -8256,8 +8277,8 @@ "h": 16 }, "frame": { - "x": 329, - "y": 390, + "x": 357, + "y": 379, "w": 16, "h": 16 } @@ -8277,8 +8298,8 @@ "h": 16 }, "frame": { - "x": 329, - "y": 406, + "x": 373, + "y": 363, "w": 16, "h": 16 } @@ -8298,8 +8319,8 @@ "h": 16 }, "frame": { - "x": 345, - "y": 374, + "x": 373, + "y": 379, "w": 16, "h": 16 } @@ -8319,8 +8340,8 @@ "h": 16 }, "frame": { - "x": 345, - "y": 390, + "x": 389, + "y": 363, "w": 16, "h": 16 } @@ -8340,8 +8361,8 @@ "h": 16 }, "frame": { - "x": 345, - "y": 406, + "x": 389, + "y": 379, "w": 16, "h": 16 } @@ -8361,8 +8382,8 @@ "h": 16 }, "frame": { - "x": 361, - "y": 375, + "x": 405, + "y": 377, "w": 16, "h": 16 } @@ -8383,7 +8404,7 @@ }, "frame": { "x": 361, - "y": 391, + "y": 395, "w": 16, "h": 16 } @@ -8403,8 +8424,8 @@ "h": 16 }, "frame": { - "x": 361, - "y": 407, + "x": 377, + "y": 395, "w": 16, "h": 16 } @@ -8415,6 +8436,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:9ef21166268f7487fc9ff8d0f9b996e4:82658ac7bdd4c2b417e1f59168179262:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:875c6d67e72590dfc6d319101aa31cfa:dd2bb865ecbc5ac7b975ddf70b993334:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 8aaa0281c0088a4b0ded764af22c3d5456ce167f..1bd7b3af9c3314850fba4eed749f7e3aaf46d8f0 100644 GIT binary patch literal 58657 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 VnKdzxs!0I6wACM})u>HkJz_A)z9D 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 diff --git a/public/images/items/pb_silver.png b/public/images/items/pb_silver.png new file mode 100644 index 0000000000000000000000000000000000000000..f60a8348a94de2e587a94a66e2d0b4336b25763d GIT binary patch literal 556 zcmV+{0@MA8P)Px$=1D|BR9J=Wmd{G#Kpe+E{iBGD(%MtqOM6a2)4_jWw)gr4>f6Ol_aguOTIA7OlIcy{p6R)B;d-G zt0BwN=Q{CT@tiIY09vK(U-z{yK0N*bAUPd!9M=he(2b)ZC{#NGbzcYK_E(v;WZZUa zZ$IYdT9*_E0`MU+&2c6NZ$Bo-03uVazH0gwgsQ5xA#7zp4{T1m-q-g*zp?@_?%r%_ zu1A}_ixw9WwzFV&54;Ky4Yi9IqFSjKZB$amH3g=GcpxCq4On!Csb0>foV~!fNOt%2uJLj)H z7V`c9cAihl`lomP@z86!>@@t)3%E1ZZ$Xq}(@q~tZb!%L{a6Pv74CM0a}_L8or}6S zR5KZdt6hxImEv~SXcV_9sEwLssV*q=9$Dv{RdLb(Fzpv}GoeqE?kk_+TiBkx-&UIb&JYavlC?UY0EQ#Z8z3`e9qoXIwH>x=pqd z%35Sq>qmzv^CTe%oUfV}4yqwAZUt~i>7)61sNM}8P;br=s$(ZrlZK(vjAsUWM38U+ zr&)QP->kiGTmg*mJkJS+I`+I}KRnc`C{xKEdPLC}N;Oxf^~q{$aPvAo1Q<7u@*{@)RdMQ0{*wIZpce-YC+`B66=Hm#rS9 z%i`PcuPXOyFj)A1^nUO+-SD3k=fyMMs?i6of6#jWc(z?l<@v@Jr5k>0zjZ1vyuJtA y#ewheyXsUbi|VYIH!R!g?3LP&(Df*KfBywl*SaLA^$+XOa?;Me&zBUz_3=2Cwf6C~&~@LKwZ?SJ zE(wE97~16d?B;4H%K^`)c55OY#&D;a_3RAJ4PYgU)7YFM01p}4=;Tsp4yDdsA_GOq zHj$VF9zG>>tstHXDJ3?7#^!Pg8o5$8Hjza&V;TW-x*eovM&aRY_k_*ADM*R)`H4*PKWf!0(48sQn?===)i~112hN$mX3T1 zNb3q!MRVcoU^0@=a@~8`qj7$9tK=(GH*ofDuGS$J!DH*KY9U?MJ4kNh9R#?q2=(Ox zNzfGNF1y`8%XW2_-5!@i-9byY%H4I)C89N=CYraJyuF3a)e5zv?x3~#Z`4wE(AL~V zXGd>`^r#Le$9#<-=Y5X`@BKC?AC;htZMXHmsR`xnlLY!?+^B&cr~V77S8({jvAJ@F d&VQ%0%pa{9Auo9qX&wLo002ovPDHLkV1n*=KDGb= literal 0 HcmV?d00001 diff --git a/public/locales b/public/locales index 3ccef8472dd..87615556d8a 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 3ccef8472dd7cc7c362538489954cb8fdad27e5f +Subproject commit 87615556d8a2bd7eef7abac818f84423a8a13b03 diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index c838f6b2c49..7d0d86fadbf 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -10,7 +10,7 @@ import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { TimeOfDay } from "#enums/time-of-day"; -import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier } from "#app/modifier/modifier"; +import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; import { SpeciesFormKey } from "#enums/species-form-key"; @@ -1652,11 +1652,11 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter + p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length + p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier - || m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG), + || m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG), new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesEvolutionCondition(p => p.evoCounter + p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length + p.scene.findModifiers(m => m instanceof MoneyMultiplierModifier - || m instanceof ExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG) + || m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9), SpeciesWildEvolutionDelay.VERY_LONG) ] }; 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 8dc4eca25bf..1e20b73e351 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 @@ -1,4 +1,4 @@ -import { leaveEncounterWithoutBattle, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { generateModifierType, leaveEncounterWithoutBattle, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; @@ -14,6 +14,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import i18next from "i18next"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/anOfferYouCantRefuse"; @@ -98,6 +99,8 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = } } + const shinyCharm = generateModifierType(scene, modifierTypes.SHINY_CHARM); + encounter.setDialogueToken("itemName", shinyCharm?.name ?? i18next.t("modifierType:ModifierType.SHINY_CHARM.name")); encounter.setDialogueToken("liepardName", getPokemonSpecies(Species.LIEPARD).getName()); return true; @@ -123,7 +126,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = return true; }) .withOptionPhase(async (scene: BattleScene) => { - // Give the player a Shiny charm + // Give the player a Shiny Charm scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.SHINY_CHARM)); leaveEncounterWithoutBattle(scene, true); }) @@ -132,9 +135,11 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = .withOption( MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) - .withPrimaryPokemonRequirement(new CombinationPokemonRequirement( - new MoveRequirement(EXTORTION_MOVES, true), - new AbilityRequirement(EXTORTION_ABILITIES, true)) + .withPrimaryPokemonRequirement( + CombinationPokemonRequirement.Some( + new MoveRequirement(EXTORTION_MOVES, true), + new AbilityRequirement(EXTORTION_ABILITIES, true) + ) ) .withDialogue({ buttonLabel: `${namespace}:option.2.label`, diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index d316ab14cde..e24eadb56c7 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -193,12 +193,14 @@ const WAVE_LEVEL_BREAKPOINTS = [ 30, 50, 70, 100, 120, 140, 160 ]; export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.BUG_TYPE_SUPERFAN) .withEncounterTier(MysteryEncounterTier.GREAT) - .withPrimaryPokemonRequirement(new CombinationPokemonRequirement( - // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team - new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1), - new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1), - new TypeRequirement(Type.BUG, false, 1) - )) + .withPrimaryPokemonRequirement( + CombinationPokemonRequirement.Some( + // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team + new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1), + new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1), + new TypeRequirement(Type.BUG, false, 1) + ) + ) .withMaxAllowedEncounters(1) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withIntroSpriteConfigs([]) // These are set in onInit() @@ -405,11 +407,13 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = .build()) .withOption(MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) - .withPrimaryPokemonRequirement(new CombinationPokemonRequirement( - // Meets one or both of the below reqs - new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1), - new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1) - )) + .withPrimaryPokemonRequirement( + CombinationPokemonRequirement.Some( + // Meets one or both of the below reqs + new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1), + new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1) + ) + ) .withDialogue({ buttonLabel: `${namespace}:option.3.label`, buttonTooltip: `${namespace}:option.3.tooltip`, diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index 57c8aa7a561..c4b03660bde 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -11,7 +11,7 @@ import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Abilities } from "#enums/abilities"; -import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { applyAbilityOverrideToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { Type } from "#app/data/type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -425,17 +425,8 @@ function onYesAbilitySwap(scene: BattleScene, resolve) { const onPokemonSelected = (pokemon: PlayerPokemon) => { // Do ability swap const encounter = scene.currentBattle.mysteryEncounter!; - if (pokemon.isFusion()) { - if (!pokemon.fusionCustomPokemonData) { - pokemon.fusionCustomPokemonData = new CustomPokemonData(); - } - pokemon.fusionCustomPokemonData.ability = encounter.misc.ability; - } else { - if (!pokemon.customPokemonData) { - pokemon.customPokemonData = new CustomPokemonData(); - } - pokemon.customPokemonData.ability = encounter.misc.ability; - } + + applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability); encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender()); scene.ui.setMode(Mode.MESSAGE).then(() => resolve(true)); }; diff --git a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts index 2c13086ccb8..8a814b58248 100644 --- a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts +++ b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts @@ -14,6 +14,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { Challenges } from "#enums/challenges"; /** i18n namespace for encounter */ const namespace = "mysteryEncounters/darkDeal"; @@ -141,6 +142,7 @@ export const DarkDealEncounter: MysteryEncounter = // Removes random pokemon (including fainted) from party and adds name to dialogue data tokens // Will never return last battle able mon and instead pick fainted/unable to battle const removedPokemon = getRandomPlayerPokemon(scene, true, false, true); + // Get all the pokemon's held items const modifiers = removedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier)); scene.removePokemonFromPlayerParty(removedPokemon); @@ -160,7 +162,13 @@ export const DarkDealEncounter: MysteryEncounter = scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ROGUE_BALL)); // Start encounter with random legendary (7-10 starter strength) that has level additive - const bossTypes: Type[] = encounter.misc.removedTypes; + // If this is a mono-type challenge, always ensure the required type is filtered for + let bossTypes: Type[] = encounter.misc.removedTypes; + const singleTypeChallenges = scene.gameMode.challenges.filter(c => c.value && c.id === Challenges.SINGLE_TYPE); + if (scene.gameMode.isChallenge && singleTypeChallenges.length > 0) { + bossTypes = singleTypeChallenges.map(c => (c.value - 1) as Type); + } + const bossModifiers: PokemonHeldItemModifier[] = encounter.misc.modifiers; // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+ const roll = randSeedInt(100); diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 5686d0f6ce5..d5f9388b56c 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -45,10 +45,13 @@ export const DelibirdyEncounter: MysteryEncounter = .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneRequirement(new MoneyRequirement(0, DELIBIRDY_MONEY_PRICE_MULTIPLIER)) // Must have enough money for it to spawn at the very least - .withPrimaryPokemonRequirement(new CombinationPokemonRequirement( // Must also have either option 2 or 3 available to spawn - new HeldItemRequirement(OPTION_2_ALLOWED_MODIFIERS), - new HeldItemRequirement(OPTION_3_DISALLOWED_MODIFIERS, 1, true) - )) + .withPrimaryPokemonRequirement( + CombinationPokemonRequirement.Some( + // Must also have either option 2 or 3 available to spawn + new HeldItemRequirement(OPTION_2_ALLOWED_MODIFIERS), + new HeldItemRequirement(OPTION_3_DISALLOWED_MODIFIERS, 1, true) + ) + ) .withIntroSpriteConfigs([ { spriteKey: "", @@ -196,7 +199,7 @@ export const DelibirdyEncounter: MysteryEncounter = const encounter = scene.currentBattle.mysteryEncounter!; const modifier: BerryModifier | HealingBoosterModifier = encounter.misc.chosenModifier; - // Give the player a Candy Jar if they gave a Berry, and a Healing Charm for Reviver Seed + // Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed if (modifier instanceof BerryModifier) { // Check if the player has max stacks of that Candy Jar already const existing = scene.findModifier(m => m instanceof LevelIncrementBoosterModifier) as LevelIncrementBoosterModifier; @@ -211,8 +214,8 @@ export const DelibirdyEncounter: MysteryEncounter = scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR)); } } else { - // Check if the player has max stacks of that Healing Charm already - const existing = scene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier; + // Check if the player has max stacks of that Berry Pouch already + const existing = scene.findModifier(m => m instanceof PreserveBerryModifier) as PreserveBerryModifier; if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead @@ -221,7 +224,7 @@ export const DelibirdyEncounter: MysteryEncounter = scene.playSound("item_fanfare"); await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true); } else { - scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM)); + scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH)); } } @@ -290,8 +293,8 @@ export const DelibirdyEncounter: MysteryEncounter = const encounter = scene.currentBattle.mysteryEncounter!; const modifier = encounter.misc.chosenModifier; - // Check if the player has max stacks of Berry Pouch already - const existing = scene.findModifier(m => m instanceof PreserveBerryModifier) as PreserveBerryModifier; + // Check if the player has max stacks of Healing Charm already + const existing = scene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier; if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead @@ -300,7 +303,7 @@ export const DelibirdyEncounter: MysteryEncounter = scene.playSound("item_fanfare"); await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true); } else { - scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH)); + scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM)); } // Remove the modifier if its stacks go to 0 diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index d306206159a..5c16e5d8564 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -4,24 +4,30 @@ import { AttackTypeBoosterModifierType, modifierTypes, } from "#app/modifier/mod import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; -import { TypeRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; +import { AbilityRequirement, CombinationPokemonRequirement, TypeRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { Species } from "#enums/species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Gender } from "#app/data/gender"; import { Type } from "#app/data/type"; import { BattlerIndex } from "#app/battle"; -import { PokemonMove } from "#app/field/pokemon"; +import Pokemon, { PokemonMove } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { EncounterBattleAnim } from "#app/data/battle-anims"; import { WeatherType } from "#app/data/weather"; import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { StatusEffect } from "#app/data/status-effect"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { applyDamageToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { applyAbilityOverrideToPokemon, applyDamageToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { EncounterAnim } from "#enums/encounter-anims"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; +import { Stat } from "#enums/stat"; +import { Ability } from "#app/data/ability"; +import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/fieryFallout"; @@ -62,16 +68,24 @@ export const FieryFalloutEncounter: MysteryEncounter = { species: volcaronaSpecies, isBoss: false, - gender: Gender.MALE + gender: Gender.MALE, + tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ], + mysteryEncounterBattleEffects: (pokemon: Pokemon) => { + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1)); + } }, { species: volcaronaSpecies, isBoss: false, - gender: Gender.FEMALE + gender: Gender.FEMALE, + tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ], + mysteryEncounterBattleEffects: (pokemon: Pokemon) => { + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPDEF, Stat.SPD ], 1)); + } } ], doubleBattle: true, - disableSwitch: true + disableSwitch: true, }; encounter.enemyPartyConfigs = [ config ]; @@ -139,7 +153,7 @@ export const FieryFalloutEncounter: MysteryEncounter = async (scene: BattleScene) => { // Pick battle const encounter = scene.currentBattle.mysteryEncounter!; - setEncounterRewards(scene, { fillRemaining: true }, undefined, () => giveLeadPokemonCharcoal(scene)); + setEncounterRewards(scene, { fillRemaining: true }, undefined, () => giveLeadPokemonAttackTypeBoostItem(scene)); encounter.startOfBattleEffects.push( { @@ -153,18 +167,6 @@ export const FieryFalloutEncounter: MysteryEncounter = targets: [ BattlerIndex.PLAYER_2 ], move: new PokemonMove(Moves.FIRE_SPIN), ignorePp: true - }, - { - sourceBattlerIndex: BattlerIndex.ENEMY, - targets: [ BattlerIndex.ENEMY ], - move: new PokemonMove(Moves.QUIVER_DANCE), - ignorePp: true - }, - { - sourceBattlerIndex: BattlerIndex.ENEMY_2, - targets: [ BattlerIndex.ENEMY_2 ], - move: new PokemonMove(Moves.QUIVER_DANCE), - ignorePp: true }); await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]); } @@ -180,7 +182,7 @@ export const FieryFalloutEncounter: MysteryEncounter = ], }, async (scene: BattleScene) => { - // Damage non-fire types and burn 1 random non-fire type member + // Damage non-fire types and burn 1 random non-fire type member + give it Heatproof const encounter = scene.currentBattle.mysteryEncounter!; const nonFireTypes = scene.getParty().filter((p) => p.isAllowedInBattle() && !p.getTypes().includes(Type.FIRE)); @@ -198,7 +200,11 @@ export const FieryFalloutEncounter: MysteryEncounter = if (chosenPokemon.trySetStatus(StatusEffect.BURN)) { // Burn applied encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender()); + encounter.setDialogueToken("abilityName", new Ability(Abilities.HEATPROOF, 3).name); queueEncounterMessage(scene, `${namespace}:option.2.target_burned`); + + // Also permanently change the burned Pokemon's ability to Heatproof + applyAbilityOverrideToPokemon(chosenPokemon, Abilities.HEATPROOF); } } @@ -209,8 +215,12 @@ export const FieryFalloutEncounter: MysteryEncounter = .withOption( MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) - .withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3PrimaryName dialogue token automatically - .withSecondaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3SecondaryName dialogue token automatically + .withPrimaryPokemonRequirement( + CombinationPokemonRequirement.Some( + new TypeRequirement(Type.FIRE, true, 1), + new AbilityRequirement(FIRE_RESISTANT_ABILITIES, true) + ) + ) // Will set option3PrimaryName dialogue token automatically .withDialogue({ buttonLabel: `${namespace}:option.3.label`, buttonTooltip: `${namespace}:option.3.tooltip`, @@ -233,26 +243,32 @@ export const FieryFalloutEncounter: MysteryEncounter = { fillRemaining: true }, undefined, () => { - giveLeadPokemonCharcoal(scene); + giveLeadPokemonAttackTypeBoostItem(scene); }); const primary = encounter.options[2].primaryPokemon!; - const secondary = encounter.options[2].secondaryPokemon![0]; - setEncounterExp(scene, [ primary.id, secondary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2); + setEncounterExp(scene, [ primary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2); leaveEncounterWithoutBattle(scene); }) .build() ) .build(); -function giveLeadPokemonCharcoal(scene: BattleScene) { - // Give first party pokemon Charcoal for free at end of battle +function giveLeadPokemonAttackTypeBoostItem(scene: BattleScene) { + // Give first party pokemon attack type boost item for free at end of battle const leadPokemon = scene.getParty()?.[0]; if (leadPokemon) { - const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType; - applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal); - scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender()); - queueEncounterMessage(scene, `${namespace}:found_charcoal`); + // Generate type booster held item, default to Charcoal if item fails to generate + let boosterModifierType = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER) as AttackTypeBoosterModifierType; + if (!boosterModifierType) { + boosterModifierType = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType; + } + applyModifierTypeToPlayerPokemon(scene, leadPokemon, boosterModifierType); + + const encounter = scene.currentBattle.mysteryEncounter!; + encounter.setDialogueToken("itemName", boosterModifierType.name); + encounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender()); + queueEncounterMessage(scene, `${namespace}:found_item`); } } diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index f282064bb94..7fdd29d36a2 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -56,7 +56,13 @@ export const MysteriousChallengersEncounter: MysteryEncounter = // Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config // Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100 - const hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex); + let retries = 0; + let hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex); + while (retries < 5 && hardTrainerType === normalTrainerType) { + // Will try to use a different trainer from the normal trainer type + hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex); + retries++; + } const hardTemplate = new TrainerPartyCompoundTemplate( new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true), new TrainerPartyTemplate( 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 d30c97b27de..8dd730492b1 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -21,7 +21,7 @@ import i18next from "i18next"; const namespace = "mysteryEncounters/shadyVitaminDealer"; const VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER = 1.5; -const VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER = 3.5; +const VITAMIN_DEALER_EXPENSIVE_PRICE_MULTIPLIER = 5; /** * Shady Vitamin Dealer encounter. diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 9c10d33d019..610209f8aad 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -222,7 +222,10 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = encounter.misc.chosenPokemon = pokemon1; encounter.setDialogueToken("chosenPokemon", pokemon1.getNameToRender()); const eggOptions = getEggOptions(scene, pokemon1CommonEggs, pokemon1RareEggs); - setEncounterRewards(scene, { fillRemaining: true }, eggOptions, () => doPostEncounterCleanup(scene)); + setEncounterRewards(scene, + { guaranteedModifierTypeFuncs: [ modifierTypes.SOOTHE_BELL ], fillRemaining: true }, + eggOptions, + () => doPostEncounterCleanup(scene)); // Remove all Pokemon from the party except the chosen Pokemon removePokemonFromPartyAndStoreHeldItems(scene, encounter, pokemon1); @@ -271,7 +274,10 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = encounter.misc.chosenPokemon = pokemon2; encounter.setDialogueToken("chosenPokemon", pokemon2.getNameToRender()); const eggOptions = getEggOptions(scene, pokemon2CommonEggs, pokemon2RareEggs); - setEncounterRewards(scene, { fillRemaining: true }, eggOptions, () => doPostEncounterCleanup(scene)); + setEncounterRewards(scene, + { guaranteedModifierTypeFuncs: [ modifierTypes.SOOTHE_BELL ], fillRemaining: true }, + eggOptions, + () => doPostEncounterCleanup(scene)); // Remove all Pokemon from the party except the chosen Pokemon removePokemonFromPartyAndStoreHeldItems(scene, encounter, pokemon2); @@ -320,7 +326,10 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = encounter.misc.chosenPokemon = pokemon3; encounter.setDialogueToken("chosenPokemon", pokemon3.getNameToRender()); const eggOptions = getEggOptions(scene, pokemon3CommonEggs, pokemon3RareEggs); - setEncounterRewards(scene, { fillRemaining: true }, eggOptions, () => doPostEncounterCleanup(scene)); + setEncounterRewards(scene, + { guaranteedModifierTypeFuncs: [ modifierTypes.SOOTHE_BELL ], fillRemaining: true }, + eggOptions, + () => doPostEncounterCleanup(scene)); // Remove all Pokemon from the party except the chosen Pokemon removePokemonFromPartyAndStoreHeldItems(scene, encounter, pokemon3); @@ -454,12 +463,16 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number] } // Maximum of 30 points - const totalPoints = Math.min(pointsFromStarterTier + pointsFromBst, 30); + let totalPoints = Math.min(pointsFromStarterTier + pointsFromBst, 30); - // 1 Rare egg for every 6 points - const numRares = Math.floor(totalPoints / 6); + // First 5 points go to Common eggs + let numCommons = Math.min(totalPoints, 5); + totalPoints -= numCommons; + + // Then, 1 Rare egg for every 4 points + const numRares = Math.floor(totalPoints / 4); // 1 Common egg for every point leftover - const numCommons = totalPoints % 6; + numCommons += totalPoints % 4; return [ numCommons, numRares ]; } diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index 9f80bbbffde..03341a713f2 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -37,6 +37,7 @@ export const TrainingSessionEncounter: MysteryEncounter = .withScenePartySizeRequirement(2, 6, true) // Must have at least 2 unfainted pokemon in party .withFleeAllowed(false) .withHideWildIntroMessage(true) + .withPreventGameStatsUpdates(true) // Do not count the Pokemon as seen or defeated since it is ours .withIntroSpriteConfigs([ { spriteKey: "training_session_gear", 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 2b3b38b2164..d3c16ce2122 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -71,7 +71,7 @@ export const TrashToTreasureEncounter: MysteryEncounter = moveSet: [ Moves.PAYBACK, Moves.GUNK_SHOT, Moves.STOMPING_TANTRUM, Moves.DRAIN_PUNCH ] }; const config: EnemyPartyConfig = { - levelAdditiveModifier: 1, + levelAdditiveModifier: 0.5, pokemonConfigs: [ pokemonConfig ], disableSwitch: true }; diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index b97a22dbe51..2ecba6ce658 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -4,23 +4,30 @@ import { Species } from "#enums/species"; import BattleScene from "#app/battle-scene"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { leaveEncounterWithoutBattle, setEncounterRewards, } from "../utils/encounter-phase-utils"; +import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, } from "../utils/encounter-phase-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; +import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { IntegerHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { achvs } from "#app/system/achv"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { modifierTypes } from "#app/modifier/modifier-type"; +import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; import { doPokemonTransformationSequence, TransformationScreenPosition } from "#app/data/mystery-encounters/utils/encounter-transformation-sequence"; import { getLevelTotalExp } from "#app/data/exp"; import { Stat } from "#enums/stat"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { Challenges } from "#enums/challenges"; +import { ModifierTier } from "#app/modifier/modifier-tier"; +import { PlayerGender } from "#enums/player-gender"; +import { TrainerType } from "#enums/trainer-type"; +import PokemonData from "#app/system/pokemon-data"; +import { Nature } from "#enums/nature"; +import HeldModifierConfig from "#app/interfaces/held-modifier-config"; +import { trainerConfigs, TrainerPartyTemplate } from "#app/data/trainer-config"; +import { PartyMemberStrength } from "#enums/party-member-strength"; /** i18n namespace for encounter */ const namespace = "mysteryEncounters/weirdDream"; @@ -80,10 +87,11 @@ const EXCLUDED_TRANSFORMATION_SPECIES = [ const SUPER_LEGENDARY_BST_THRESHOLD = 600; const NON_LEGENDARY_BST_THRESHOLD = 570; -const GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD = 450; + +const OLD_GATEAU_STATS_UP = 20; /** 0-100 */ -const PERCENT_LEVEL_LOSS_ON_REFUSE = 12.5; +const PERCENT_LEVEL_LOSS_ON_REFUSE = 10; /** * Value ranges of the resulting species BST transformations after adding values to original species @@ -105,7 +113,8 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.WEIRD_DREAM) .withEncounterTier(MysteryEncounterTier.ROGUE) .withDisallowedChallenges(Challenges.SINGLE_TYPE, Challenges.SINGLE_GENERATION) - .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + // TODO: should reset minimum wave to 10 when there are more Rogue tiers in pool. Matching Dark Deal minimum for now. + .withSceneWaveRangeRequirement(30, 140) .withIntroSpriteConfigs([ { spriteKey: "weird_dream_woman", @@ -131,6 +140,15 @@ export const WeirdDreamEncounter: MysteryEncounter = .withQuery(`${namespace}:query`) .withOnInit((scene: BattleScene) => { scene.loadBgm("mystery_encounter_weird_dream", "mystery_encounter_weird_dream.mp3"); + + // Calculate all the newly transformed Pokemon and begin asset load + const teamTransformations = getTeamTransformations(scene); + const loadAssets = teamTransformations.map(t => (t.newPokemon as PlayerPokemon).loadAssets()); + scene.currentBattle.mysteryEncounter!.misc = { + teamTransformations, + loadAssets + }; + return true; }) .withOnVisualsStart((scene: BattleScene) => { @@ -156,13 +174,10 @@ export const WeirdDreamEncounter: MysteryEncounter = doShowDreamBackground(scene); }); - // Calculate all the newly transformed Pokemon and begin asset load - const teamTransformations = getTeamTransformations(scene); - const loadAssets = teamTransformations.map(t => (t.newPokemon as PlayerPokemon).loadAssets()); - scene.currentBattle.mysteryEncounter!.misc = { - teamTransformations, - loadAssets - }; + for (const transformation of scene.currentBattle.mysteryEncounter!.misc.teamTransformations) { + scene.removePokemonFromPlayerParty(transformation.previousPokemon, false); + scene.getParty().push(transformation.newPokemon); + } }) .withOptionPhase(async (scene: BattleScene) => { // Starts cutscene dialogue, but does not await so that cutscene plays as player goes through dialogue @@ -193,7 +208,7 @@ export const WeirdDreamEncounter: MysteryEncounter = await showEncounterText(scene, `${namespace}:option.1.dream_complete`); await doNewTeamPostProcess(scene, transformations); - setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT ]}); + setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT, modifierTypes.MINT ], fillRemaining: false }); leaveEncounterWithoutBattle(scene, true); }) .build() @@ -209,7 +224,88 @@ export const WeirdDreamEncounter: MysteryEncounter = ], }, async (scene: BattleScene) => { - // Reduce party levels by 20% + // Battle your "future" team for some item rewards + const transformations: PokemonTransformation[] = scene.currentBattle.mysteryEncounter!.misc.teamTransformations; + + // Uses the pokemon that player's party would have transformed into + const enemyPokemonConfigs: EnemyPokemonConfig[] = []; + for (const transformation of transformations) { + const newPokemon = transformation.newPokemon; + const previousPokemon = transformation.previousPokemon; + + await postProcessTransformedPokemon(scene, previousPokemon, newPokemon, newPokemon.species.getRootSpeciesId(), true); + + const dataSource = new PokemonData(newPokemon); + dataSource.player = false; + + // Copy held items to new pokemon + const newPokemonHeldItemConfigs: HeldModifierConfig[] = []; + for (const item of transformation.heldItems) { + newPokemonHeldItemConfigs.push({ + modifier: item.clone() as PokemonHeldItemModifier, + stackCount: item.getStackCount(), + isTransferable: false + }); + } + // Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats + if (shouldGetOldGateau(newPokemon)) { + const stats = getOldGateauBoostedStats(newPokemon); + newPokemonHeldItemConfigs.push({ + modifier: generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU, [ OLD_GATEAU_STATS_UP, stats ]) as PokemonHeldItemModifierType, + stackCount: 1, + isTransferable: false + }); + } + + const enemyConfig: EnemyPokemonConfig = { + species: transformation.newSpecies, + isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD, + level: previousPokemon.level, + dataSource: dataSource, + modifierConfigs: newPokemonHeldItemConfigs + }; + + enemyPokemonConfigs.push(enemyConfig); + } + + const genderIndex = scene.gameData.gender ?? PlayerGender.UNSET; + const trainerConfig = trainerConfigs[genderIndex === PlayerGender.FEMALE ? TrainerType.FUTURE_SELF_F : TrainerType.FUTURE_SELF_M].clone(); + trainerConfig.setPartyTemplates(new TrainerPartyTemplate(transformations.length, PartyMemberStrength.STRONG)); + const enemyPartyConfig: EnemyPartyConfig = { + trainerConfig: trainerConfig, + pokemonConfigs: enemyPokemonConfigs, + female: genderIndex === PlayerGender.FEMALE + }; + + const onBeforeRewards = () => { + // Before battle rewards, unlock the passive on a pokemon in the player's team for the rest of the run (not permanently) + // One random pokemon will get its passive unlocked + const passiveDisabledPokemon = scene.getParty().filter(p => !p.passive); + if (passiveDisabledPokemon?.length > 0) { + const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)]; + enablePassiveMon.passive = true; + enablePassiveMon.updateInfo(true); + } + }; + + setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: false }, undefined, onBeforeRewards); + + await showEncounterText(scene, `${namespace}:option.2.selected_2`, null, undefined, true); + await initBattleWithEnemyConfig(scene, enemyPartyConfig); + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}:option.3.label`, + buttonTooltip: `${namespace}:option.3.tooltip`, + selected: [ + { + text: `${namespace}:option.3.selected`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave, reduce party levels by 10% for (const pokemon of scene.getParty()) { pokemon.level = Math.max(Math.ceil((100 - PERCENT_LEVEL_LOSS_ON_REFUSE) / 100 * pokemon.level), 1); pokemon.exp = getLevelTotalExp(pokemon.level, pokemon.species.growthRate); @@ -235,7 +331,7 @@ interface PokemonTransformation { function getTeamTransformations(scene: BattleScene): PokemonTransformation[] { const party = scene.getParty(); // Removes all pokemon from the party - const alreadyUsedSpecies: PokemonSpecies[] = []; + const alreadyUsedSpecies: PokemonSpecies[] = party.map(p => p.species); const pokemonTransformations: PokemonTransformation[] = party.map(p => { return { previousPokemon: p @@ -250,11 +346,11 @@ function getTeamTransformations(scene: BattleScene): PokemonTransformation[] { // First, roll 2 of the party members to new Pokemon at a +90 to +110 BST difference // Then, roll the remainder of the party members at a +40 to +50 BST difference const numPokemon = party.length; + const removedPokemon = randSeedShuffle(party.slice(0)); for (let i = 0; i < numPokemon; i++) { - const removed = party[randSeedInt(party.length)]; + const removed = removedPokemon[i]; const index = pokemonTransformations.findIndex(p => p.previousPokemon.id === removed.id); pokemonTransformations[index].heldItems = removed.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier)); - scene.removePokemonFromPlayerParty(removed, false); const bst = removed.calculateBaseStats().reduce((a, b) => a + b, 0); let newBstRange: [number, number]; @@ -276,14 +372,13 @@ function getTeamTransformations(scene: BattleScene): PokemonTransformation[] { pokemonTransformations[index].newSpecies = newSpecies; + console.log("New species: " + JSON.stringify(newSpecies)); alreadyUsedSpecies.push(newSpecies); } for (const transformation of pokemonTransformations) { const newAbilityIndex = randSeedInt(transformation.newSpecies.getAbilityCount()); - const newPlayerPokemon = scene.addPlayerPokemon(transformation.newSpecies, transformation.previousPokemon.level, newAbilityIndex, undefined); - transformation.newPokemon = newPlayerPokemon; - scene.getParty().push(newPlayerPokemon); + transformation.newPokemon = scene.addPlayerPokemon(transformation.newSpecies, transformation.previousPokemon.level, newAbilityIndex, undefined); } return pokemonTransformations; @@ -296,109 +391,20 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon const newPokemon = transformation.newPokemon; const speciesRootForm = newPokemon.species.getRootSpeciesId(); - // Roll HA a second time - if (newPokemon.species.abilityHidden) { - const hiddenIndex = newPokemon.species.ability2 ? 2 : 1; - if (newPokemon.abilityIndex < hiddenIndex) { - const hiddenAbilityChance = new IntegerHolder(256); - scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance); - - const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value); - - if (hasHiddenAbility) { - newPokemon.abilityIndex = hiddenIndex; - } - } + if (await postProcessTransformedPokemon(scene, previousPokemon, newPokemon, speciesRootForm)) { + atLeastOneNewStarter = true; } - // Roll IVs a second time - newPokemon.ivs = newPokemon.ivs.map(iv => { - const newValue = randSeedInt(31); - return newValue > iv ? newValue : iv; - }); - - // For pokemon at/below 570 BST or any shiny pokemon, unlock it permanently as if you had caught it - if (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny()) { - if (newPokemon.getSpeciesForm().abilityHidden && newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1) { - scene.validateAchv(achvs.HIDDEN_ABILITY); - } - - if (newPokemon.species.subLegendary) { - scene.validateAchv(achvs.CATCH_SUB_LEGENDARY); - } - - if (newPokemon.species.legendary) { - scene.validateAchv(achvs.CATCH_LEGENDARY); - } - - if (newPokemon.species.mythical) { - scene.validateAchv(achvs.CATCH_MYTHICAL); - } - - scene.gameData.updateSpeciesDexIvs(newPokemon.species.getRootSpeciesId(true), newPokemon.ivs); - const newStarterUnlocked = await scene.gameData.setPokemonCaught(newPokemon, true, false, false); - if (newStarterUnlocked) { - atLeastOneNewStarter = true; - await showEncounterText(scene, i18next.t("battle:addedAsAStarter", { pokemonName: getPokemonSpecies(speciesRootForm).getName() })); - } - } - - // If the previous pokemon had pokerus, transfer to new pokemon - newPokemon.pokerus = previousPokemon.pokerus; - - // Transfer previous Pokemon's luck value - newPokemon.luck = previousPokemon.getLuck(); - - // If the previous pokemon had higher IVs, override to those (after updating dex IVs > prevents perfect 31s on a new unlock) - newPokemon.ivs = newPokemon.ivs.map((iv, index) => { - return previousPokemon.ivs[index] > iv ? previousPokemon.ivs[index] : iv; - }); - - // For pokemon that the player owns (including ones just caught), gain a candy - if (!!scene.gameData.dexData[speciesRootForm].caughtAttr) { - scene.gameData.addStarterCandy(getPokemonSpecies(speciesRootForm), 1); - } - - // Set the moveset of the new pokemon to be the same as previous, but with 1 egg move and 1 (attempted) STAB move of the new species - newPokemon.generateAndPopulateMoveset(); - // Store a copy of a "standard" generated moveset for the new pokemon, will be used later for finding a favored move - const newPokemonGeneratedMoveset = newPokemon.moveset; - - newPokemon.moveset = previousPokemon.moveset; - - const newEggMoveIndex = await addEggMoveToNewPokemonMoveset(scene, newPokemon, speciesRootForm); - - // Try to add a favored STAB move (might fail if Pokemon already knows a bunch of moves from newPokemonGeneratedMoveset) - addFavoredMoveToNewPokemonMoveset(newPokemon, newPokemonGeneratedMoveset, newEggMoveIndex); - - // Randomize the second type of the pokemon - // If the pokemon does not normally have a second type, it will gain 1 - const newTypes = [ newPokemon.getTypes()[0] ]; - let newType = randSeedInt(18) as Type; - while (newType === newTypes[0]) { - newType = randSeedInt(18) as Type; - } - newTypes.push(newType); - if (!newPokemon.customPokemonData) { - newPokemon.customPokemonData = new CustomPokemonData(); - } - newPokemon.customPokemonData.types = newTypes; - + // Copy old items to new pokemon for (const item of transformation.heldItems) { item.pokemonId = newPokemon.id; await scene.addModifier(item, false, false, false, true); } - - // Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef - if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) { - const stats: Stat[] = [ Stat.HP ]; - const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0); - // Attack or SpAtk - stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK); - // Def or SpDef - stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF); + // Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats + if (shouldGetOldGateau(newPokemon)) { + const stats = getOldGateauBoostedStats(newPokemon); const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU() - .generateType(scene.getParty(), [ 20, stats ]) + .generateType(scene.getParty(), [ OLD_GATEAU_STATS_UP, stats ]) ?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU); const modifier = modType?.newModifier(newPokemon); if (modifier) { @@ -406,9 +412,6 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon } } - // Enable passive if previous had it - newPokemon.passive = previousPokemon.passive; - newPokemon.calculateStats(); await newPokemon.updateInfo(); } @@ -427,6 +430,138 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon } } +/** + * Applies special changes to the newly transformed pokemon, such as passing previous moves, gaining egg moves, etc. + * Returns whether the transformed pokemon unlocks a new starter for the player. + * @param scene + * @param previousPokemon + * @param newPokemon + * @param speciesRootForm + * @param forBattle Default `false`. If false, will perform achievements and dex unlocks for the player. + */ +async function postProcessTransformedPokemon(scene: BattleScene, previousPokemon: PlayerPokemon, newPokemon: PlayerPokemon, speciesRootForm: Species, forBattle: boolean = false): Promise { + let isNewStarter = false; + // Roll HA a second time + if (newPokemon.species.abilityHidden) { + const hiddenIndex = newPokemon.species.ability2 ? 2 : 1; + if (newPokemon.abilityIndex < hiddenIndex) { + const hiddenAbilityChance = new IntegerHolder(256); + scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance); + + const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value); + + if (hasHiddenAbility) { + newPokemon.abilityIndex = hiddenIndex; + } + } + } + + // Roll IVs a second time + newPokemon.ivs = newPokemon.ivs.map(iv => { + const newValue = randSeedInt(31); + return newValue > iv ? newValue : iv; + }); + + // Roll a neutral nature + newPokemon.nature = [ Nature.HARDY, Nature.DOCILE, Nature.BASHFUL, Nature.QUIRKY, Nature.SERIOUS ][randSeedInt(5)]; + + // For pokemon at/below 570 BST or any shiny pokemon, unlock it permanently as if you had caught it + if (!forBattle && (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny())) { + if (newPokemon.getSpeciesForm().abilityHidden && newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1) { + scene.validateAchv(achvs.HIDDEN_ABILITY); + } + + if (newPokemon.species.subLegendary) { + scene.validateAchv(achvs.CATCH_SUB_LEGENDARY); + } + + if (newPokemon.species.legendary) { + scene.validateAchv(achvs.CATCH_LEGENDARY); + } + + if (newPokemon.species.mythical) { + scene.validateAchv(achvs.CATCH_MYTHICAL); + } + + scene.gameData.updateSpeciesDexIvs(newPokemon.species.getRootSpeciesId(true), newPokemon.ivs); + const newStarterUnlocked = await scene.gameData.setPokemonCaught(newPokemon, true, false, false); + if (newStarterUnlocked) { + isNewStarter = true; + await showEncounterText(scene, i18next.t("battle:addedAsAStarter", { pokemonName: getPokemonSpecies(speciesRootForm).getName() })); + } + } + + // If the previous pokemon had pokerus, transfer to new pokemon + newPokemon.pokerus = previousPokemon.pokerus; + + // Transfer previous Pokemon's luck value + newPokemon.luck = previousPokemon.getLuck(); + + // If the previous pokemon had higher IVs, override to those (after updating dex IVs > prevents perfect 31s on a new unlock) + newPokemon.ivs = newPokemon.ivs.map((iv, index) => { + return previousPokemon.ivs[index] > iv ? previousPokemon.ivs[index] : iv; + }); + + // For pokemon that the player owns (including ones just caught), gain a candy + if (!forBattle && !!scene.gameData.dexData[speciesRootForm].caughtAttr) { + scene.gameData.addStarterCandy(getPokemonSpecies(speciesRootForm), 1); + } + + // Set the moveset of the new pokemon to be the same as previous, but with 1 egg move and 1 (attempted) STAB move of the new species + newPokemon.generateAndPopulateMoveset(); + // Store a copy of a "standard" generated moveset for the new pokemon, will be used later for finding a favored move + const newPokemonGeneratedMoveset = newPokemon.moveset; + + newPokemon.moveset = previousPokemon.moveset.slice(0); + + const newEggMoveIndex = await addEggMoveToNewPokemonMoveset(scene, newPokemon, speciesRootForm, forBattle); + + // Try to add a favored STAB move (might fail if Pokemon already knows a bunch of moves from newPokemonGeneratedMoveset) + addFavoredMoveToNewPokemonMoveset(newPokemon, newPokemonGeneratedMoveset, newEggMoveIndex); + + // Randomize the second type of the pokemon + // If the pokemon does not normally have a second type, it will gain 1 + const newTypes = [ newPokemon.getTypes()[0] ]; + let newType = randSeedInt(18) as Type; + while (newType === newTypes[0]) { + newType = randSeedInt(18) as Type; + } + newTypes.push(newType); + if (!newPokemon.customPokemonData) { + newPokemon.customPokemonData = new CustomPokemonData(); + } + newPokemon.customPokemonData.types = newTypes; + + // Enable passive if previous had it + newPokemon.passive = previousPokemon.passive; + + return isNewStarter; +} + +/** + * @returns `true` if a given Pokemon has valid BST to be given an Old Gateau + */ +function shouldGetOldGateau(pokemon: Pokemon): boolean { + return pokemon.getSpeciesForm().getBaseStatTotal() < NON_LEGENDARY_BST_THRESHOLD; +} + +/** + * Get the lowest of HP/Spd, lowest of Atk/SpAtk, and lowest of Def/SpDef + * @returns Array of 3 {@linkcode Stat}s to boost + */ +function getOldGateauBoostedStats(pokemon: Pokemon): Stat[] { + const stats: Stat[] = []; + const baseStats = pokemon.getSpeciesForm().baseStats.slice(0); + // HP or Speed + stats.push(baseStats[Stat.HP] < baseStats[Stat.SPD] ? Stat.HP : Stat.SPD); + // Attack or SpAtk + stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK); + // Def or SpDef + stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF); + return stats; +} + + function getTransformedSpecies(originalBst: number, bstSearchRange: [number, number], hasPokemonBstHigherThan600: boolean, hasPokemonBstBetween570And600: boolean, alreadyUsedSpecies: PokemonSpecies[]): PokemonSpecies { let newSpecies: PokemonSpecies | undefined; while (isNullOrUndefined(newSpecies)) { @@ -550,7 +685,7 @@ function doSideBySideTransformations(scene: BattleScene, transformations: Pokemo * @param newPokemon * @param speciesRootForm */ -async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: PlayerPokemon, speciesRootForm: Species): Promise { +async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: PlayerPokemon, speciesRootForm: Species, forBattle: boolean = false): Promise { let eggMoveIndex: null | number = null; const eggMoves = newPokemon.getEggMoves()?.slice(0); if (eggMoves) { @@ -576,7 +711,7 @@ async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Pla } // For pokemon that the player owns (including ones just caught), unlock the egg move - if (!isNullOrUndefined(randomEggMoveIndex) && !!scene.gameData.dexData[speciesRootForm].caughtAttr) { + if (!forBattle && !isNullOrUndefined(randomEggMoveIndex) && !!scene.gameData.dexData[speciesRootForm].caughtAttr) { await scene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true); } } diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts index a57cedc8fa3..91ea0c5be19 100644 --- a/src/data/mystery-encounters/mystery-encounter-requirements.ts +++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts @@ -37,31 +37,58 @@ export abstract class EncounterSceneRequirement implements EncounterRequirement abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string]; } +/** + * Combination of multiple {@linkcode EncounterSceneRequirement | EncounterSceneRequirements} (OR/AND possible. See {@linkcode isAnd}) + */ export class CombinationSceneRequirement extends EncounterSceneRequirement { - orRequirements: EncounterSceneRequirement[]; + /** If `true`, all requirements must be met (AND). If `false`, any requirement must be met (OR) */ + private isAnd: boolean; + requirements: EncounterSceneRequirement[]; - constructor(... orRequirements: EncounterSceneRequirement[]) { + public static Some(...requirements: EncounterSceneRequirement[]): CombinationSceneRequirement { + return new CombinationSceneRequirement(false, ...requirements); + } + + public static Every(...requirements: EncounterSceneRequirement[]): CombinationSceneRequirement { + return new CombinationSceneRequirement(true, ...requirements); + } + + private constructor(isAnd: boolean, ...requirements: EncounterSceneRequirement[]) { super(); - this.orRequirements = orRequirements; + this.isAnd = isAnd; + this.requirements = requirements; } + /** + * Checks if all/any requirements are met (depends on {@linkcode isAnd}) + * @param scene The {@linkcode BattleScene} to check against + * @returns true if all/any requirements are met (depends on {@linkcode isAnd}) + */ override meetsRequirement(scene: BattleScene): boolean { - for (const req of this.orRequirements) { - if (req.meetsRequirement(scene)) { - return true; - } - } - return false; + return this.isAnd + ? this.requirements.every(req => req.meetsRequirement(scene)) + : this.requirements.some(req => req.meetsRequirement(scene)); } + /** + * Retrieves a dialogue token key/value pair for the given {@linkcode EncounterSceneRequirement | requirements}. + * @param scene The {@linkcode BattleScene} to check against + * @param pokemon The {@linkcode PlayerPokemon} to check against + * @returns A dialogue token key/value pair + * @throws An {@linkcode Error} if {@linkcode isAnd} is `true` (not supported) + */ override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - for (const req of this.orRequirements) { - if (req.meetsRequirement(scene)) { - return req.getDialogueToken(scene, pokemon); + if (this.isAnd) { + throw new Error("Not implemented (Sorry)"); + } else { + for (const req of this.requirements) { + if (req.meetsRequirement(scene)) { + return req.getDialogueToken(scene, pokemon); + } } - } - return this.orRequirements[0].getDialogueToken(scene, pokemon); + return this.requirements[0].getDialogueToken(scene, pokemon); + } } } @@ -90,44 +117,74 @@ export abstract class EncounterPokemonRequirement implements EncounterRequiremen abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string]; } +/** + * Combination of multiple {@linkcode EncounterPokemonRequirement | EncounterPokemonRequirements} (OR/AND possible. See {@linkcode isAnd}) + */ export class CombinationPokemonRequirement extends EncounterPokemonRequirement { - orRequirements: EncounterPokemonRequirement[]; + /** If `true`, all requirements must be met (AND). If `false`, any requirement must be met (OR) */ + private isAnd: boolean; + private requirements: EncounterPokemonRequirement[]; - constructor(...orRequirements: EncounterPokemonRequirement[]) { + public static Some(...requirements: EncounterPokemonRequirement[]): CombinationPokemonRequirement { + return new CombinationPokemonRequirement(false, ...requirements); + } + + public static Every(...requirements: EncounterPokemonRequirement[]): CombinationPokemonRequirement { + return new CombinationPokemonRequirement(true, ...requirements); + } + + private constructor(isAnd: boolean, ...requirements: EncounterPokemonRequirement[]) { super(); + this.isAnd = isAnd; this.invertQuery = false; this.minNumberOfPokemon = 1; - this.orRequirements = orRequirements; + this.requirements = requirements; } + /** + * Checks if all/any requirements are met (depends on {@linkcode isAnd}) + * @param scene The {@linkcode BattleScene} to check against + * @returns true if all/any requirements are met (depends on {@linkcode isAnd}) + */ override meetsRequirement(scene: BattleScene): boolean { - for (const req of this.orRequirements) { - if (req.meetsRequirement(scene)) { - return true; - } - } - return false; + return this.isAnd + ? this.requirements.every(req => req.meetsRequirement(scene)) + : this.requirements.some(req => req.meetsRequirement(scene)); } + /** + * Queries the players party for all party members that are compatible with all/any requirements (depends on {@linkcode isAnd}) + * @param partyPokemon The party of {@linkcode PlayerPokemon} + * @returns All party members that are compatible with all/any requirements (depends on {@linkcode isAnd}) + */ override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { - for (const req of this.orRequirements) { - const result = req.queryParty(partyPokemon); - if (result?.length > 0) { - return result; - } + if (this.isAnd) { + return this.requirements.reduce((relevantPokemon, req) => req.queryParty(relevantPokemon), partyPokemon); + } else { + const matchingRequirement = this.requirements.find(req => req.queryParty(partyPokemon).length > 0); + return matchingRequirement ? matchingRequirement.queryParty(partyPokemon) : []; } - - return []; } + /** + * Retrieves a dialogue token key/value pair for the given {@linkcode EncounterPokemonRequirement | requirements}. + * @param scene The {@linkcode BattleScene} to check against + * @param pokemon The {@linkcode PlayerPokemon} to check against + * @returns A dialogue token key/value pair + * @throws An {@linkcode Error} if {@linkcode isAnd} is `true` (not supported) + */ override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - for (const req of this.orRequirements) { - if (req.meetsRequirement(scene)) { - return req.getDialogueToken(scene, pokemon); + if (this.isAnd) { + throw new Error("Not implemented (Sorry)"); + } else { + for (const req of this.requirements) { + if (req.meetsRequirement(scene)) { + return req.getDialogueToken(scene, pokemon); + } } - } - return this.orRequirements[0].getDialogueToken(scene, pokemon); + return this.requirements[0].getDialogueToken(scene, pokemon); + } } } diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index ee9eb159e10..c045ee51bd7 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -53,6 +53,7 @@ export interface IMysteryEncounter { hasBattleAnimationsWithoutTargets: boolean; skipEnemyBattleTurns: boolean; skipToFightInput: boolean; + preventGameStatsUpdates: boolean; onInit?: (scene: BattleScene) => boolean; onVisualsStart?: (scene: BattleScene) => boolean; @@ -150,6 +151,10 @@ export default class MysteryEncounter implements IMysteryEncounter { * If true, will skip COMMAND input and go straight to FIGHT (move select) input menu */ skipToFightInput: boolean; + /** + * If true, will prevent updating {@linkcode GameStats} for encountering and/or defeating Pokemon + */ + preventGameStatsUpdates: boolean; // #region Event callback functions @@ -548,6 +553,7 @@ export class MysteryEncounterBuilder implements Partial { hasBattleAnimationsWithoutTargets: boolean = false; skipEnemyBattleTurns: boolean = false; skipToFightInput: boolean = false; + preventGameStatsUpdates: boolean = false; maxAllowedEncounters: number = 3; expMultiplier: number = 1; @@ -735,6 +741,14 @@ export class MysteryEncounterBuilder implements Partial { return Object.assign(this, { skipToFightInput }); } + /** + * If true, will prevent updating {@linkcode GameStats} for encountering and/or defeating Pokemon + * Default `false` + */ + withPreventGameStatsUpdates(preventGameStatsUpdates: boolean): this & Required> { + return Object.assign(this, { preventGameStatsUpdates }); + } + /** * Sets the maximum number of times that an encounter can spawn in a given Classic run * @param maxAllowedEncounters diff --git a/src/data/mystery-encounters/requirements/requirement-groups.ts b/src/data/mystery-encounters/requirements/requirement-groups.ts index 63c899fc5e9..76bbb8f03a7 100644 --- a/src/data/mystery-encounters/requirements/requirement-groups.ts +++ b/src/data/mystery-encounters/requirements/requirement-groups.ts @@ -118,3 +118,20 @@ export const EXTORTION_ABILITIES = [ Abilities.SUCTION_CUPS, Abilities.STICKY_HOLD ]; + +/** + * Abilities that signify resistance to fire + */ +export const FIRE_RESISTANT_ABILITIES = [ + Abilities.FLAME_BODY, + Abilities.FLASH_FIRE, + Abilities.WELL_BAKED_BODY, + Abilities.HEATPROOF, + Abilities.THERMAL_EXCHANGE, + Abilities.THICK_FAT, + Abilities.WATER_BUBBLE, + Abilities.MAGMA_ARMOR, + Abilities.WATER_VEIL, + Abilities.STEAM_ENGINE, + Abilities.PRIMORDIAL_SEA +]; diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index 5fa8af95f4d..b1adc478ab0 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -21,6 +21,8 @@ import { Gender } from "#app/data/gender"; import { PermanentStat } from "#enums/stat"; import { VictoryPhase } from "#app/phases/victory-phase"; import { SummaryUiMode } from "#app/ui/summary-ui-handler"; +import { CustomPokemonData } from "#app/data/custom-pokemon-data"; +import { Abilities } from "#enums/abilities"; /** Will give +1 level every 10 waves */ export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1; @@ -833,3 +835,21 @@ export function isPokemonValidForEncounterOptionSelection(pokemon: Pokemon, scen return null; } + +/** + * Permanently overrides the ability (not passive) of a pokemon. + * If the pokemon is a fusion, instead overrides the fused pokemon's ability. + */ +export function applyAbilityOverrideToPokemon(pokemon: Pokemon, ability: Abilities) { + if (pokemon.isFusion()) { + if (!pokemon.fusionCustomPokemonData) { + pokemon.fusionCustomPokemonData = new CustomPokemonData(); + } + pokemon.fusionCustomPokemonData.ability = ability; + } else { + if (!pokemon.customPokemonData) { + pokemon.customPokemonData = new CustomPokemonData(); + } + pokemon.customPokemonData.ability = ability; + } +} diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index fcc13975270..bc69b611075 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -2500,6 +2500,22 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.BUG_TYPE_SUPERFAN]: new TrainerConfig(++t).setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER) .setPartyTemplates(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE)), [TrainerType.EXPERT_POKEMON_BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(3).setEncounterBgm(TrainerType.ACE_TRAINER).setLocalizedName("Expert Pokemon Breeder") - .setPartyTemplates(new TrainerPartyTemplate(3, PartyMemberStrength.STRONG)) + .setPartyTemplates(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE)), + [TrainerType.FUTURE_SELF_M]: new TrainerConfig(++t) + .setMoneyMultiplier(0) + .setEncounterBgm("mystery_encounter_weird_dream") + .setBattleBgm("mystery_encounter_weird_dream") + .setMixedBattleBgm("mystery_encounter_weird_dream") + .setVictoryBgm("mystery_encounter_weird_dream") + .setLocalizedName("Future Self M") + .setPartyTemplates(new TrainerPartyTemplate(6, PartyMemberStrength.STRONG)), + [TrainerType.FUTURE_SELF_F]: new TrainerConfig(++t) + .setMoneyMultiplier(0) + .setEncounterBgm("mystery_encounter_weird_dream") + .setBattleBgm("mystery_encounter_weird_dream") + .setMixedBattleBgm("mystery_encounter_weird_dream") + .setVictoryBgm("mystery_encounter_weird_dream") + .setLocalizedName("Future Self F") + .setPartyTemplates(new TrainerPartyTemplate(6, PartyMemberStrength.STRONG)) }; diff --git a/src/enums/trainer-type.ts b/src/enums/trainer-type.ts index cb7509067b5..708faf69196 100644 --- a/src/enums/trainer-type.ts +++ b/src/enums/trainer-type.ts @@ -116,6 +116,8 @@ export enum TrainerType { VITO, BUG_TYPE_SUPERFAN, EXPERT_POKEMON_BREEDER, + FUTURE_SELF_M, + FUTURE_SELF_F, BROCK = 200, MISTY, diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6c4ae3b7ff9..d41c1f9eefa 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -93,7 +93,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public stats: integer[]; public ivs: integer[]; public nature: Nature; - public natureOverride: Nature | -1; public moveset: (PokemonMove | null)[]; public status: Status | null; public friendship: integer; @@ -4283,7 +4282,6 @@ export class PlayerPokemon extends Pokemon { if (newEvolution.condition?.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature); - newPokemon.natureOverride = this.natureOverride; newPokemon.passive = this.passive; newPokemon.moveset = this.moveset.slice(); newPokemon.moveset = this.copyMoveset(); diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 8e7853a41bb..3e475c62590 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -10,7 +10,9 @@ import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect import { Type } from "#app/data/type"; import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; -import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier } from "#app/modifier/modifier"; +import { + AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier +} from "#app/modifier/modifier"; import { ModifierTier } from "#app/modifier/modifier-tier"; import Overrides from "#app/overrides"; import { Unlockables } from "#app/system/unlockables"; @@ -1561,6 +1563,7 @@ export const modifierTypes = { VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 1), GOLDEN_POKEBALL: () => new ModifierType("modifierType:ModifierType.GOLDEN_POKEBALL", "pb_gold", (type, _args) => new ExtraModifierModifier(type), undefined, "se/pb_bounce_1"), + SILVER_POKEBALL: () => new ModifierType("modifierType:ModifierType.SILVER_POKEBALL", "pb_silver", (type, _args) => new TempExtraModifierModifier(type, 100), undefined, "se/pb_bounce_1"), ENEMY_DAMAGE_BOOSTER: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_BOOSTER", "wl_item_drop", (type, _args) => new EnemyDamageBoosterModifier(type, 5)), ENEMY_DAMAGE_REDUCTION: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_REDUCTION", "wl_guard_spec", (type, _args) => new EnemyDamageReducerModifier(type, 2.5)), @@ -1577,13 +1580,13 @@ export const modifierTypes = { if (pregenArgs) { return new PokemonBaseStatTotalModifierType(pregenArgs[0] as number); } - return new PokemonBaseStatTotalModifierType(randSeedInt(20)); + return new PokemonBaseStatTotalModifierType(randSeedInt(20, 1)); }), MYSTERY_ENCOUNTER_OLD_GATEAU: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]); } - return new PokemonBaseStatFlatModifierType(randSeedInt(20), [ Stat.HP, Stat.ATK, Stat.DEF ]); + return new PokemonBaseStatFlatModifierType(randSeedInt(20, 1), [ Stat.HP, Stat.ATK, Stat.DEF ]); }), MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index b699c2483c9..11f16f103a5 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -404,6 +404,14 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { this.battleCount = this.maxBattles; } + /** + * Updates an existing modifier with a new `maxBattles` and `battleCount`. + */ + setNewBattleCount(count: number): void { + this.maxBattles = count; + this.battleCount = count; + } + getMaxBattles(): number { return this.maxBattles; } @@ -960,7 +968,7 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { this.stackCount = pokemon ? pokemon.evoCounter + pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length - + pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier).length + + pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length : this.stackCount; const text = scene.add.bitmapText(10, 15, "item-count", this.stackCount.toString(), 11); @@ -975,7 +983,7 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { getMaxHeldItemCount(pokemon: Pokemon): number { this.stackCount = pokemon.evoCounter + pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length - + pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier).length; + + pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length; return 999; } } @@ -3288,6 +3296,60 @@ export class ExtraModifierModifier extends PersistentModifier { } } +/** + * Modifier used for timed boosts to the player's shop item rewards. + * @extends LapsingPersistentModifier + * @see {@linkcode apply} + */ +export class TempExtraModifierModifier extends LapsingPersistentModifier { + constructor(type: ModifierType, maxBattles: number, battleCount?: number, stackCount?: number) { + super(type, maxBattles, battleCount, stackCount); + } + + /** + * Goes through existing modifiers for any that match Silver Pokeball, + * which will then add the max count of the new item to the existing count of the current item. + * If no existing Silver Pokeballs are found, will add a new one. + * @param modifiers {@linkcode PersistentModifier} array of the player's modifiers + * @param _virtual N/A + * @param scene + * @returns true if the modifier was successfully added or applied, false otherwise + */ + add(modifiers: PersistentModifier[], _virtual: boolean, scene: BattleScene): boolean { + for (const modifier of modifiers) { + if (this.match(modifier)) { + const modifierInstance = modifier as TempExtraModifierModifier; + const newBattleCount = this.getMaxBattles() + modifierInstance.getBattleCount(); + + modifierInstance.setNewBattleCount(newBattleCount); + scene.playSound("se/restore"); + return true; + } + } + + modifiers.push(this); + return true; + } + + clone() { + return new TempExtraModifierModifier(this.type, this.getMaxBattles(), this.getBattleCount(), this.stackCount); + } + + match(modifier: Modifier): boolean { + return (modifier instanceof TempExtraModifierModifier); + } + + /** + * Increases the current rewards in the battle by the `stackCount`. + * @returns `true` if the shop reward number modifier applies successfully + * @param count {@linkcode NumberHolder} that holds the resulting shop item reward count + */ + apply(count: NumberHolder): boolean { + count.value += this.getStackCount(); + return true; + } +} + export abstract class EnemyPersistentModifier extends PersistentModifier { constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 38d5cfb4a10..e5a60692bb4 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -1,7 +1,7 @@ import BattleScene from "#app/battle-scene"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions } from "#app/modifier/modifier-type"; -import { ExtraModifierModifier, HealShopCostModifier, Modifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; +import { ExtraModifierModifier, HealShopCostModifier, Modifier, PokemonHeldItemModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler"; import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler"; import { Mode } from "#app/ui/ui"; @@ -45,6 +45,7 @@ export class SelectModifierPhase extends BattlePhase { const modifierCount = new Utils.IntegerHolder(3); if (this.isPlayer()) { this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount); + this.scene.applyModifiers(TempExtraModifierModifier, true, modifierCount); } // If custom modifiers are specified, overrides default item count @@ -274,7 +275,13 @@ export class SelectModifierPhase extends BattlePhase { // Otherwise, continue with custom multiplier multiplier = this.customModifierSettings.rerollMultiplier; } - return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount) * multiplier, Number.MAX_SAFE_INTEGER); + + const baseMultiplier = Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * (2 ** this.rerollCount) * multiplier, Number.MAX_SAFE_INTEGER); + + // Apply Black Sludge to reroll cost + const modifiedRerollCost = new NumberHolder(baseMultiplier); + this.scene.applyModifier(HealShopCostModifier, true, modifiedRerollCost); + return modifiedRerollCost.value; } getPoolType(): ModifierPoolType { diff --git a/src/phases/victory-phase.ts b/src/phases/victory-phase.ts index e900ff97fc6..1faa31655df 100644 --- a/src/phases/victory-phase.ts +++ b/src/phases/victory-phase.ts @@ -25,12 +25,17 @@ export class VictoryPhase extends PokemonPhase { start() { super.start(); - this.scene.gameData.gameStats.pokemonDefeated++; + const isMysteryEncounter = this.scene.currentBattle.isBattleMysteryEncounter(); + + // update Pokemon defeated count except for MEs that disable it + if (!isMysteryEncounter || !this.scene.currentBattle.mysteryEncounter?.preventGameStatsUpdates) { + this.scene.gameData.gameStats.pokemonDefeated++; + } const expValue = this.getPokemon().getExpValue(); this.scene.applyPartyExp(expValue, true); - if (this.scene.currentBattle.isBattleMysteryEncounter()) { + if (isMysteryEncounter) { handleMysteryEncounterVictory(this.scene, false, this.isExpOnly); return this.end(); } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 5f9aad63408..c00159a7fd7 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1569,6 +1569,10 @@ export class GameData { } setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true, trainer: boolean = false): void { + // Some Mystery Encounters block updates to these stats + if (this.scene.currentBattle?.isBattleMysteryEncounter() && this.scene.currentBattle.mysteryEncounter?.preventGameStatsUpdates) { + return; + } const dexEntry = this.dexData[pokemon.species.speciesId]; dexEntry.seenAttr |= pokemon.getDexAttr(); if (incrementCount) { diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index e681c995b26..421739a9da1 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -92,7 +92,6 @@ export default class PokemonData { this.stats = source.stats; this.ivs = source.ivs; this.nature = source.nature !== undefined ? source.nature : 0 as Nature; - this.natureOverride = source.natureOverride !== undefined ? source.natureOverride : -1; this.friendship = source.friendship !== undefined ? source.friendship : getPokemonSpecies(this.species).baseFriendship; this.metLevel = source.metLevel || 5; this.metBiome = source.metBiome !== undefined ? source.metBiome : -1; @@ -117,6 +116,8 @@ export default class PokemonData { this.customPokemonData = new CustomPokemonData(source.customPokemonData); + // Deprecated, but needed for session data migration + this.natureOverride = source.natureOverride; this.mysteryEncounterPokemonData = new CustomPokemonData(source.mysteryEncounterPokemonData); this.fusionMysteryEncounterPokemonData = new CustomPokemonData(source.fusionMysteryEncounterPokemonData); diff --git a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts index 69c0a114645..66d628ef82f 100644 --- a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts @@ -206,7 +206,7 @@ describe("Delibird-y - Mystery Encounter", () => { expect(candyJarAfter?.stackCount).toBe(1); }); - it("Should remove Reviver Seed and give the player a Healing Charm", async () => { + it("Should remove Reviver Seed and give the player a Berry Pouch", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); // Set 1 Reviver Seed on party lead @@ -220,11 +220,11 @@ describe("Delibird-y - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2, { pokemonNo: 1, optionNo: 1 }); const reviverSeedAfter = scene.findModifier(m => m instanceof PokemonInstantReviveModifier); - const healingCharmAfter = scene.findModifier(m => m instanceof HealingBoosterModifier); + const berryPouchAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); expect(reviverSeedAfter).toBeUndefined(); - expect(healingCharmAfter).toBeDefined(); - expect(healingCharmAfter?.stackCount).toBe(1); + expect(berryPouchAfter).toBeDefined(); + expect(berryPouchAfter?.stackCount).toBe(1); }); it("Should give the player a Shell Bell if they have max stacks of Candy Jars", async () => { @@ -256,13 +256,13 @@ describe("Delibird-y - Mystery Encounter", () => { expect(shellBellAfter?.stackCount).toBe(1); }); - it("Should give the player a Shell Bell if they have max stacks of Healing Charms", async () => { + it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); - // 5 Healing Charms + // 3 Berry Pouches scene.modifiers = []; - const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM)!.newModifier() as HealingBoosterModifier; - healingCharm.stackCount = 5; + const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH)!.newModifier() as PreserveBerryModifier; + healingCharm.stackCount = 3; await scene.addModifier(healingCharm, true, false, false, true); // Set 1 Reviver Seed on party lead @@ -275,12 +275,12 @@ describe("Delibird-y - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2, { pokemonNo: 1, optionNo: 1 }); const reviverSeedAfter = scene.findModifier(m => m instanceof PokemonInstantReviveModifier); - const healingCharmAfter = scene.findModifier(m => m instanceof HealingBoosterModifier); + const healingCharmAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier); expect(reviverSeedAfter).toBeUndefined(); expect(healingCharmAfter).toBeDefined(); - expect(healingCharmAfter?.stackCount).toBe(5); + expect(healingCharmAfter?.stackCount).toBe(3); expect(shellBellAfter).toBeDefined(); expect(shellBellAfter?.stackCount).toBe(1); }); @@ -347,7 +347,7 @@ describe("Delibird-y - Mystery Encounter", () => { }); }); - it("Should decrease held item stacks and give the player a Berry Pouch", async () => { + it("Should decrease held item stacks and give the player a Healing Charm", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); // Set 2 Soul Dew on party lead @@ -361,14 +361,14 @@ describe("Delibird-y - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 }); const soulDewAfter = scene.findModifier(m => m instanceof PokemonNatureWeightModifier); - const berryPouchAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); + const healingCharmAfter = scene.findModifier(m => m instanceof HealingBoosterModifier); expect(soulDewAfter?.stackCount).toBe(1); - expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter?.stackCount).toBe(1); + expect(healingCharmAfter).toBeDefined(); + expect(healingCharmAfter?.stackCount).toBe(1); }); - it("Should remove held item and give the player a Berry Pouch", async () => { + it("Should remove held item and give the player a Healing Charm", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); // Set 1 Soul Dew on party lead @@ -382,20 +382,20 @@ describe("Delibird-y - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 }); const soulDewAfter = scene.findModifier(m => m instanceof PokemonNatureWeightModifier); - const berryPouchAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); + const healingCharmAfter = scene.findModifier(m => m instanceof HealingBoosterModifier); expect(soulDewAfter).toBeUndefined(); - expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter?.stackCount).toBe(1); + expect(healingCharmAfter).toBeDefined(); + expect(healingCharmAfter?.stackCount).toBe(1); }); - it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => { + it("Should give the player a Shell Bell if they have max stacks of Healing Charms", async () => { await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); // 5 Healing Charms scene.modifiers = []; - const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH)!.newModifier() as PreserveBerryModifier; - healingCharm.stackCount = 3; + const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM)!.newModifier() as HealingBoosterModifier; + healingCharm.stackCount = 5; await scene.addModifier(healingCharm, true, false, false, true); // Set 1 Soul Dew on party lead @@ -408,12 +408,12 @@ describe("Delibird-y - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 }); const soulDewAfter = scene.findModifier(m => m instanceof PokemonNatureWeightModifier); - const berryPouchAfter = scene.findModifier(m => m instanceof PreserveBerryModifier); + const healingCharmAfter = scene.findModifier(m => m instanceof HealingBoosterModifier); const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier); expect(soulDewAfter).toBeUndefined(); - expect(berryPouchAfter).toBeDefined(); - expect(berryPouchAfter?.stackCount).toBe(3); + expect(healingCharmAfter).toBeDefined(); + expect(healingCharmAfter?.stackCount).toBe(5); expect(shellBellAfter).toBeDefined(); expect(shellBellAfter?.stackCount).toBe(1); }); diff --git a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts index a4f303d121f..5a270f1cbec 100644 --- a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts @@ -12,7 +12,7 @@ import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encount import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils"; import { Moves } from "#enums/moves"; import BattleScene from "#app/battle-scene"; -import { PokemonHeldItemModifier } from "#app/modifier/modifier"; +import { AttackTypeBoosterModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { Type } from "#app/data/type"; import { Status, StatusEffect } from "#app/data/status-effect"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; @@ -22,6 +22,8 @@ import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; import { CommandPhase } from "#app/phases/command-phase"; import { MovePhase } from "#app/phases/move-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Abilities } from "#enums/abilities"; import i18next from "i18next"; const namespace = "mysteryEncounters/fieryFallout"; @@ -42,10 +44,11 @@ describe("Fiery Fallout - Mystery Encounter", () => { beforeEach(async () => { game = new GameManager(phaserGame); scene = game.scene; - game.override.mysteryEncounterChance(100); - game.override.startingWave(defaultWave); - game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(); + game.override.mysteryEncounterChance(100) + .startingWave(defaultWave) + .startingBiome(defaultBiome) + .disableTrainerWaves() + .moveset([ Moves.PAYBACK, Moves.THUNDERBOLT ]); // Required for attack type booster item generation vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -109,12 +112,16 @@ describe("Fiery Fallout - Mystery Encounter", () => { { species: getPokemonSpecies(Species.VOLCARONA), isBoss: false, - gender: Gender.MALE + gender: Gender.MALE, + tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ], + mysteryEncounterBattleEffects: expect.any(Function) }, { species: getPokemonSpecies(Species.VOLCARONA), isBoss: false, - gender: Gender.FEMALE + gender: Gender.FEMALE, + tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ], + mysteryEncounterBattleEffects: expect.any(Function) } ], doubleBattle: true, @@ -157,12 +164,11 @@ describe("Fiery Fallout - Mystery Encounter", () => { expect(enemyField[0].gender).not.toEqual(enemyField[1].gender); // Should be opposite gender const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]); - expect(movePhases.length).toBe(4); + expect(movePhases.length).toBe(2); expect(movePhases.filter(p => (p as MovePhase).move.moveId === Moves.FIRE_SPIN).length).toBe(2); // Fire spin used twice before battle - expect(movePhases.filter(p => (p as MovePhase).move.moveId === Moves.QUIVER_DANCE).length).toBe(2); // Quiver Dance used twice before battle }); - it("should give charcoal to lead pokemon", async () => { + it("should give attack type boosting item to lead pokemon", async () => { await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runMysteryEncounterToEnd(game, 1, undefined, true); await skipBattleRunMysteryEncounterRewardsPhase(game); @@ -172,8 +178,8 @@ describe("Fiery Fallout - Mystery Encounter", () => { const leadPokemonId = scene.getParty()?.[0].id; const leadPokemonItems = scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === leadPokemonId, true) as PokemonHeldItemModifier[]; - const charcoal = leadPokemonItems.find(i => i.type.name === "Charcoal"); - expect(charcoal).toBeDefined; + const item = leadPokemonItems.find(i => i instanceof AttackTypeBoosterModifier); + expect(item).toBeDefined; }); }); @@ -193,7 +199,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); }); - it("should damage all non-fire party PKM by 20% and randomly burn 1", async () => { + it("should damage all non-fire party PKM by 20%, and burn + give Heatproof to a random Pokemon", async () => { await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); const party = scene.getParty(); @@ -210,7 +216,8 @@ describe("Fiery Fallout - Mystery Encounter", () => { burnablePokemon.forEach((pkm) => { expect(pkm.hp, `${pkm.name} should have received 20% damage: ${pkm.hp} / ${pkm.getMaxHp()} HP`).toBe(pkm.getMaxHp() - Math.floor(pkm.getMaxHp() * 0.2)); }); - expect(burnablePokemon.some(pkm => pkm?.status?.effect === StatusEffect.BURN)).toBeTruthy(); + expect(burnablePokemon.some(pkm => pkm.status?.effect === StatusEffect.BURN)).toBeTruthy(); + expect(burnablePokemon.some(pkm => pkm.customPokemonData.ability === Abilities.HEATPROOF)); notBurnablePokemon.forEach((pkm) => expect(pkm.hp, `${pkm.name} should be full hp: ${pkm.hp} / ${pkm.getMaxHp()} HP`).toBe(pkm.getMaxHp())); }); @@ -241,17 +248,15 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); }); - it("should give charcoal to lead pokemon", async () => { + it("should give attack type boosting item to lead pokemon", async () => { await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runMysteryEncounterToEnd(game, 3); await game.phaseInterceptor.to(SelectModifierPhase, false); expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); - const leadPokemonId = scene.getParty()?.[0].id; - const leadPokemonItems = scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === leadPokemonId, true) as PokemonHeldItemModifier[]; - const charcoal = leadPokemonItems.find(i => i.type.name === "Charcoal"); - expect(charcoal).toBeDefined; + const leadPokemonItems = scene.getParty()?.[0].getHeldItems() as PokemonHeldItemModifier[]; + const item = leadPokemonItems.find(i => i instanceof AttackTypeBoosterModifier); + expect(item).toBeDefined; }); it("should leave encounter without battle", async () => { @@ -264,7 +269,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); it("should be disabled if not enough FIRE types are in party", async () => { - await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, [ Species.MAGIKARP, Species.ARCANINE ]); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, [ Species.MAGIKARP ]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); const encounterPhase = scene.getCurrentPhase(); diff --git a/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts b/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts index d761f2d1b21..8286c6a694b 100644 --- a/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts @@ -86,7 +86,7 @@ describe("Trash to Treasure - Mystery Encounter", () => { expect(TrashToTreasureEncounter.enemyPartyConfigs).toEqual([ { - levelAdditiveModifier: 1, + levelAdditiveModifier: 0.5, disableSwitch: true, pokemonConfigs: [ { diff --git a/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts b/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts index 0d463655a52..c1fa6d83a18 100644 --- a/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/weird-dream-encounter.test.ts @@ -5,7 +5,7 @@ import { Species } from "#app/enums/species"; import GameManager from "#app/test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; +import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils"; import BattleScene from "#app/battle-scene"; import { Mode } from "#app/ui/ui"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; @@ -15,6 +15,8 @@ import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; import { WeirdDreamEncounter } from "#app/data/mystery-encounters/encounters/weird-dream-encounter"; import * as EncounterTransformationSequence from "#app/data/mystery-encounters/utils/encounter-transformation-sequence"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { ModifierTier } from "#app/modifier/modifier-tier"; const namespace = "mysteryEncounters/weirdDream"; const defaultParty = [ Species.MAGBY, Species.HAUNTER, Species.ABRA ]; @@ -70,7 +72,7 @@ describe("Weird Dream - Mystery Encounter", () => { expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}:title`); expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}:description`); expect(WeirdDreamEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}:query`); - expect(WeirdDreamEncounter.options.length).toBe(2); + expect(WeirdDreamEncounter.options.length).toBe(3); }); it("should initialize fully", async () => { @@ -132,7 +134,7 @@ describe("Weird Dream - Mystery Encounter", () => { expect(plus40To50.length).toBe(1); }); - it("should have 1 Memory Mushroom, 5 Rogue Balls, and 2 Mints in rewards", async () => { + it("should have 1 Memory Mushroom, 5 Rogue Balls, and 3 Mints in rewards", async () => { await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); await runMysteryEncounterToEnd(game, 1); await game.phaseInterceptor.to(SelectModifierPhase, false); @@ -141,11 +143,12 @@ describe("Weird Dream - Mystery Encounter", () => { 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(4); + expect(modifierSelectHandler.options.length).toEqual(5); expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MEMORY_MUSHROOM"); expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("ROGUE_BALL"); expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("MINT"); expect(modifierSelectHandler.options[3].modifierTypeOption.type.id).toEqual("MINT"); + expect(modifierSelectHandler.options[3].modifierTypeOption.type.id).toEqual("MINT"); }); it("should leave encounter without battle", async () => { @@ -158,7 +161,7 @@ describe("Weird Dream - Mystery Encounter", () => { }); }); - describe("Option 2 - Leave", () => { + describe("Option 2 - Battle Future Self", () => { it("should have the correct properties", () => { const option = WeirdDreamEncounter.options[1]; expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); @@ -174,17 +177,63 @@ describe("Weird Dream - Mystery Encounter", () => { }); }); - it("should reduce party levels by 12.5%", async () => { + it("should start a battle against the player's transformation team", async () => { + await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); + await runMysteryEncounterToEnd(game, 2, undefined, true); + + const enemyField = scene.getEnemyField(); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); + expect(enemyField.length).toBe(1); + expect(scene.getEnemyParty().length).toBe(scene.getParty().length); + }); + + it("should have 2 Rogue/2 Ultra/2 Great items in rewards", async () => { + await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); + await runMysteryEncounterToEnd(game, 2, undefined, true); + await skipBattleRunMysteryEncounterRewardsPhase(game); + 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(6); + expect(modifierSelectHandler.options[0].modifierTypeOption.type.tier - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ROGUE); + expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ROGUE); + expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ULTRA); + expect(modifierSelectHandler.options[3].modifierTypeOption.type.tier - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ULTRA); + expect(modifierSelectHandler.options[4].modifierTypeOption.type.tier - modifierSelectHandler.options[4].modifierTypeOption.upgradeCount).toEqual(ModifierTier.GREAT); + expect(modifierSelectHandler.options[5].modifierTypeOption.type.tier - modifierSelectHandler.options[5].modifierTypeOption.upgradeCount).toEqual(ModifierTier.GREAT); + }); + }); + + describe("Option 3 - Leave", () => { + it("should have the correct properties", () => { + const option = WeirdDreamEncounter.options[2]; + expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); + expect(option.dialogue).toBeDefined(); + expect(option.dialogue).toStrictEqual({ + buttonLabel: `${namespace}:option.3.label`, + buttonTooltip: `${namespace}:option.3.tooltip`, + selected: [ + { + text: `${namespace}:option.3.selected`, + }, + ], + }); + }); + + it("should reduce party levels by 10%", async () => { const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); const levelsPrior = scene.getParty().map(p => p.level); - await runMysteryEncounterToEnd(game, 2); + await runMysteryEncounterToEnd(game, 3); const levelsAfter = scene.getParty().map(p => p.level); for (let i = 0; i < levelsPrior.length; i++) { - expect(Math.max(Math.ceil(0.8875 * levelsPrior[i]), 1)).toBe(levelsAfter[i]); + expect(Math.max(Math.ceil(0.9 * levelsPrior[i]), 1)).toBe(levelsAfter[i]); expect(scene.getParty()[i].levelExp).toBe(0); } @@ -195,7 +244,7 @@ describe("Weird Dream - Mystery Encounter", () => { const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); await game.runToMysteryEncounter(MysteryEncounterType.WEIRD_DREAM, defaultParty); - await runMysteryEncounterToEnd(game, 2); + await runMysteryEncounterToEnd(game, 3); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); });