mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-20 07:12:32 +02:00
Filtering correctly when combining gen and monotype challenges
This commit is contained in:
parent
b298138157
commit
a29747fcc7
@ -18,9 +18,10 @@ import { TrainerType } from "#enums/trainer-type";
|
||||
import { Nature } from "#enums/nature";
|
||||
import type { Moves } from "#enums/moves";
|
||||
import { TypeColor, TypeShadow } from "#enums/color";
|
||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
||||
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;
|
||||
@ -285,15 +286,9 @@ export abstract class Challenge {
|
||||
* @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
||||
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
||||
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
||||
* @param _soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyStarterChoice(
|
||||
_pokemon: PokemonSpecies,
|
||||
_valid: Utils.BooleanHolder,
|
||||
_dexAttr: DexAttrProps,
|
||||
_soft = false,
|
||||
): boolean {
|
||||
applyStarterChoice(_pokemon: PokemonSpecies, _valid: Utils.BooleanHolder, _dexAttr: DexAttrProps): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -445,27 +440,8 @@ export class SingleGenerationChallenge extends Challenge {
|
||||
super(Challenges.SINGLE_GENERATION, 9);
|
||||
}
|
||||
|
||||
applyStarterChoice(
|
||||
pokemon: PokemonSpecies,
|
||||
valid: Utils.BooleanHolder,
|
||||
_dexAttr: DexAttrProps,
|
||||
soft = false,
|
||||
): boolean {
|
||||
const generations = [pokemon.generation];
|
||||
if (soft) {
|
||||
const speciesToCheck = [pokemon.speciesId];
|
||||
while (speciesToCheck.length) {
|
||||
const checking = speciesToCheck.pop();
|
||||
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
||||
pokemonEvolutions[checking].forEach(e => {
|
||||
speciesToCheck.push(e.speciesId);
|
||||
generations.push(getPokemonSpecies(e.speciesId).generation);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!generations.includes(this.value)) {
|
||||
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean {
|
||||
if (pokemon.generation !== this.value) {
|
||||
valid.value = false;
|
||||
return true;
|
||||
}
|
||||
@ -745,35 +721,9 @@ export class SingleTypeChallenge extends Challenge {
|
||||
super(Challenges.SINGLE_TYPE, 18);
|
||||
}
|
||||
|
||||
override applyStarterChoice(
|
||||
pokemon: PokemonSpecies,
|
||||
valid: Utils.BooleanHolder,
|
||||
dexAttr: DexAttrProps,
|
||||
soft = false,
|
||||
): boolean {
|
||||
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean {
|
||||
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
|
||||
const types = [speciesForm.type1, speciesForm.type2];
|
||||
if (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) {
|
||||
const speciesToCheck = [pokemon.speciesId];
|
||||
while (speciesToCheck.length) {
|
||||
const checking = speciesToCheck.pop();
|
||||
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
||||
pokemonEvolutions[checking].forEach(e => {
|
||||
speciesToCheck.push(e.speciesId);
|
||||
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
|
||||
});
|
||||
}
|
||||
if (checking && pokemonFormChanges.hasOwnProperty(checking)) {
|
||||
pokemonFormChanges[checking].forEach(f1 => {
|
||||
getPokemonSpecies(checking).forms.forEach(f2 => {
|
||||
if (f1.formKey === f2.formKey) {
|
||||
types.push(f2.type1, f2.type2);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!types.includes(this.value - 1)) {
|
||||
valid.value = false;
|
||||
return true;
|
||||
@ -1030,7 +980,6 @@ export class LowerStarterPointsChallenge extends Challenge {
|
||||
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
||||
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
||||
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
||||
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(
|
||||
@ -1039,7 +988,6 @@ export function applyChallenges(
|
||||
pokemon: PokemonSpecies,
|
||||
valid: Utils.BooleanHolder,
|
||||
dexAttr: DexAttrProps,
|
||||
soft: boolean,
|
||||
): boolean;
|
||||
/**
|
||||
* Apply all challenges that modify available total starter points.
|
||||
@ -1222,7 +1170,7 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
||||
if (c.value !== 0) {
|
||||
switch (challengeType) {
|
||||
case ChallengeType.STARTER_CHOICE:
|
||||
ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3]);
|
||||
ret ||= c.applyStarterChoice(args[0], args[1], args[2]);
|
||||
break;
|
||||
case ChallengeType.STARTER_POINTS:
|
||||
ret ||= c.applyStarterPoints(args[0]);
|
||||
@ -1305,3 +1253,74 @@ 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 speciesToCheck = [species.speciesId];
|
||||
while (speciesToCheck.length) {
|
||||
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 || !pokemonFormChanges.hasOwnProperty(species.speciesId) || props.formIndex === 0) {
|
||||
const isValidForChallenge = new Utils.BooleanHolder(true);
|
||||
applyChallenges(globalScene.gameMode, ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
|
||||
return isValidForChallenge.value;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene";
|
||||
import { BattleSceneEventType } from "#app/events/battle-scene";
|
||||
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import type { Variant } from "#app/data/variant";
|
||||
import { getVariantTint, getVariantIcon } from "#app/data/variant";
|
||||
import { argbFromRgba } from "@material/material-color-utilities";
|
||||
@ -19,7 +19,7 @@ import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
||||
import type { LevelMoves } from "#app/data/balance/pokemon-level-moves";
|
||||
import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves";
|
||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { allSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data/pokemon-species";
|
||||
import { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data/pokemon-species";
|
||||
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
|
||||
import { PokemonType } from "#enums/pokemon-type";
|
||||
import { GameModes } from "#app/game-mode";
|
||||
@ -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;
|
||||
|
||||
@ -1760,21 +1761,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
const species = starter.species;
|
||||
const [isDupe] = this.isInParty(species);
|
||||
const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId);
|
||||
const isValidForChallenge = new BooleanHolder(true);
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
species,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||
this.isPartyValid(),
|
||||
);
|
||||
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
|
||||
return (
|
||||
!isDupe &&
|
||||
isValidForChallenge.value &&
|
||||
currentPartyValue + starterCost <= this.getValueLimit() &&
|
||||
isCaught
|
||||
!isDupe && isValidForChallenge && currentPartyValue + starterCost <= this.getValueLimit() && isCaught
|
||||
);
|
||||
});
|
||||
if (validStarters.length === 0) {
|
||||
@ -1861,16 +1855,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
const ui = this.getUi();
|
||||
let options: any[] = []; // TODO: add proper type
|
||||
|
||||
const [isDupe, removeIndex]: [boolean, number] = this.isInParty(this.lastSpecies); // checks to see if the pokemon is a duplicate; if it is, returns the index that will be removed
|
||||
const [isDupe, removeIndex]: [boolean, number] = this.isInParty(this.lastSpecies);
|
||||
|
||||
const isPartyValid = this.isPartyValid();
|
||||
const isValidForChallenge = new BooleanHolder(true);
|
||||
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
this.lastSpecies,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(
|
||||
this.lastSpecies,
|
||||
this.getCurrentDexProps(this.lastSpecies.speciesId),
|
||||
@ -1888,11 +1877,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId);
|
||||
if (
|
||||
!isDupe &&
|
||||
isValidForChallenge.value &&
|
||||
isValidForChallenge &&
|
||||
currentPartyValue + newCost <= this.getValueLimit() &&
|
||||
this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE
|
||||
) {
|
||||
// this checks to make sure the pokemon doesn't exist in your party, it's valid for the challenge and that it won't go over the cost limit; if it meets all these criteria it will add it to your party
|
||||
options = [
|
||||
{
|
||||
label: i18next.t("starterSelectUiHandler:addToParty"),
|
||||
@ -1902,7 +1890,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId),
|
||||
true,
|
||||
);
|
||||
if (!isDupe && isValidForChallenge.value && isOverValueLimit) {
|
||||
if (!isDupe && isValidForChallenge && isOverValueLimit) {
|
||||
const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
|
||||
cursorObj.setVisible(true);
|
||||
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
|
||||
@ -2994,31 +2982,23 @@ 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 = new BooleanHolder(true);
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
container.species,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps),
|
||||
true,
|
||||
);
|
||||
allFormsValid = allFormsValid || isValidForChallenge.value;
|
||||
allFormsValid = allFormsValid || isValidForChallenge;
|
||||
}
|
||||
} else {
|
||||
const isValidForChallenge = new BooleanHolder(true);
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
container.species,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(
|
||||
species,
|
||||
globalScene.gameData.getSpeciesDefaultDexAttr(container.species, false, true),
|
||||
),
|
||||
true,
|
||||
);
|
||||
allFormsValid = isValidForChallenge.value;
|
||||
allFormsValid = isValidForChallenge;
|
||||
}
|
||||
if (allFormsValid) {
|
||||
this.validStarterContainers.push(container);
|
||||
@ -3851,15 +3831,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonSprite.setVisible(!this.statsMode);
|
||||
}
|
||||
|
||||
const isValidForChallenge = new BooleanHolder(true);
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
species,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor),
|
||||
!!this.starterSpecies.length,
|
||||
);
|
||||
const currentFilteredContainer = this.filteredStarterContainers.find(
|
||||
p => p.species.speciesId === species.speciesId,
|
||||
);
|
||||
@ -4233,20 +4204,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
globalScene.time.delayedCall(fixedInt(500), () => this.tryUpdateValue());
|
||||
return false;
|
||||
}
|
||||
let isPartyValid: boolean = this.isPartyValid(); // this checks to see if the party is valid
|
||||
let isPartyValid: boolean = this.isPartyValid();
|
||||
if (addingToParty) {
|
||||
// this does a check to see if the pokemon being added is valid; if so, it will update the isPartyValid boolean
|
||||
const isNewPokemonValid = new BooleanHolder(true);
|
||||
const species = this.filteredStarterContainers[this.cursor].species;
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isNewPokemonValid = checkStarterValidForChallenge(
|
||||
species,
|
||||
isNewPokemonValid,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||
false,
|
||||
);
|
||||
isPartyValid = isPartyValid || isNewPokemonValid.value;
|
||||
isPartyValid = isPartyValid || isNewPokemonValid;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4270,12 +4236,8 @@ 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 = new BooleanHolder(true);
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
this.allSpecies[s],
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(
|
||||
this.allSpecies[s],
|
||||
this.getCurrentDexProps(this.allSpecies[s].speciesId),
|
||||
@ -4283,7 +4245,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
isPartyValid,
|
||||
);
|
||||
|
||||
const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge.value;
|
||||
const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge;
|
||||
|
||||
const isPokemonInParty = this.isInParty(this.allSpecies[s])[0]; // this will get the valud of isDupe from isInParty. This will let us see if the pokemon in question is in our party already so we don't grey out the sprites if they're invalid
|
||||
|
||||
@ -4417,17 +4379,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
isPartyValid(): boolean {
|
||||
let canStart = false;
|
||||
for (let s = 0; s < this.starterSpecies.length; s++) {
|
||||
const isValidForChallenge = new BooleanHolder(true);
|
||||
const species = this.starterSpecies[s];
|
||||
Challenge.applyChallenges(
|
||||
globalScene.gameMode,
|
||||
Challenge.ChallengeType.STARTER_CHOICE,
|
||||
const isValidForChallenge = checkStarterValidForChallenge(
|
||||
species,
|
||||
isValidForChallenge,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||
false,
|
||||
);
|
||||
canStart = canStart || isValidForChallenge.value;
|
||||
canStart = canStart || isValidForChallenge;
|
||||
}
|
||||
return canStart;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user