[Balance] [Mystery Encounter] Many Minor Mystery Encounter Adjustments (#5726)

* Update slumbering-snorlax-encounter.ts

* Add Slumbering Snorlax to Tall Grass, remove Absolute Avarice from Plains

* Update absolute-avarice-encounter.ts

* Update absolute-avarice-encounter.ts

* Update slumbering-snorlax-encounter.ts

* Update slumbering-snorlax-encounter.ts

* Update the-expert-pokemon-breeder-encounter.ts

* Update slumbering-snorlax-encounter.ts nature

* Update bug-type-superfan-encounter.ts move reward

* Update bug-type-superfan-encounter.ts moves again

* fix encounter waves

* Update absolute-avarice-encounter.test.ts

* add Nature import

* Update bug-type-superfan-encounter.test.ts

* greedent moves

* test moves

* Updated mysterious-chest-encounter.ts trap/reward chance

* swapped Macho Brace stats, +2 / 10% for HP stats and +1 / 5% for all else

* Update bug-type-superfan-encounter.ts moves

* Update the-expert-pokemon-breeder-encounter.ts tera

* Update bug-type-superfan-encounter.test.ts fix test
This commit is contained in:
damocleas 2025-05-02 01:11:02 -04:00 committed by GitHub
parent 6d90649b92
commit 8f0eee9c4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 80 additions and 54 deletions

View File

@ -37,7 +37,6 @@ import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
import type { BerryType } from "#enums/berry-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next";
/** the i18n namespace for this encounter */
@ -52,8 +51,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
MysteryEncounterType.ABSOLUTE_AVARICE,
)
.withEncounterTier(MysteryEncounterTier.GREAT)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Must have at least 4 berries to spawn
.withSceneWaveRangeRequirement(20, 180)
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 6)) // Must have at least 6 berries to spawn
.withFleeAllowed(false)
.withIntroSpriteConfigs([
{
@ -220,9 +219,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
// 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
// +1 SpDef below wave 50, SpDef and Speed otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] =
globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];
globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.SPDEF, Stat.SPD];
// Calculate boss mon
const config: EnemyPartyConfig = {
@ -233,7 +232,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
isBoss: true,
bossSegments: 3,
shiny: false, // Shiny lock because of consistency issues between the different options
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH],
moveSet: [Moves.THRASH, Moves.CRUNCH, Moves.BODY_PRESS, Moves.SLACK_OFF],
modifierConfigs: bossModifierConfigs,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {

View File

@ -146,24 +146,34 @@ const POOL_4_POKEMON = [Species.GENESECT, Species.SLITHER_WING, Species.BUZZWOLE
const PHYSICAL_TUTOR_MOVES = [
Moves.MEGAHORN,
Moves.X_SCISSOR,
Moves.ATTACK_ORDER,
Moves.PIN_MISSILE,
Moves.BUG_BITE,
Moves.FIRST_IMPRESSION,
Moves.LUNGE
];
const SPECIAL_TUTOR_MOVES = [Moves.SILVER_WIND, Moves.BUG_BUZZ, Moves.SIGNAL_BEAM, Moves.POLLEN_PUFF];
const SPECIAL_TUTOR_MOVES = [
Moves.SILVER_WIND,
Moves.SIGNAL_BEAM,
Moves.BUG_BUZZ,
Moves.POLLEN_PUFF,
Moves.STRUGGLE_BUG
];
const STATUS_TUTOR_MOVES = [Moves.STRING_SHOT, Moves.STICKY_WEB, Moves.SILK_TRAP, Moves.RAGE_POWDER, Moves.HEAL_ORDER];
const STATUS_TUTOR_MOVES = [
Moves.STRING_SHOT,
Moves.DEFEND_ORDER,
Moves.RAGE_POWDER,
Moves.STICKY_WEB,
Moves.SILK_TRAP
];
const MISC_TUTOR_MOVES = [
Moves.BUG_BITE,
Moves.LEECH_LIFE,
Moves.DEFEND_ORDER,
Moves.QUIVER_DANCE,
Moves.TAIL_GLOW,
Moves.INFESTATION,
Moves.U_TURN,
Moves.HEAL_ORDER,
Moves.QUIVER_DANCE,
Moves.INFESTATION,
];
/**

View File

@ -29,8 +29,8 @@ import { Species } from "#enums/species";
const namespace = "mysteryEncounters/mysteriousChest";
const RAND_LENGTH = 100;
const TRAP_PERCENT = 35;
const COMMON_REWARDS_PERCENT = 20;
const TRAP_PERCENT = 30;
const COMMON_REWARDS_PERCENT = 25;
const ULTRA_REWARDS_PERCENT = 30;
const ROGUE_REWARDS_PERCENT = 10;
const MASTER_REWARDS_PERCENT = 5;

View File

@ -19,6 +19,7 @@ import {
setEncounterRewards,
} from "../utils/encounter-phase-utils";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { Nature } from "#enums/nature";
import { Moves } from "#enums/moves";
import { BattlerIndex } from "#app/battle";
import { AiType, PokemonMove } from "#app/field/pokemon";
@ -26,9 +27,10 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat";
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { randSeedInt } from "#app/utils/common";
/** i18n namespace for the encounter */
const namespace = "mysteryEncounters/slumberingSnorlax";
@ -42,7 +44,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
MysteryEncounterType.SLUMBERING_SNORLAX,
)
.withEncounterTier(MysteryEncounterTier.GREAT)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneWaveRangeRequirement(15, 150)
.withCatchAllowed(true)
.withHideWildIntroMessage(true)
.withFleeAllowed(false)
@ -72,16 +74,26 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
species: bossSpecies,
isBoss: true,
shiny: false, // Shiny lock because shiny is rolled only if the battle option is picked
status: [StatusEffect.SLEEP, 5], // Extra turns on timer for Snorlax's start of fight moves
moveSet: [Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT],
status: [StatusEffect.SLEEP, 6], // Extra turns on timer for Snorlax's start of fight moves
nature: Nature.DOCILE,
moveSet: [Moves.BODY_SLAM, Moves.CRUNCH, Moves.SLEEP_TALK, Moves.REST],
modifierConfigs: [
{
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
stackCount: 2,
},
{
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
stackCount: 2,
},
{
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
},
{
modifier: generateModifierType(modifierTypes.SOOTHE_BELL) as PokemonHeldItemModifierType,
stackCount: randSeedInt(2, 0),
},
{
modifier: generateModifierType(modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType,
stackCount: randSeedInt(2, 0),
},
],
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
@ -128,12 +140,6 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
move: new PokemonMove(Moves.SNORE),
ignorePp: true,
},
{
sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER],
move: new PokemonMove(Moves.SNORE),
ignorePp: true,
},
);
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
},

View File

@ -11,7 +11,6 @@ import { randSeedShuffle } from "#app/utils/common";
import type MysteryEncounter from "../mystery-encounter";
import { MysteryEncounterBuilder } from "../mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { Biome } from "#enums/biome";
import { TrainerType } from "#enums/trainer-type";
import i18next from "i18next";
@ -123,7 +122,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER,
)
.withEncounterTier(MysteryEncounterTier.ULTRA)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneWaveRangeRequirement(25, 180)
.withScenePartySizeRequirement(4, 6, true) // Must have at least 4 legal pokemon in party
.withIntroSpriteConfigs([]) // These are set in onInit()
.withIntroDialogue([
@ -483,9 +482,9 @@ function getPartyConfig(): EnemyPartyConfig {
abilityIndex: 1, // Magic Guard
shiny: false,
nature: Nature.ADAMANT,
moveSet: [Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH],
moveSet: [Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH, Moves.METEOR_MASH],
ivs: [31, 31, 31, 31, 31, 31],
tera: PokemonType.STEEL,
tera: PokemonType.FAIRY,
},
],
};

View File

@ -226,9 +226,9 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
*/
export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([
[Biome.TOWN, []],
[Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX]],
[Biome.GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.TALL_GRASS, [MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.TALL_GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.METROPOLIS, []],
[Biome.FOREST, [MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.SEA, [MysteryEncounterType.LOST_AT_SEA]],

View File

@ -1114,20 +1114,20 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
* @returns always `true`
*/
override apply(_pokemon: Pokemon, stat: Stat, statHolder: NumberHolder): boolean {
// Modifies the passed in stat number holder by +1 per stack for HP, +2 per stack for other stats
// If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats
// Modifies the passed in stat number holder by +2 per stack for HP, +1 per stack for other stats
// If the Macho Brace is at max stacks (50), adds additional 10% to total HP and 5% to other stats
const isHp = stat === Stat.HP;
if (isHp) {
statHolder.value += this.stackCount;
if (this.stackCount === this.getMaxHeldItemCount()) {
statHolder.value = Math.floor(statHolder.value * 1.05);
}
} else {
statHolder.value += 2 * this.stackCount;
if (this.stackCount === this.getMaxHeldItemCount()) {
statHolder.value = Math.floor(statHolder.value * 1.1);
}
} else {
statHolder.value += this.stackCount;
if (this.stackCount === this.getMaxHeldItemCount()) {
statHolder.value = Math.floor(statHolder.value * 1.05);
}
}
return true;

View File

@ -23,7 +23,7 @@ import i18next from "i18next";
const namespace = "mysteryEncounters/absoluteAvarice";
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
const defaultBiome = Biome.PLAINS;
const defaultBiome = Biome.TALL_GRASS;
const defaultWave = 45;
describe("Absolute Avarice - Mystery Encounter", () => {
@ -45,7 +45,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([
[Biome.PLAINS, [MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.TALL_GRASS, [MysteryEncounterType.ABSOLUTE_AVARICE]],
[Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]],
]),
);
@ -91,6 +91,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
game.override.startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS },
{ name: "BERRY", count: 3, type: BerryType.GANLON },
{ name: "BERRY", count: 2, type: BerryType.APICOT },
]);
await game.runToMysteryEncounter();
@ -102,6 +103,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
game.override.startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS },
{ name: "BERRY", count: 3, type: BerryType.GANLON },
{ name: "BERRY", count: 2, type: BerryType.APICOT },
]);
await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty);
@ -138,7 +140,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
expect(enemyField[0].species.speciesId).toBe(Species.GREEDENT);
const moveset = enemyField[0].moveset.map(m => m.moveId);
expect(moveset?.length).toBe(4);
expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH]);
expect(moveset).toEqual([Moves.THRASH, Moves.CRUNCH, Moves.BODY_PRESS, Moves.SLACK_OFF]);
const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]);
expect(movePhases.length).toBe(1);

View File

@ -118,24 +118,34 @@ const POOL_4_POKEMON = [Species.GENESECT, Species.SLITHER_WING, Species.BUZZWOLE
const PHYSICAL_TUTOR_MOVES = [
Moves.MEGAHORN,
Moves.X_SCISSOR,
Moves.ATTACK_ORDER,
Moves.PIN_MISSILE,
Moves.BUG_BITE,
Moves.FIRST_IMPRESSION,
Moves.LUNGE
];
const SPECIAL_TUTOR_MOVES = [Moves.SILVER_WIND, Moves.BUG_BUZZ, Moves.SIGNAL_BEAM, Moves.POLLEN_PUFF];
const SPECIAL_TUTOR_MOVES = [
Moves.SILVER_WIND,
Moves.SIGNAL_BEAM,
Moves.BUG_BUZZ,
Moves.POLLEN_PUFF,
Moves.STRUGGLE_BUG
];
const STATUS_TUTOR_MOVES = [Moves.STRING_SHOT, Moves.STICKY_WEB, Moves.SILK_TRAP, Moves.RAGE_POWDER, Moves.HEAL_ORDER];
const STATUS_TUTOR_MOVES = [
Moves.STRING_SHOT,
Moves.DEFEND_ORDER,
Moves.RAGE_POWDER,
Moves.STICKY_WEB,
Moves.SILK_TRAP
];
const MISC_TUTOR_MOVES = [
Moves.BUG_BITE,
Moves.LEECH_LIFE,
Moves.DEFEND_ORDER,
Moves.QUIVER_DANCE,
Moves.TAIL_GLOW,
Moves.INFESTATION,
Moves.U_TURN,
Moves.HEAL_ORDER,
Moves.QUIVER_DANCE,
Moves.INFESTATION,
];
describe("Bug-Type Superfan - Mystery Encounter", () => {