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 15cba1fa103..eee7a266a6b 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -57,6 +57,7 @@ import { allMoves } from "#app/data/moves/move"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { Challenges } from "#enums/challenges"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/bugTypeSuperfan"; @@ -193,6 +194,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde ) .withMaxAllowedEncounters(1) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withDisallowedChallenges(Challenges.METRONOME) .withIntroSpriteConfigs([]) // These are set in onInit() .withAutoHideIntroVisuals(false) .withIntroDialogue([ diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 91f168371cf..332d44f3a04 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -41,6 +41,7 @@ import { PokeballType } from "#enums/pokeball"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; import i18next from "i18next"; +import { Challenges } from "#enums/challenges"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/dancingLessons"; @@ -99,6 +100,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder ) .withEncounterTier(MysteryEncounterTier.GREAT) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withDisallowedChallenges(Challenges.METRONOME) .withIntroSpriteConfigs([]) // Uses a real Pokemon sprite instead of ME Intro Visuals .withAnimations(EncounterAnim.DANCE) .withHideWildIntroMessage(true) diff --git a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts index 9b8e2e24d12..9804bbd77b2 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts @@ -11,6 +11,10 @@ import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounte import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; +import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import { CompatibleMoveRequirement } from "../mystery-encounter-requirements"; +import { Moves } from "#enums/moves"; /** i18n namespace for encounter */ const namespace = "mysteryEncounters/departmentStoreSale"; @@ -55,34 +59,37 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu .withTitle(`${namespace}:title`) .withDescription(`${namespace}:description`) .withQuery(`${namespace}:query`) - .withSimpleOption( - { - buttonLabel: `${namespace}:option.1.label`, - buttonTooltip: `${namespace}:option.1.tooltip`, - }, - async () => { - // Choose TMs - const modifiers: ModifierTypeFunc[] = []; - let i = 0; - while (i < 5) { - // 2/2/1 weight on TM rarity - const roll = randSeedInt(5); - if (roll < 2) { - modifiers.push(modifierTypes.TM_COMMON); - } else if (roll < 4) { - modifiers.push(modifierTypes.TM_GREAT); - } else { - modifiers.push(modifierTypes.TM_ULTRA); + .withOption( + MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) + .withPrimaryPokemonRequirement(new CompatibleMoveRequirement(Moves.PROTECT)) // Check Protect in compatible tms yeah this sucks + .withDialogue({ + buttonLabel: `${namespace}:option.1.label`, + buttonTooltip: `${namespace}:option.1.tooltip`, + }) + .withOptionPhase(async () => { + // Choose TMs + const modifiers: ModifierTypeFunc[] = []; + let i = 0; + while (i < 5) { + // 2/2/1 weight on TM rarity + const roll = randSeedInt(5); + if (roll < 2) { + modifiers.push(modifierTypes.TM_COMMON); + } else if (roll < 4) { + modifiers.push(modifierTypes.TM_GREAT); + } else { + modifiers.push(modifierTypes.TM_ULTRA); + } + i++; } - i++; - } - setEncounterRewards({ - guaranteedModifierTypeFuncs: modifiers, - fillRemaining: false, - }); - leaveEncounterWithoutBattle(); - }, + setEncounterRewards({ + guaranteedModifierTypeFuncs: modifiers, + fillRemaining: false, + }); + leaveEncounterWithoutBattle(); + }) + .build(), ) .withSimpleOption( { diff --git a/src/data/mystery-encounters/encounters/part-timer-encounter.ts b/src/data/mystery-encounters/encounters/part-timer-encounter.ts index 61b48353997..9318a85d688 100644 --- a/src/data/mystery-encounters/encounters/part-timer-encounter.ts +++ b/src/data/mystery-encounters/encounters/part-timer-encounter.ts @@ -22,6 +22,7 @@ import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { Challenges } from "#enums/challenges"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/partTimer"; @@ -36,6 +37,7 @@ export const PartTimerEncounter: MysteryEncounter = MysteryEncounterBuilder.with ) .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withDisallowedChallenges(Challenges.METRONOME) .withIntroSpriteConfigs([ { spriteKey: "part_timer_crate", diff --git a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts index a7ffe3e26ca..b272e00d760 100644 --- a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts +++ b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts @@ -51,17 +51,23 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon; } + /** + * Queries party for mons meeting move requirements + * @param partyPokemon {@link PlayerPokemon} party to query + * @returns list of {@link PlayerPokemon} that match query + */ override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { if (!this.invertQuery) { - return partyPokemon.filter(pokemon => - // every required move should be included - this.requiredMoves.every(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)), + return partyPokemon.filter( + pokemon => + // every required move should be included + this.requiredMoves.length === this.getAllPokemonMoves(pokemon).length, ); } return partyPokemon.filter( pokemon => // none of the "required" moves should be included - !this.requiredMoves.some(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)), + this.getAllPokemonMoves(pokemon).length === 0, ); } @@ -73,19 +79,24 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement { return pkm.getLevelMoves().map(([_level, move]) => move); } + /** + * Gets all the moves with matching criteria + * @param pkm {@link PlayerPokemon} to check + * @returns list of {@link Moves} moves matching criteria + */ private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] { const allPokemonMoves: Moves[] = []; if (!this.excludeLevelMoves) { - allPokemonMoves.push(...(this.getPokemonLevelMoves(pkm) ?? [])); + allPokemonMoves.push(...(this.getPokemonLevelMoves(pkm).filter(m => this.requiredMoves.includes(m)) ?? [])); } if (!this.excludeTmMoves) { - allPokemonMoves.push(...(pkm.compatibleTms ?? [])); + allPokemonMoves.push(...pkm.generateCompatibleTms(false, false).filter(m => this.requiredMoves.includes(m))); } if (!this.excludeEggMoves) { - allPokemonMoves.push(...(pkm.getEggMoves() ?? [])); + allPokemonMoves.push(...(pkm.getEggMoves()?.filter(m => this.requiredMoves.includes(m)) ?? [])); } return allPokemonMoves; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b49898389a8..ec54e6172c3 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -6318,8 +6318,8 @@ export class PlayerPokemon extends Pokemon { return this.getFieldIndex(); } - generateCompatibleTms(): void { - this.compatibleTms = []; + generateCompatibleTms(alsoSet: boolean = true, applyChal: boolean = true): Moves[] { + const ret: Moves[] = []; const tms = Object.keys(tmSpecies); for (const tm of tms) { @@ -6347,10 +6347,15 @@ export class PlayerPokemon extends Pokemon { if (reverseCompatibleTms.indexOf(moveId) > -1) { compatible = !compatible; } - if (compatible && !applyChallenges(ChallengeType.BAN_MOVE_LEARNING, this, moveId)) { - this.compatibleTms.push(moveId); + if (compatible && (!applyChal || !applyChallenges(ChallengeType.BAN_MOVE_LEARNING, this, moveId))) { + ret.push(moveId); } } + if (alsoSet) { + this.compatibleTms = ret; + } + + return ret; } tryPopulateMoveset(moveset: StarterMoveset): boolean {