From a9ed02d45d4f835c574a7229149961ce709ddec7 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 11 Mar 2025 23:32:35 +0100 Subject: [PATCH] Moving challenge filter logic to challenge.ts --- src/data/challenge.ts | 77 ++++++++++++++++++++++++++++ src/ui/starter-select-ui-handler.ts | 78 +++-------------------------- 2 files changed, 85 insertions(+), 70 deletions(-) diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 00d96fd94fe..561c6feb914 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -19,6 +19,9 @@ import { Nature } from "#enums/nature"; import type { Moves } from "#enums/moves"; import { TypeColor, TypeShadow } from "#enums/color"; import { ModifierTier } from "#app/modifier/modifier-tier"; +import { globalScene } from "#app/global-scene"; +import { pokemonFormChanges } from "./pokemon-forms"; +import { pokemonEvolutions } from "./balance/pokemon-evolutions"; /** A constant for the default max cost of the starting party before a run */ const DEFAULT_PARTY_MAX_COST = 10; @@ -1250,3 +1253,77 @@ export function initChallenges() { new FlipStatChallenge(), ); } + +/** + * Apply all challenges to the given starter (and form) to check its validity. + * Differs from {@link checkSpeciesValidForChallenge} which only checks form changes. + * @param species {@link PokemonSpecies} The species to check the validity of. + * @param dexAttr {@link DexAttrProps} The dex attributes of the species, including its form index. + * @param soft {@link boolean} If true, allow it if it could become valid through evolution or form change. + * @returns True if the species is considered valid. + */ +export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { + if (!soft) { + const isValidForChallenge = new Utils.BooleanHolder(true); + applyChallenges(globalScene.gameMode, ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); + return isValidForChallenge.value; + } + // We check the validity of every evolution and form change, and require that at least one is valid + const isValid = false; + const speciesToCheck = [species.speciesId]; + while (speciesToCheck.length && !isValid) { + const checking = speciesToCheck.pop(); + // Linter complains if we don't handle this + if (!checking) { + return false; + } + const checkingSpecies = getPokemonSpecies(checking); + if (checkSpeciesValidForChallenge(checkingSpecies, props, true)) { + return true; + } + if (checking && pokemonEvolutions.hasOwnProperty(checking)) { + pokemonEvolutions[checking].forEach(e => { + speciesToCheck.push(e.speciesId); + }); + } + } + return false; +} + +/** + * Apply all challenges to the given species (and form) to check its validity. + * Differs from {@link checkStarterValidForChallenge} which also checks evolutions. + * @param species {@link PokemonSpecies} The species to check the validity of. + * @param dexAttr {@link DexAttrProps} The dex attributes of the species, including its form index. + * @param soft {@link boolean} If true, allow it if it could become valid through a form change. + * @returns True if the species is considered valid. + */ +function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { + if (!soft) { + const isValidForChallenge = new Utils.BooleanHolder(true); + applyChallenges(globalScene.gameMode, ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); + return isValidForChallenge.value; + } + if (pokemonFormChanges.hasOwnProperty(species.speciesId)) { + pokemonFormChanges[species.speciesId].forEach(f1 => { + species.forms.forEach((f2, formIndex) => { + if (f1.formKey === f2.formKey) { + const formProps = { ...props }; + formProps.formIndex = formIndex; + const isFormValidForChallenge = new Utils.BooleanHolder(true); + applyChallenges( + globalScene.gameMode, + ChallengeType.STARTER_CHOICE, + species, + isFormValidForChallenge, + formProps, + ); + if (isFormValidForChallenge.value) { + return true; + } + } + }); + }); + } + return false; +} diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index c8cb129d02f..e2c3297edf5 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -80,6 +80,7 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { achvs } from "#app/system/achv"; import * as Utils from "../utils"; import type { GameObjects } from "phaser"; +import { checkStarterValidForChallenge } from "#app/data/challenge"; export type StarterSelectCallback = (starters: Starter[]) => void; @@ -1554,69 +1555,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }); } - /** - * Apply all challenges to the given species (and form) to check its validity. - * @param species {@link PokemonSpecies} The species to check the validity of. - * @param dexAttr {@link DexAttrProps} The dex attributes of the species, including its form index. - * @param soft {@link boolean} If true, allow it if it could become valid through evolution or form change. - * @returns True if the species is considered valid. - */ - checkValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { - if (!soft) { - const isValidForChallenge = new BooleanHolder(true); - Challenge.applyChallenges( - globalScene.gameMode, - Challenge.ChallengeType.STARTER_CHOICE, - species, - isValidForChallenge, - props, - ); - return isValidForChallenge.value; - } - // We check the validity of every evolution and battle form separately, - // and require that at least one is valid - const allValidities: boolean[] = []; - const speciesToCheck = [species.speciesId]; - while (speciesToCheck.length) { - const checking = speciesToCheck.pop(); - const checkingSpecies = getPokemonSpecies(checking ?? Species.BULBASAUR); - const isEvoValidForChallenge = new BooleanHolder(true); - Challenge.applyChallenges( - globalScene.gameMode, - Challenge.ChallengeType.STARTER_CHOICE, - checkingSpecies, - isEvoValidForChallenge, - props, // This might be wrong, in principle we need to pass the right formIndex - ); - allValidities.push(isEvoValidForChallenge.value); - if (checking && pokemonEvolutions.hasOwnProperty(checking)) { - pokemonEvolutions[checking].forEach(e => { - speciesToCheck.push(e.speciesId); - }); - } - if (checking && pokemonFormChanges.hasOwnProperty(checking)) { - pokemonFormChanges[checking].forEach(f1 => { - checkingSpecies.forms.forEach((f2, formIndex) => { - if (f1.formKey === f2.formKey) { - const formProps = { ...props }; - formProps.formIndex = formIndex; - const isFormValidForChallenge = new BooleanHolder(true); - Challenge.applyChallenges( - globalScene.gameMode, - Challenge.ChallengeType.STARTER_CHOICE, - checkingSpecies, - isFormValidForChallenge, - formProps, - ); - allValidities.push(isFormValidForChallenge.value); - } - }); - }); - } - } - return allValidities.filter(v => v).length > 0; - } - processInput(button: Button): boolean { if (this.blockInput) { return false; @@ -1823,7 +1761,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const species = starter.species; const [isDupe] = this.isInParty(species); const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId); - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( species, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), this.isPartyValid(), @@ -1920,7 +1858,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const [isDupe, removeIndex]: [boolean, number] = this.isInParty(this.lastSpecies); const isPartyValid = this.isPartyValid(); - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( this.lastSpecies, globalScene.gameData.getSpeciesDexAttrProps( this.lastSpecies, @@ -3044,7 +2982,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { * Since some pokemon rely on forms to be valid (i.e. blaze tauros for fire challenges), we make a fake form and dex props to use in the challenge */ const tempFormProps = BigInt(Math.pow(2, i)) * DexAttr.DEFAULT_FORM; - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( container.species, globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps), true, @@ -3052,7 +2990,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { allFormsValid = allFormsValid || isValidForChallenge; } } else { - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( container.species, globalScene.gameData.getSpeciesDexAttrProps( species, @@ -4269,7 +4207,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { let isPartyValid: boolean = this.isPartyValid(); if (addingToParty) { const species = this.filteredStarterContainers[this.cursor].species; - const isNewPokemonValid = this.checkValidForChallenge( + const isNewPokemonValid = checkStarterValidForChallenge( species, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false, @@ -4298,7 +4236,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { * If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater. * we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too. */ - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( this.allSpecies[s], globalScene.gameData.getSpeciesDexAttrProps( this.allSpecies[s], @@ -4442,7 +4380,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { let canStart = false; for (let s = 0; s < this.starterSpecies.length; s++) { const species = this.starterSpecies[s]; - const isValidForChallenge = this.checkValidForChallenge( + const isValidForChallenge = checkStarterValidForChallenge( species, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false,