Removing soft parameter from applyStarterChoice; logic for soft is now in starterSelectUiHandler

This commit is contained in:
Wlowscha 2025-03-02 01:27:53 +01:00
parent 373b7895b4
commit 896befde8b
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
2 changed files with 67 additions and 80 deletions

View File

@ -18,8 +18,6 @@ import { TrainerType } from "#enums/trainer-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import type { Moves } from "#enums/moves"; import type { Moves } from "#enums/moves";
import { TypeColor, TypeShadow } from "#enums/color"; 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 { ModifierTier } from "#app/modifier/modifier-tier";
/** A constant for the default max cost of the starting party before a run */ /** A constant for the default max cost of the starting party before a run */
@ -286,7 +284,7 @@ export abstract class Challenge {
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon. * @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
* @returns {@link boolean} Whether this function did anything. * @returns {@link boolean} Whether this function did anything.
*/ */
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean {
return false; return false;
} }
@ -433,22 +431,8 @@ export class SingleGenerationChallenge extends Challenge {
super(Challenges.SINGLE_GENERATION, 9); super(Challenges.SINGLE_GENERATION, 9);
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean {
const generations = [ pokemon.generation ]; if (pokemon.generation !== this.value) {
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)) {
valid.value = false; valid.value = false;
return true; return true;
} }
@ -591,30 +575,9 @@ export class SingleTypeChallenge extends Challenge {
super(Challenges.SINGLE_TYPE, 18); super(Challenges.SINGLE_TYPE, 18);
} }
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean {
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
const types = [ speciesForm.type1, speciesForm.type2 ]; 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)) { if (!types.includes(this.value - 1)) {
valid.value = false; valid.value = false;
return true; return true;
@ -858,7 +821,7 @@ export class LowerStarterPointsChallenge extends Challenge {
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon. * @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
* @returns True if any challenge was successfully applied. * @returns True if any challenge was successfully applied.
*/ */
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean): boolean; export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean;
/** /**
* Apply all challenges that modify available total starter points. * Apply all challenges that modify available total starter points.
* @param gameMode {@link GameMode} The current gameMode * @param gameMode {@link GameMode} The current gameMode
@ -977,7 +940,7 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
if (c.value !== 0) { if (c.value !== 0) {
switch (challengeType) { switch (challengeType) {
case ChallengeType.STARTER_CHOICE: 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; break;
case ChallengeType.STARTER_POINTS: case ChallengeType.STARTER_POINTS:
ret ||= c.applyStarterPoints(args[0]); ret ||= c.applyStarterPoints(args[0]);

View File

@ -1,6 +1,6 @@
import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene"; import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene";
import { BattleSceneEventType } 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 type { Variant } from "#app/data/variant";
import { getVariantTint, getVariantIcon } from "#app/data/variant"; import { getVariantTint, getVariantIcon } from "#app/data/variant";
import { argbFromRgba } from "@material/material-color-utilities"; import { argbFromRgba } from "@material/material-color-utilities";
@ -18,7 +18,7 @@ import { pokemonFormChanges } from "#app/data/pokemon-forms";
import type { LevelMoves } from "#app/data/balance/pokemon-level-moves"; import type { LevelMoves } from "#app/data/balance/pokemon-level-moves";
import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } 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 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 { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
import { Type } from "#enums/type"; import { Type } from "#enums/type";
import { GameModes } from "#app/game-mode"; import { GameModes } from "#app/game-mode";
@ -1300,20 +1300,57 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
} }
checkValidForChallenge(species: PokemonSpecies, soft: boolean) { checkValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
const isValidForChallenge = new BooleanHolder(true); const isValidForChallenge = new BooleanHolder(true);
Challenge.applyChallenges( Challenge.applyChallenges(
globalScene.gameMode, globalScene.gameMode,
Challenge.ChallengeType.STARTER_CHOICE, Challenge.ChallengeType.STARTER_CHOICE,
species, species,
isValidForChallenge, isValidForChallenge,
globalScene.gameData.getSpeciesDexAttrProps( props
species,
this.getCurrentDexProps(species.speciesId)
),
this.isPartyValid()
); );
return isValidForChallenge.value; const allValidities: boolean[] = [];
if (soft) {
const speciesToCheck = [ species.speciesId ];
while (speciesToCheck.length) {
const checking = speciesToCheck.pop();
const checkingSpecies = getPokemonSpecies(checking);
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 isValidForChallenge.value || (soft && allValidities.filter(v => v).length > 0);
} }
processInput(button: Button): boolean { processInput(button: Button): boolean {
@ -1509,12 +1546,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const species = starter.species; const species = starter.species;
const [ isDupe ] = this.isInParty(species); const [ isDupe ] = this.isInParty(species);
const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId); const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId);
const isValidForChallenge = new BooleanHolder(true); const isValidForChallenge = this.checkValidForChallenge(
Challenge.applyChallenges(
globalScene.gameMode,
Challenge.ChallengeType.STARTER_CHOICE,
species, species,
isValidForChallenge,
globalScene.gameData.getSpeciesDexAttrProps( globalScene.gameData.getSpeciesDexAttrProps(
species, species,
this.getCurrentDexProps(species.speciesId) this.getCurrentDexProps(species.speciesId)
@ -1524,7 +1557,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr; const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
return ( return (
!isDupe && !isDupe &&
isValidForChallenge.value && isValidForChallenge &&
currentPartyValue + starterCost <= this.getValueLimit() && currentPartyValue + starterCost <= this.getValueLimit() &&
isCaught isCaught
); );
@ -1614,20 +1647,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
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); // checks to see if the pokemon is a duplicate; if it is, returns the index that will be removed
const isPartyValid = this.isPartyValid(); const isPartyValid = this.isPartyValid();
const isValidForChallenge = new BooleanHolder(true); const isValidForChallenge = this.checkValidForChallenge(this.lastSpecies, globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)), isPartyValid);
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.lastSpecies, isValidForChallenge, globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)), isPartyValid);
const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, _gen: number, i: number) => total += globalScene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, _gen: number, i: number) => total += globalScene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0);
const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId); const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId);
if (!isDupe && isValidForChallenge.value && 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 if (!isDupe && 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 = [ options = [
{ {
label: i18next.t("starterSelectUiHandler:addToParty"), label: i18next.t("starterSelectUiHandler:addToParty"),
handler: () => { handler: () => {
ui.setMode(Mode.STARTER_SELECT); ui.setMode(Mode.STARTER_SELECT);
const isOverValueLimit = this.tryUpdateValue(globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId), true); const isOverValueLimit = this.tryUpdateValue(globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId), true);
if (!isDupe && isValidForChallenge.value && isOverValueLimit) { if (!isDupe && isValidForChallenge && isOverValueLimit) {
const cursorObj = this.starterCursorObjs[this.starterSpecies.length]; const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
cursorObj.setVisible(true); cursorObj.setVisible(true);
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y); cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
@ -2572,14 +2603,12 @@ 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 * 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 tempFormProps = BigInt(Math.pow(2, i)) * DexAttr.DEFAULT_FORM;
const isValidForChallenge = new BooleanHolder(true); const isValidForChallenge = this.checkValidForChallenge(container.species, globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps), true);
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, container.species, isValidForChallenge, globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps), true); allFormsValid = allFormsValid || isValidForChallenge;
allFormsValid = allFormsValid || isValidForChallenge.value;
} }
} else { } else {
const isValidForChallenge = new BooleanHolder(true); const isValidForChallenge = this.checkValidForChallenge(container.species, globalScene.gameData.getSpeciesDexAttrProps(species, globalScene.gameData.getSpeciesDefaultDexAttr(container.species, false, true)), true);
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, container.species, isValidForChallenge, globalScene.gameData.getSpeciesDexAttrProps(species, globalScene.gameData.getSpeciesDefaultDexAttr(container.species, false, true)), true); allFormsValid = isValidForChallenge;
allFormsValid = isValidForChallenge.value;
} }
if (allFormsValid) { if (allFormsValid) {
this.validStarterContainers.push(container); this.validStarterContainers.push(container);
@ -3331,8 +3360,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonSprite.setVisible(!this.statsMode); 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); const currentFilteredContainer = this.filteredStarterContainers.find(p => p.species.speciesId === species.speciesId);
if (currentFilteredContainer) { if (currentFilteredContainer) {
const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite; const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite;
@ -3659,10 +3686,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
} }
let isPartyValid: boolean = this.isPartyValid(); // this checks to see if the party is valid let isPartyValid: boolean = this.isPartyValid(); // this checks to see if the party is valid
if (addingToParty) { // this does a check to see if the pokemon being added is valid; if so, it will update the isPartyValid boolean 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; const species = this.filteredStarterContainers[this.cursor].species;
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isNewPokemonValid, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false); const isNewPokemonValid = this.checkValidForChallenge(species, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false);
isPartyValid = isPartyValid || isNewPokemonValid.value; isPartyValid = isPartyValid || isNewPokemonValid;
} }
/** /**
@ -3686,10 +3712,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
* If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater. * 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. * 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); const isValidForChallenge = this.checkValidForChallenge(this.allSpecies[s], globalScene.gameData.getSpeciesDexAttrProps(this.allSpecies[s], this.getCurrentDexProps(this.allSpecies[s].speciesId)), isPartyValid);
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.allSpecies[s], isValidForChallenge, globalScene.gameData.getSpeciesDexAttrProps(this.allSpecies[s], this.getCurrentDexProps(this.allSpecies[s].speciesId)), 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 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
@ -3798,10 +3823,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
isPartyValid(): boolean { isPartyValid(): boolean {
let canStart = false; let canStart = false;
for (let s = 0; s < this.starterSpecies.length; s++) { for (let s = 0; s < this.starterSpecies.length; s++) {
const isValidForChallenge = new BooleanHolder(true);
const species = this.starterSpecies[s]; const species = this.starterSpecies[s];
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false); const isValidForChallenge = this.checkValidForChallenge(species, globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false);
canStart = canStart || isValidForChallenge.value; canStart = canStart || isValidForChallenge;
} }
return canStart; return canStart;
} }