diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 82421fb1e17..75dacadff78 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1201,7 +1201,7 @@ export default class BattleScene extends SceneBase { // Check for mystery encounter // Can only occur in place of a standard (non-boss) wild battle, waves 10-180 - if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex, mysteryEncounterType)) { + if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex, mysteryEncounterType) || newBattleType === BattleType.MYSTERY_ENCOUNTER || !isNullOrUndefined(mysteryEncounterType)) { newBattleType = BattleType.MYSTERY_ENCOUNTER; // Reset base spawn weight this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT; diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index c9605aadc49..93d47fb7e5b 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -202,10 +202,15 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType; bossModifierConfigs.push({ modifier: modifierType }); } - - scene.removeModifier(berryMod); }); + // Do NOT remove the real berries yet or else it will be persisted in the session data + + // SpDef buff below wave 50, +1 to all stats otherwise + const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? + [Stat.SPDEF] : + [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; + // Calculate boss mon const config: EnemyPartyConfig = { levelAdditiveModifier: 1, @@ -214,12 +219,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = species: getPokemonSpecies(Species.GREEDENT), isBoss: true, bossSegments: 3, - moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF], + moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH], modifierConfigs: bossModifierConfigs, tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: (pokemon: Pokemon) => { queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`); - pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1)); + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); } } ], @@ -230,6 +235,18 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = return true; }) + .withOnVisualsStart((scene: BattleScene) => { + // Remove the berries from the party + // Session has been safely saved at this point, so data won't be lost + const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; + berryItems.forEach(berryMod => { + scene.removeModifier(berryMod); + }); + + scene.updateModifiers(true); + + return true; + }) .withOption( MysteryEncounterOptionBuilder .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index 2468ab0af8c..4cc5edc5208 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -190,11 +190,16 @@ export const BerriesAboundEncounter: MysteryEncounter = } }; + // Defense/Spd buffs below wave 50, +1 to all stats otherwise + const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? + [Stat.DEF, Stat.SPDEF, Stat.SPD] : + [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; + const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { queueEncounterMessage(pokemon.scene, `${namespace}.option.2.boss_enraged`); - pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1)); + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); }; setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards); await showEncounterText(scene, `${namespace}.option.2.selected_bad`); diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts index c35817255e0..f5d1891a391 100644 --- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts +++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts @@ -172,7 +172,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) { const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true); encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon)); - // Defense/Spd buffs below wave 50, Atk/Def/Spd buffs otherwise + // Defense/Spd buffs below wave 50, +1 to all stats otherwise const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? [Stat.DEF, Stat.SPDEF, Stat.SPD] : [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; diff --git a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts index 4f8a43ce364..4eade78baa6 100644 --- a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts +++ b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts @@ -72,6 +72,11 @@ export const UncommonBreedEncounter: MysteryEncounter = encounter.misc.pokemon = pokemon; + // Defense/Spd buffs below wave 50, +1 to all stats otherwise + const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? + [Stat.DEF, Stat.SPDEF, Stat.SPD] : + [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; + const config: EnemyPartyConfig = { pokemonConfigs: [{ level: level, @@ -81,7 +86,7 @@ export const UncommonBreedEncounter: MysteryEncounter = tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: (pokemon: Pokemon) => { queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`); - pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1)); + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); } }], }; diff --git a/src/locales/en/mystery-encounters/delibirdy-dialogue.json b/src/locales/en/mystery-encounters/delibirdy-dialogue.json index ca1fefa3a39..eb9e02f1312 100644 --- a/src/locales/en/mystery-encounters/delibirdy-dialogue.json +++ b/src/locales/en/mystery-encounters/delibirdy-dialogue.json @@ -25,5 +25,5 @@ "selected": "You toss the {{chosenItem}} to the {{delibirdName}}s,\nwho chatter amongst themselves excitedly.$They turn back to you and happily give you a present!" } }, - "outro": "The {{delibirdName}} pack happily waddles off into the distance.$What a curious little exchange!" + "outro": "The {{delibirdName}} flock happily waddles off into the distance.$What a curious little exchange!" } \ No newline at end of file diff --git a/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts b/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts index 78f4a477216..d71b982bfc7 100644 --- a/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/berries-abound-encounter.test.ts @@ -17,6 +17,7 @@ import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encount import * as EncounterDialogueUtils from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { CommandPhase } from "#app/phases/command-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; +import { Abilities } from "#enums/abilities"; const namespace = "mysteryEncounter:berriesAbound"; const defaultParty = [Species.PYUKUMUKU, Species.MAGIKARP, Species.PIKACHU]; @@ -35,13 +36,15 @@ describe("Berries Abound - Mystery Encounter", () => { beforeEach(async () => { game = new GameManager(phaserGame); scene = game.scene; - game.override.mysteryEncounterChance(100); - game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON); - game.override.startingWave(defaultWave); - game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(); - game.override.startingModifier([]); - game.override.startingHeldItems([]); + game.override.mysteryEncounterChance(100) + .mysteryEncounterTier(MysteryEncounterTier.COMMON) + .startingWave(defaultWave) + .startingBiome(defaultBiome) + .disableTrainerWaves() + .startingModifier([]) + .startingHeldItems([]) + .enemyAbility(Abilities.BALL_FETCH) + .enemyPassiveAbility(Abilities.BALL_FETCH); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -168,7 +171,30 @@ describe("Berries Abound - Mystery Encounter", () => { }); }); - it("should start battle if fastest pokemon is slower than boss", async () => { + it("should start battle if fastest pokemon is slower than boss below wave 50", async () => { + game.override.startingWave(41); + const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText"); + await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); + + const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; + const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId; + // Setting enemy's level arbitrarily high to outspeed + config.pokemonConfigs![0].dataSource!.level = 1000; + + await runMysteryEncounterToEnd(game, 2, undefined, true); + + const enemyField = scene.getEnemyField(); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); + expect(enemyField.length).toBe(1); + expect(enemyField[0].species.speciesId).toBe(speciesToSpawn); + + // Should be enraged + expect(enemyField[0].summonData.statStages).toEqual([0, 1, 0, 1, 1, 0, 0]); + expect(encounterTextSpy).toHaveBeenCalledWith(expect.any(BattleScene), `${namespace}.option.2.selected_bad`); + }); + + it("should start battle if fastest pokemon is slower than boss above wave 50", async () => { + game.override.startingWave(57); const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText"); await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); diff --git a/src/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts b/src/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts index 44a5197a39e..f3723983b14 100644 --- a/src/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts @@ -42,6 +42,7 @@ describe("Teleporting Hijinks - Mystery Encounter", () => { .startingWave(defaultWave) .startingBiome(defaultBiome) .disableTrainerWaves() + .enemyAbility(Abilities.BALL_FETCH) .enemyPassiveAbility(Abilities.BALL_FETCH); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( @@ -257,8 +258,8 @@ describe("Teleporting Hijinks - Mystery Encounter", () => { it("should start a battle against an extra enraged boss above wave 50", { retry: 5 }, async () => { game.override.startingWave(56); - await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, defaultParty); - await runMysteryEncounterToEnd(game, 1, undefined, true); + await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, [Species.PIKACHU]); + await runMysteryEncounterToEnd(game, 2, undefined, true); const enemyField = scene.getEnemyField(); expect(enemyField[0].summonData.statStages).toEqual([1, 1, 1, 1, 1, 0, 0]); expect(enemyField[0].isBoss()).toBe(true); diff --git a/src/test/mystery-encounter/encounters/uncommon-breed-encounter.test.ts b/src/test/mystery-encounter/encounters/uncommon-breed-encounter.test.ts index 2f8c4e5111a..3943063d7c0 100644 --- a/src/test/mystery-encounter/encounters/uncommon-breed-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/uncommon-breed-encounter.test.ts @@ -24,6 +24,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; import { BerryModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; +import { Abilities } from "#enums/abilities"; const namespace = "mysteryEncounter:uncommonBreed"; const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; @@ -42,11 +43,13 @@ describe("Uncommon Breed - Mystery Encounter", () => { beforeEach(async () => { game = new GameManager(phaserGame); scene = game.scene; - game.override.mysteryEncounterChance(100); - game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON); - game.override.startingWave(defaultWave); - game.override.startingBiome(defaultBiome); - game.override.disableTrainerWaves(); + game.override.mysteryEncounterChance(100) + .mysteryEncounterTier(MysteryEncounterTier.COMMON) + .startingWave(defaultWave) + .startingBiome(defaultBiome) + .disableTrainerWaves() + .enemyAbility(Abilities.BALL_FETCH) + .enemyPassiveAbility(Abilities.BALL_FETCH); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -107,7 +110,34 @@ describe("Uncommon Breed - Mystery Encounter", () => { }); }); - it.skip("should start a fight against the boss", async () => { + it.skip("should start a fight against the boss below wave 50", async () => { + const phaseSpy = vi.spyOn(scene, "pushPhase"); + const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase"); + await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty); + + const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; + const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId; + + await runMysteryEncounterToEnd(game, 1, undefined, true); + + const enemyField = scene.getEnemyField(); + expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); + expect(enemyField.length).toBe(1); + expect(enemyField[0].species.speciesId).toBe(speciesToSpawn); + + const statStagePhases = unshiftPhaseSpy.mock.calls.filter(p => p[0] instanceof StatStageChangePhase)[0][0] as any; + expect(statStagePhases.stats).toEqual([Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]); + + // Should have used its egg move pre-battle + const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]); + expect(movePhases.length).toBe(1); + const eggMoves: Moves[] = speciesEggMoves[getPokemonSpecies(speciesToSpawn).getRootSpeciesId()]; + const usedMove = (movePhases[0] as MovePhase).move.moveId; + expect(eggMoves.includes(usedMove)).toBe(true); + }); + + it.skip("should start a fight against the boss above wave 50", async () => { + game.override.startingWave(57); const phaseSpy = vi.spyOn(scene, "pushPhase"); const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase"); await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);