balance adjustments to certain ME battles

This commit is contained in:
ImperialSympathizer 2024-09-23 19:23:46 -04:00
parent cf80abe33f
commit 05b9e74729
9 changed files with 109 additions and 25 deletions

View File

@ -1201,7 +1201,7 @@ export default class BattleScene extends SceneBase {
// Check for mystery encounter // Check for mystery encounter
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180 // 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; newBattleType = BattleType.MYSTERY_ENCOUNTER;
// Reset base spawn weight // Reset base spawn weight
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT; this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;

View File

@ -202,10 +202,15 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType; const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType;
bossModifierConfigs.push({ modifier: modifierType }); 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 // Calculate boss mon
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveModifier: 1, levelAdditiveModifier: 1,
@ -214,12 +219,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.GREEDENT), species: getPokemonSpecies(Species.GREEDENT),
isBoss: true, isBoss: true,
bossSegments: 3, 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, modifierConfigs: bossModifierConfigs,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`); 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; 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( .withOption(
MysteryEncounterOptionBuilder MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)

View File

@ -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]; const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.2.boss_enraged`); 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); setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
await showEncounterText(scene, `${namespace}.option.2.selected_bad`); await showEncounterText(scene, `${namespace}.option.2.selected_bad`);

View File

@ -172,7 +172,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true); const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true);
encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon)); 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 ? 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.DEF, Stat.SPDEF, Stat.SPD] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];

View File

@ -72,6 +72,11 @@ export const UncommonBreedEncounter: MysteryEncounter =
encounter.misc.pokemon = pokemon; 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 = { const config: EnemyPartyConfig = {
pokemonConfigs: [{ pokemonConfigs: [{
level: level, level: level,
@ -81,7 +86,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`); 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));
} }
}], }],
}; };

View File

@ -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!" "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!"
} }

View File

@ -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 * as EncounterDialogueUtils from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { CommandPhase } from "#app/phases/command-phase"; import { CommandPhase } from "#app/phases/command-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { Abilities } from "#enums/abilities";
const namespace = "mysteryEncounter:berriesAbound"; const namespace = "mysteryEncounter:berriesAbound";
const defaultParty = [Species.PYUKUMUKU, Species.MAGIKARP, Species.PIKACHU]; const defaultParty = [Species.PYUKUMUKU, Species.MAGIKARP, Species.PIKACHU];
@ -35,13 +36,15 @@ describe("Berries Abound - Mystery Encounter", () => {
beforeEach(async () => { beforeEach(async () => {
game = new GameManager(phaserGame); game = new GameManager(phaserGame);
scene = game.scene; scene = game.scene;
game.override.mysteryEncounterChance(100); game.override.mysteryEncounterChance(100)
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON); .mysteryEncounterTier(MysteryEncounterTier.COMMON)
game.override.startingWave(defaultWave); .startingWave(defaultWave)
game.override.startingBiome(defaultBiome); .startingBiome(defaultBiome)
game.override.disableTrainerWaves(); .disableTrainerWaves()
game.override.startingModifier([]); .startingModifier([])
game.override.startingHeldItems([]); .startingHeldItems([])
.enemyAbility(Abilities.BALL_FETCH)
.enemyPassiveAbility(Abilities.BALL_FETCH);
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([ new Map<Biome, MysteryEncounterType[]>([
@ -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"); const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText");
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);

View File

@ -42,6 +42,7 @@ describe("Teleporting Hijinks - Mystery Encounter", () => {
.startingWave(defaultWave) .startingWave(defaultWave)
.startingBiome(defaultBiome) .startingBiome(defaultBiome)
.disableTrainerWaves() .disableTrainerWaves()
.enemyAbility(Abilities.BALL_FETCH)
.enemyPassiveAbility(Abilities.BALL_FETCH); .enemyPassiveAbility(Abilities.BALL_FETCH);
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( 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 () => { it("should start a battle against an extra enraged boss above wave 50", { retry: 5 }, async () => {
game.override.startingWave(56); game.override.startingWave(56);
await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, [Species.PIKACHU]);
await runMysteryEncounterToEnd(game, 1, undefined, true); await runMysteryEncounterToEnd(game, 2, undefined, true);
const enemyField = scene.getEnemyField(); const enemyField = scene.getEnemyField();
expect(enemyField[0].summonData.statStages).toEqual([1, 1, 1, 1, 1, 0, 0]); expect(enemyField[0].summonData.statStages).toEqual([1, 1, 1, 1, 1, 0, 0]);
expect(enemyField[0].isBoss()).toBe(true); expect(enemyField[0].isBoss()).toBe(true);

View File

@ -24,6 +24,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { BerryModifier } from "#app/modifier/modifier"; import { BerryModifier } from "#app/modifier/modifier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { Abilities } from "#enums/abilities";
const namespace = "mysteryEncounter:uncommonBreed"; const namespace = "mysteryEncounter:uncommonBreed";
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
@ -42,11 +43,13 @@ describe("Uncommon Breed - Mystery Encounter", () => {
beforeEach(async () => { beforeEach(async () => {
game = new GameManager(phaserGame); game = new GameManager(phaserGame);
scene = game.scene; scene = game.scene;
game.override.mysteryEncounterChance(100); game.override.mysteryEncounterChance(100)
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON); .mysteryEncounterTier(MysteryEncounterTier.COMMON)
game.override.startingWave(defaultWave); .startingWave(defaultWave)
game.override.startingBiome(defaultBiome); .startingBiome(defaultBiome)
game.override.disableTrainerWaves(); .disableTrainerWaves()
.enemyAbility(Abilities.BALL_FETCH)
.enemyPassiveAbility(Abilities.BALL_FETCH);
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([ new Map<Biome, MysteryEncounterType[]>([
@ -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 phaseSpy = vi.spyOn(scene, "pushPhase");
const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase"); const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase");
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);