mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-09 00:49:27 +02:00
Separate Challenge Utility Functions
This commit is contained in:
parent
10f4326c77
commit
32a56e9a5f
@ -1,15 +1,11 @@
|
|||||||
import type { FixedBattleConfig } from "#app/battle";
|
import type { FixedBattleConfig } from "#app/battle";
|
||||||
import { getRandomTrainerFunc } from "#app/battle";
|
import { getRandomTrainerFunc } from "#app/battle";
|
||||||
import { defaultStarterSpecies } from "#app/constants";
|
import { defaultStarterSpecies } from "#app/constants";
|
||||||
import { globalScene } from "#app/global-scene";
|
|
||||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
|
||||||
import { speciesStarterCosts } from "#balance/starters";
|
import { speciesStarterCosts } from "#balance/starters";
|
||||||
import { getEggTierForSpecies } from "#data/egg";
|
import { getEggTierForSpecies } from "#data/egg";
|
||||||
import { pokemonFormChanges } from "#data/pokemon-forms";
|
|
||||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||||
import { getPokemonSpeciesForm } from "#data/pokemon-species";
|
import { getPokemonSpeciesForm } from "#data/pokemon-species";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { TypeColor, TypeShadow } from "#enums/color";
|
import { TypeColor, TypeShadow } from "#enums/color";
|
||||||
import { EggTier } from "#enums/egg-type";
|
import { EggTier } from "#enums/egg-type";
|
||||||
@ -27,7 +23,7 @@ import { Trainer } from "#field/trainer";
|
|||||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||||
import { PokemonMove } from "#moves/pokemon-move";
|
import { PokemonMove } from "#moves/pokemon-move";
|
||||||
import type { DexAttrProps, GameData } from "#system/game-data";
|
import type { DexAttrProps, GameData } from "#system/game-data";
|
||||||
import { BooleanHolder, type NumberHolder, randSeedItem } from "#utils/common";
|
import { type BooleanHolder, type NumberHolder, randSeedItem } from "#utils/common";
|
||||||
import { deepCopy } from "#utils/data";
|
import { deepCopy } from "#utils/data";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import { toCamelCase, toSnakeCase } from "#utils/strings";
|
import { toCamelCase, toSnakeCase } from "#utils/strings";
|
||||||
@ -1016,295 +1012,6 @@ export class PermanentFaintChallenge extends Challenge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify starter choice.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE
|
|
||||||
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
|
||||||
* @param valid {@link 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.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.STARTER_CHOICE,
|
|
||||||
pokemon: PokemonSpecies,
|
|
||||||
valid: BooleanHolder,
|
|
||||||
dexAttr: DexAttrProps,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify available total starter points.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS
|
|
||||||
* @param points {@link NumberHolder} The amount of points you have available.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: NumberHolder): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify the cost of a starter.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST
|
|
||||||
* @param species {@link SpeciesId} The pokemon to change the cost of.
|
|
||||||
* @param points {@link NumberHolder} The cost of the pokemon.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.STARTER_COST,
|
|
||||||
species: SpeciesId,
|
|
||||||
cost: NumberHolder,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify a starter after selection.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_MODIFY
|
|
||||||
* @param pokemon {@link Pokemon} The starter pokemon to modify.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.STARTER_MODIFY, pokemon: Pokemon): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that what pokemon you can have in battle.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE
|
|
||||||
* @param pokemon {@link Pokemon} The pokemon to check the validity of.
|
|
||||||
* @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.POKEMON_IN_BATTLE,
|
|
||||||
pokemon: Pokemon,
|
|
||||||
valid: BooleanHolder,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify what fixed battles there are.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.FIXED_BATTLES
|
|
||||||
* @param waveIndex {@link Number} The current wave index.
|
|
||||||
* @param battleConfig {@link FixedBattleConfig} The battle config to modify.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.FIXED_BATTLES,
|
|
||||||
waveIndex: number,
|
|
||||||
battleConfig: FixedBattleConfig,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify type effectiveness.
|
|
||||||
* @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS
|
|
||||||
* @param effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: NumberHolder): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify what level AI are.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL
|
|
||||||
* @param level {@link NumberHolder} The generated level of the pokemon.
|
|
||||||
* @param levelCap {@link Number} The maximum level cap for the current wave.
|
|
||||||
* @param isTrainer {@link Boolean} Whether this is a trainer pokemon.
|
|
||||||
* @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.AI_LEVEL,
|
|
||||||
level: NumberHolder,
|
|
||||||
levelCap: number,
|
|
||||||
isTrainer: boolean,
|
|
||||||
isBoss: boolean,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify how many move slots the AI has.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS
|
|
||||||
* @param pokemon {@link Pokemon} The pokemon being considered.
|
|
||||||
* @param moveSlots {@link NumberHolder} The amount of move slots.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.AI_MOVE_SLOTS,
|
|
||||||
pokemon: Pokemon,
|
|
||||||
moveSlots: NumberHolder,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify whether a pokemon has its passive.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS
|
|
||||||
* @param pokemon {@link Pokemon} The pokemon to modify.
|
|
||||||
* @param hasPassive {@link BooleanHolder} Whether it has its passive.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.PASSIVE_ACCESS,
|
|
||||||
pokemon: Pokemon,
|
|
||||||
hasPassive: BooleanHolder,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify the game modes settings.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.GAME_MODE_MODIFY
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.GAME_MODE_MODIFY): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify what level a pokemon can access a move.
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.MOVE_ACCESS
|
|
||||||
* @param pokemon {@link Pokemon} What pokemon would learn the move.
|
|
||||||
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
|
||||||
* @param move {@link MoveId} The move in question.
|
|
||||||
* @param level {@link NumberHolder} The level threshold for access.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.MOVE_ACCESS,
|
|
||||||
pokemon: Pokemon,
|
|
||||||
moveSource: MoveSourceType,
|
|
||||||
move: MoveId,
|
|
||||||
level: NumberHolder,
|
|
||||||
): boolean;
|
|
||||||
/**
|
|
||||||
* Apply all challenges that modify what weight a pokemon gives to move generation
|
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.MOVE_WEIGHT
|
|
||||||
* @param pokemon {@link Pokemon} What pokemon would learn the move.
|
|
||||||
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
|
||||||
* @param move {@link MoveId} The move in question.
|
|
||||||
* @param weight {@link NumberHolder} The weight of the move.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
|
||||||
*/
|
|
||||||
export function applyChallenges(
|
|
||||||
challengeType: ChallengeType.MOVE_WEIGHT,
|
|
||||||
pokemon: Pokemon,
|
|
||||||
moveSource: MoveSourceType,
|
|
||||||
move: MoveId,
|
|
||||||
weight: NumberHolder,
|
|
||||||
): boolean;
|
|
||||||
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that conditionally enable or disable automatic party healing during biome transitions
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.PARTY_HEAL}
|
|
||||||
* @returns Whether party healing is enabled or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.PARTY_HEAL): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that conditionally enable or disable the shop
|
|
||||||
* @returns Whether the shop is or is not available after a wave
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.SHOP): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that validate whether a pokemon can be added to the player's party or not
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.POKEMON_ADD_TO_PARTY}
|
|
||||||
* @param pokemon - The pokemon being caught
|
|
||||||
* @return Whether the pokemon can be added to the party or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.POKEMON_ADD_TO_PARTY, pokemon: EnemyPokemon): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that validate whether a pokemon is allowed to fuse or not
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.POKEMON_FUSION}
|
|
||||||
* @param pokemon - The pokemon being checked
|
|
||||||
* @returns Whether the selected pokemon is allowed to fuse or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.POKEMON_FUSION, pokemon: PlayerPokemon): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that validate whether particular moves can or cannot be used
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.POKEMON_MOVE}
|
|
||||||
* @param moveId - The move being checked
|
|
||||||
* @returns Whether the move can be used or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.POKEMON_MOVE, moveId: MoveId): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that validate whether particular items are or are not sold in the shop
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.SHOP_ITEM}
|
|
||||||
* @param shopItem - The item being checked
|
|
||||||
* @returns Whether the item should be added to the shop or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.SHOP_ITEM, shopItem: ModifierTypeOption | null): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that validate whether particular items will be given as a reward after a wave
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.WAVE_REWARD}
|
|
||||||
* @param reward - The reward being checked
|
|
||||||
* @returns Whether the reward should be added to the reward options or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.WAVE_REWARD, reward: ModifierTypeOption | null): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges that prevent recovery from fainting
|
|
||||||
* @param challengeType - {@linkcode ChallengeType.PREVENT_REVIVE}
|
|
||||||
* @returns Whether fainting is a permanent status or not
|
|
||||||
*/
|
|
||||||
export function applyChallenges(challengeType: ChallengeType.PREVENT_REVIVE): boolean;
|
|
||||||
|
|
||||||
export function applyChallenges(challengeType: ChallengeType, ...args: any[]): boolean {
|
|
||||||
let ret = false;
|
|
||||||
globalScene.gameMode.challenges.forEach(c => {
|
|
||||||
if (c.value !== 0) {
|
|
||||||
switch (challengeType) {
|
|
||||||
case ChallengeType.STARTER_CHOICE:
|
|
||||||
ret ||= c.applyStarterChoice(args[0], args[1], args[2]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.STARTER_POINTS:
|
|
||||||
ret ||= c.applyStarterPoints(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.STARTER_COST:
|
|
||||||
ret ||= c.applyStarterCost(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.STARTER_MODIFY:
|
|
||||||
ret ||= c.applyStarterModify(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.POKEMON_IN_BATTLE:
|
|
||||||
ret ||= c.applyPokemonInBattle(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.FIXED_BATTLES:
|
|
||||||
ret ||= c.applyFixedBattle(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.TYPE_EFFECTIVENESS:
|
|
||||||
ret ||= c.applyTypeEffectiveness(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.AI_LEVEL:
|
|
||||||
ret ||= c.applyLevelChange(args[0], args[1], args[2], args[3]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.AI_MOVE_SLOTS:
|
|
||||||
ret ||= c.applyMoveSlot(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.PASSIVE_ACCESS:
|
|
||||||
ret ||= c.applyPassiveAccess(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.GAME_MODE_MODIFY:
|
|
||||||
ret ||= c.applyGameModeModify();
|
|
||||||
break;
|
|
||||||
case ChallengeType.MOVE_ACCESS:
|
|
||||||
ret ||= c.applyMoveAccessLevel(args[0], args[1], args[2], args[3]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.MOVE_WEIGHT:
|
|
||||||
ret ||= c.applyMoveWeight(args[0], args[1], args[2], args[3]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.FLIP_STAT:
|
|
||||||
ret ||= c.applyFlipStat(args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.PARTY_HEAL:
|
|
||||||
ret ||= c.applyPartyHeal();
|
|
||||||
break;
|
|
||||||
case ChallengeType.SHOP:
|
|
||||||
ret ||= c.applyShop();
|
|
||||||
break;
|
|
||||||
case ChallengeType.POKEMON_ADD_TO_PARTY:
|
|
||||||
ret ||= c.applyPokemonAddToParty(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.POKEMON_FUSION:
|
|
||||||
ret ||= c.applyPokemonFusion(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.POKEMON_MOVE:
|
|
||||||
ret ||= c.applyPokemonMove(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.SHOP_ITEM:
|
|
||||||
ret ||= c.applyShopItem(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.WAVE_REWARD:
|
|
||||||
ret ||= c.applyWaveReward(args[0]);
|
|
||||||
break;
|
|
||||||
case ChallengeType.PREVENT_REVIVE:
|
|
||||||
ret ||= c.applyPreventRevive();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param source A challenge to copy, or an object of a challenge's properties. Missing values are treated as defaults.
|
* @param source A challenge to copy, or an object of a challenge's properties. Missing values are treated as defaults.
|
||||||
@ -1350,80 +1057,3 @@ export function initChallenges() {
|
|||||||
new PermanentFaintChallenge(),
|
new PermanentFaintChallenge(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges to the given starter (and form) to check its validity.
|
|
||||||
* Differs from {@linkcode checkSpeciesValidForChallenge} which only checks form changes.
|
|
||||||
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
|
||||||
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
|
||||||
* @param soft - 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 BooleanHolder(true);
|
|
||||||
applyChallenges(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 => {
|
|
||||||
// Form check to deal with cases such as Basculin -> Basculegion
|
|
||||||
// TODO: does this miss anything if checking forms of a stage 2 Pokémon?
|
|
||||||
if (!e?.preFormKey || e.preFormKey === species.forms[props.formIndex].formKey) {
|
|
||||||
speciesToCheck.push(e.speciesId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all challenges to the given species (and form) to check its validity.
|
|
||||||
* Differs from {@linkcode checkStarterValidForChallenge} which also checks evolutions.
|
|
||||||
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
|
||||||
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
|
||||||
* @param soft - 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) {
|
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
|
||||||
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
|
|
||||||
if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) {
|
|
||||||
return isValidForChallenge.value;
|
|
||||||
}
|
|
||||||
// If the form in props is valid, return true before checking other form changes
|
|
||||||
if (soft && isValidForChallenge.value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = pokemonFormChanges[species.speciesId].some(f1 => {
|
|
||||||
// Exclude form changes that require the mon to be on the field to begin with
|
|
||||||
if (!("item" in f1.trigger)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return species.forms.some((f2, formIndex) => {
|
|
||||||
if (f1.formKey === f2.formKey) {
|
|
||||||
const formProps = { ...props, formIndex };
|
|
||||||
const isFormValidForChallenge = new BooleanHolder(true);
|
|
||||||
applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps);
|
|
||||||
return isFormValidForChallenge.value;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,6 @@ import {
|
|||||||
TypeBoostTag,
|
TypeBoostTag,
|
||||||
} from "#data/battler-tags";
|
} from "#data/battler-tags";
|
||||||
import { getBerryEffectFunc } from "#data/berry";
|
import { getBerryEffectFunc } from "#data/berry";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allAbilities, allMoves } from "#data/data-lists";
|
import { allAbilities, allMoves } from "#data/data-lists";
|
||||||
import { SpeciesFormChangeRevertWeatherFormTrigger } from "#data/form-change-triggers";
|
import { SpeciesFormChangeRevertWeatherFormTrigger } from "#data/form-change-triggers";
|
||||||
import { DelayedAttackTag } from "#data/positional-tags/positional-tag";
|
import { DelayedAttackTag } from "#data/positional-tags/positional-tag";
|
||||||
@ -93,6 +92,7 @@ import { BooleanHolder, type Constructor, isNullOrUndefined, NumberHolder, randS
|
|||||||
import { getEnumValues } from "#utils/enums";
|
import { getEnumValues } from "#utils/enums";
|
||||||
import { toTitleCase } from "#utils/strings";
|
import { toTitleCase } from "#utils/strings";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function used to conditionally determine execution of a given {@linkcode MoveAttr}.
|
* A function used to conditionally determine execution of a given {@linkcode MoveAttr}.
|
||||||
@ -124,7 +124,7 @@ export abstract class Move implements Localizable {
|
|||||||
/**
|
/**
|
||||||
* Check if the move is of the given subclass without requiring `instanceof`.
|
* Check if the move is of the given subclass without requiring `instanceof`.
|
||||||
*
|
*
|
||||||
* ⚠️ Does _not_ work for {@linkcode ChargingAttackMove} and {@linkcode ChargingSelfStatusMove} subclasses. For those,
|
* ! Does _not_ work for {@linkcode ChargingAttackMove} and {@linkcode ChargingSelfStatusMove} subclasses. For those,
|
||||||
* use {@linkcode isChargingMove} instead.
|
* use {@linkcode isChargingMove} instead.
|
||||||
*
|
*
|
||||||
* @param moveKind - The string name of the move to check against
|
* @param moveKind - The string name of the move to check against
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allMoves } from "#data/data-lists";
|
import { allMoves } from "#data/data-lists";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
import type { MoveId } from "#enums/move-id";
|
import type { MoveId } from "#enums/move-id";
|
||||||
import type { Pokemon } from "#field/pokemon";
|
import type { Pokemon } from "#field/pokemon";
|
||||||
import type { Move } from "#moves/move";
|
import type { Move } from "#moves/move";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { toDmgValue } from "#utils/common";
|
import { toDmgValue } from "#utils/common";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,12 +48,12 @@ export class PokemonMove {
|
|||||||
*/
|
*/
|
||||||
isUsable(pokemon: Pokemon, ignorePp = false, ignoreRestrictionTags = false): boolean {
|
isUsable(pokemon: Pokemon, ignorePp = false, ignoreRestrictionTags = false): boolean {
|
||||||
// TODO: Add Sky Drop's 1 turn stall
|
// TODO: Add Sky Drop's 1 turn stall
|
||||||
const isBattleRestricted = this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon);
|
return (
|
||||||
const hasPp = ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1;
|
!(this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)) &&
|
||||||
const isNotChallengeRestricted = !pokemon.isPlayer() || applyChallenges(ChallengeType.POKEMON_MOVE, this.moveId);
|
(ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1) &&
|
||||||
const isUnimplemented = this.getMove().name.endsWith(" (N)");
|
(!pokemon.isPlayer() || applyChallenges(ChallengeType.POKEMON_MOVE, this.moveId)) &&
|
||||||
|
!this.getMove().name.endsWith(" (N)")
|
||||||
return !isBattleRestricted && hasPp && isNotChallengeRestricted && !isUnimplemented;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMove(): Move {
|
getMove(): Move {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { speciesStarterCosts } from "#balance/starters";
|
import { speciesStarterCosts } from "#balance/starters";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { modifierTypes } from "#data/data-lists";
|
import { modifierTypes } from "#data/data-lists";
|
||||||
import { Gender } from "#data/gender";
|
import { Gender } from "#data/gender";
|
||||||
import {
|
import {
|
||||||
@ -35,6 +34,7 @@ import { achvs } from "#system/achv";
|
|||||||
import type { PartyOption } from "#ui/party-ui-handler";
|
import type { PartyOption } from "#ui/party-ui-handler";
|
||||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
import { PartyUiMode } from "#ui/party-ui-handler";
|
||||||
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#utils/common";
|
import { isNullOrUndefined, randSeedInt } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
@ -40,7 +40,6 @@ import {
|
|||||||
TrappedTag,
|
TrappedTag,
|
||||||
TypeImmuneTag,
|
TypeImmuneTag,
|
||||||
} from "#data/battler-tags";
|
} from "#data/battler-tags";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allAbilities, allMoves } from "#data/data-lists";
|
import { allAbilities, allMoves } from "#data/data-lists";
|
||||||
import { getLevelTotalExp } from "#data/exp";
|
import { getLevelTotalExp } from "#data/exp";
|
||||||
import {
|
import {
|
||||||
@ -149,6 +148,7 @@ import { EnemyBattleInfo } from "#ui/enemy-battle-info";
|
|||||||
import type { PartyOption } from "#ui/party-ui-handler";
|
import type { PartyOption } from "#ui/party-ui-handler";
|
||||||
import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
|
import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
|
||||||
import { PlayerBattleInfo } from "#ui/player-battle-info";
|
import { PlayerBattleInfo } from "#ui/player-battle-info";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import {
|
import {
|
||||||
BooleanHolder,
|
BooleanHolder,
|
||||||
type Constructor,
|
type Constructor,
|
||||||
|
@ -2,7 +2,7 @@ import { FixedBattleConfig } from "#app/battle";
|
|||||||
import { CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { allChallenges, applyChallenges, type Challenge, copyChallenge } from "#data/challenge";
|
import { allChallenges, type Challenge, copyChallenge } from "#data/challenge";
|
||||||
import { getDailyStartingBiome } from "#data/daily-run";
|
import { getDailyStartingBiome } from "#data/daily-run";
|
||||||
import { allSpecies } from "#data/data-lists";
|
import { allSpecies } from "#data/data-lists";
|
||||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||||
@ -13,6 +13,7 @@ import { GameModes } from "#enums/game-modes";
|
|||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import type { Arena } from "#field/arena";
|
import type { Arena } from "#field/arena";
|
||||||
import { classicFixedBattles, type FixedBattleConfigs } from "#trainers/fixed-battle-configs";
|
import { classicFixedBattles, type FixedBattleConfigs } from "#trainers/fixed-battle-configs";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#utils/common";
|
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import Overrides from "#app/overrides";
|
|||||||
import { EvolutionItem, pokemonEvolutions } from "#balance/pokemon-evolutions";
|
import { EvolutionItem, pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||||
import { tmPoolTiers, tmSpecies } from "#balance/tms";
|
import { tmPoolTiers, tmSpecies } from "#balance/tms";
|
||||||
import { getBerryEffectDescription, getBerryName } from "#data/berry";
|
import { getBerryEffectDescription, getBerryName } from "#data/berry";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allMoves, modifierTypes } from "#data/data-lists";
|
import { allMoves, modifierTypes } from "#data/data-lists";
|
||||||
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
||||||
import { getNatureName, getNatureStatMultiplier } from "#data/nature";
|
import { getNatureName, getNatureStatMultiplier } from "#data/nature";
|
||||||
@ -118,6 +117,7 @@ import type { ModifierTypeFunc, WeightedModifierTypeWeightFunc } from "#types/mo
|
|||||||
import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/party-ui-handler";
|
import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/party-ui-handler";
|
||||||
import { PartyUiHandler } from "#ui/party-ui-handler";
|
import { PartyUiHandler } from "#ui/party-ui-handler";
|
||||||
import { getModifierTierTextTint } from "#ui/text";
|
import { getModifierTierTextTint } from "#ui/text";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { formatMoney, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#utils/common";
|
import { formatMoney, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#utils/common";
|
||||||
import { getEnumKeys, getEnumValues } from "#utils/enums";
|
import { getEnumKeys, getEnumValues } from "#utils/enums";
|
||||||
import { getModifierPoolForType, getModifierType } from "#utils/modifier-utils";
|
import { getModifierPoolForType, getModifierType } from "#utils/modifier-utils";
|
||||||
|
@ -2,7 +2,6 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { SubstituteTag } from "#data/battler-tags";
|
import { SubstituteTag } from "#data/battler-tags";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { Gender } from "#data/gender";
|
import { Gender } from "#data/gender";
|
||||||
import {
|
import {
|
||||||
doPokeballBounceAnim,
|
doPokeballBounceAnim,
|
||||||
@ -25,6 +24,7 @@ import { achvs } from "#system/achv";
|
|||||||
import type { PartyOption } from "#ui/party-ui-handler";
|
import type { PartyOption } from "#ui/party-ui-handler";
|
||||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
import { PartyUiMode } from "#ui/party-ui-handler";
|
||||||
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
// TODO: Refactor and split up to allow for overriding capture chance
|
// TODO: Refactor and split up to allow for overriding capture chance
|
||||||
|
@ -3,7 +3,6 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { speciesStarterCosts } from "#balance/starters";
|
import { speciesStarterCosts } from "#balance/starters";
|
||||||
import { TrappedTag } from "#data/battler-tags";
|
import { TrappedTag } from "#data/battler-tags";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { ArenaTagSide } from "#enums/arena-tag-side";
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
@ -23,6 +22,7 @@ import type { MoveTargetSet } from "#moves/move";
|
|||||||
import { getMoveTargets } from "#moves/move-utils";
|
import { getMoveTargets } from "#moves/move-utils";
|
||||||
import { FieldPhase } from "#phases/field-phase";
|
import { FieldPhase } from "#phases/field-phase";
|
||||||
import type { TurnMove } from "#types/turn-move";
|
import type { TurnMove } from "#types/turn-move";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export class CommandPhase extends FieldPhase {
|
export class CommandPhase extends FieldPhase {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
import { BattlePhase } from "#phases/battle-phase";
|
import { BattlePhase } from "#phases/battle-phase";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { fixedInt } from "#utils/common";
|
import { fixedInt } from "#utils/common";
|
||||||
|
|
||||||
export class PartyHealPhase extends BattlePhase {
|
export class PartyHealPhase extends BattlePhase {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { biomeLinks, getBiomeName } from "#balance/biomes";
|
import { biomeLinks, getBiomeName } from "#balance/biomes";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { BiomeId } from "#enums/biome-id";
|
import { BiomeId } from "#enums/biome-id";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier";
|
import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier";
|
||||||
import { BattlePhase } from "#phases/battle-phase";
|
import { BattlePhase } from "#phases/battle-phase";
|
||||||
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { randSeedInt } from "#utils/common";
|
import { randSeedInt } from "#utils/common";
|
||||||
|
|
||||||
export class SelectBiomePhase extends BattlePhase {
|
export class SelectBiomePhase extends BattlePhase {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { Phase } from "#app/phase";
|
import { Phase } from "#app/phase";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { SpeciesFormChangeMoveLearnedTrigger } from "#data/form-change-triggers";
|
import { SpeciesFormChangeMoveLearnedTrigger } from "#data/form-change-triggers";
|
||||||
import { Gender } from "#data/gender";
|
import { Gender } from "#data/gender";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
@ -10,6 +9,7 @@ import { UiMode } from "#enums/ui-mode";
|
|||||||
import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier";
|
import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier";
|
||||||
import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
|
import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
|
||||||
import type { Starter } from "#ui/starter-select-ui-handler";
|
import type { Starter } from "#ui/starter-select-ui-handler";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { isNullOrUndefined } from "#utils/common";
|
import { isNullOrUndefined } from "#utils/common";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { modifierTypes } from "#data/data-lists";
|
import { modifierTypes } from "#data/data-lists";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import type { BattlerIndex } from "#enums/battler-index";
|
import type { BattlerIndex } from "#enums/battler-index";
|
||||||
@ -9,6 +8,7 @@ import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
|||||||
import type { CustomModifierSettings } from "#modifiers/modifier-type";
|
import type { CustomModifierSettings } from "#modifiers/modifier-type";
|
||||||
import { handleMysteryEncounterVictory } from "#mystery-encounters/encounter-phase-utils";
|
import { handleMysteryEncounterVictory } from "#mystery-encounters/encounter-phase-utils";
|
||||||
import { PokemonPhase } from "#phases/pokemon-phase";
|
import { PokemonPhase } from "#phases/pokemon-phase";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
|
|
||||||
export class VictoryPhase extends PokemonPhase {
|
export class VictoryPhase extends PokemonPhase {
|
||||||
public readonly phaseName = "VictoryPhase";
|
public readonly phaseName = "VictoryPhase";
|
||||||
|
@ -11,7 +11,6 @@ import { speciesEggMoves } from "#balance/egg-moves";
|
|||||||
import { pokemonPrevolutions } from "#balance/pokemon-evolutions";
|
import { pokemonPrevolutions } from "#balance/pokemon-evolutions";
|
||||||
import { speciesStarterCosts } from "#balance/starters";
|
import { speciesStarterCosts } from "#balance/starters";
|
||||||
import { ArenaTrapTag } from "#data/arena-tag";
|
import { ArenaTrapTag } from "#data/arena-tag";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allMoves, allSpecies } from "#data/data-lists";
|
import { allMoves, allSpecies } from "#data/data-lists";
|
||||||
import type { Egg } from "#data/egg";
|
import type { Egg } from "#data/egg";
|
||||||
import { pokemonFormChanges } from "#data/pokemon-forms";
|
import { pokemonFormChanges } from "#data/pokemon-forms";
|
||||||
@ -63,6 +62,7 @@ import { VoucherType, vouchers } from "#system/voucher";
|
|||||||
import { trainerConfigs } from "#trainers/trainer-config";
|
import { trainerConfigs } from "#trainers/trainer-config";
|
||||||
import type { DexData, DexEntry } from "#types/dex-data";
|
import type { DexData, DexEntry } from "#types/dex-data";
|
||||||
import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
|
import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common";
|
import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common";
|
||||||
import { decrypt, encrypt } from "#utils/data";
|
import { decrypt, encrypt } from "#utils/data";
|
||||||
import { getEnumKeys } from "#utils/enums";
|
import { getEnumKeys } from "#utils/enums";
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||||
import { applyChallenges } from "#data/challenge";
|
|
||||||
import { allMoves } from "#data/data-lists";
|
import { allMoves } from "#data/data-lists";
|
||||||
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
||||||
import { Gender, getGenderColor, getGenderSymbol } from "#data/gender";
|
import { Gender, getGenderColor, getGenderSymbol } from "#data/gender";
|
||||||
@ -26,6 +25,7 @@ import { MoveInfoOverlay } from "#ui/move-info-overlay";
|
|||||||
import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
|
import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-handler";
|
||||||
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
|
import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
|
||||||
import { addWindow } from "#ui/ui-theme";
|
import { addWindow } from "#ui/ui-theme";
|
||||||
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { BooleanHolder, getLocalizedSpriteKey, randInt } from "#utils/common";
|
import { BooleanHolder, getLocalizedSpriteKey, randInt } from "#utils/common";
|
||||||
import { toTitleCase } from "#utils/strings";
|
import { toTitleCase } from "#utils/strings";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
@ -16,7 +16,6 @@ import {
|
|||||||
POKERUS_STARTER_COUNT,
|
POKERUS_STARTER_COUNT,
|
||||||
speciesStarterCosts,
|
speciesStarterCosts,
|
||||||
} from "#balance/starters";
|
} from "#balance/starters";
|
||||||
import { applyChallenges, checkStarterValidForChallenge } from "#data/challenge";
|
|
||||||
import { allAbilities, allMoves, allSpecies } from "#data/data-lists";
|
import { allAbilities, allMoves, allSpecies } from "#data/data-lists";
|
||||||
import { Egg, getEggTierForSpecies } from "#data/egg";
|
import { Egg, getEggTierForSpecies } from "#data/egg";
|
||||||
import { GrowthRate, getGrowthRateColor } from "#data/exp";
|
import { GrowthRate, getGrowthRateColor } from "#data/exp";
|
||||||
@ -60,6 +59,7 @@ import { StarterContainer } from "#ui/starter-container";
|
|||||||
import { StatsContainer } from "#ui/stats-container";
|
import { StatsContainer } from "#ui/stats-container";
|
||||||
import { addBBCodeTextObject, addTextObject } from "#ui/text";
|
import { addBBCodeTextObject, addTextObject } from "#ui/text";
|
||||||
import { addWindow } from "#ui/ui-theme";
|
import { addWindow } from "#ui/ui-theme";
|
||||||
|
import { applyChallenges, checkStarterValidForChallenge } from "#utils/challenge-utils";
|
||||||
import {
|
import {
|
||||||
BooleanHolder,
|
BooleanHolder,
|
||||||
fixedInt,
|
fixedInt,
|
||||||
|
380
src/utils/challenge-utils.ts
Normal file
380
src/utils/challenge-utils.ts
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
import type { FixedBattleConfig } from "#app/battle";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||||
|
import { pokemonFormChanges } from "#data/pokemon-forms";
|
||||||
|
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||||
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
|
import type { MoveId } from "#enums/move-id";
|
||||||
|
import type { MoveSourceType } from "#enums/move-source-type";
|
||||||
|
import type { SpeciesId } from "#enums/species-id";
|
||||||
|
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
|
||||||
|
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||||
|
import type { DexAttrProps } from "#system/game-data";
|
||||||
|
import { BooleanHolder, type NumberHolder } from "./common";
|
||||||
|
import { getPokemonSpecies } from "./pokemon-utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify starter choice.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE
|
||||||
|
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
||||||
|
* @param valid {@link 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.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.STARTER_CHOICE,
|
||||||
|
pokemon: PokemonSpecies,
|
||||||
|
valid: BooleanHolder,
|
||||||
|
dexAttr: DexAttrProps,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify available total starter points.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS
|
||||||
|
* @param points {@link NumberHolder} The amount of points you have available.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: NumberHolder): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify the cost of a starter.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST
|
||||||
|
* @param species {@link SpeciesId} The pokemon to change the cost of.
|
||||||
|
* @param points {@link NumberHolder} The cost of the pokemon.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.STARTER_COST,
|
||||||
|
species: SpeciesId,
|
||||||
|
cost: NumberHolder,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify a starter after selection.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_MODIFY
|
||||||
|
* @param pokemon {@link Pokemon} The starter pokemon to modify.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.STARTER_MODIFY, pokemon: Pokemon): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that what pokemon you can have in battle.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE
|
||||||
|
* @param pokemon {@link Pokemon} The pokemon to check the validity of.
|
||||||
|
* @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.POKEMON_IN_BATTLE,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
valid: BooleanHolder,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify what fixed battles there are.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.FIXED_BATTLES
|
||||||
|
* @param waveIndex {@link Number} The current wave index.
|
||||||
|
* @param battleConfig {@link FixedBattleConfig} The battle config to modify.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.FIXED_BATTLES,
|
||||||
|
waveIndex: number,
|
||||||
|
battleConfig: FixedBattleConfig,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify type effectiveness.
|
||||||
|
* @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS
|
||||||
|
* @param effectiveness {@linkcode NumberHolder} The current effectiveness of the move.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: NumberHolder): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify what level AI are.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL
|
||||||
|
* @param level {@link NumberHolder} The generated level of the pokemon.
|
||||||
|
* @param levelCap {@link Number} The maximum level cap for the current wave.
|
||||||
|
* @param isTrainer {@link Boolean} Whether this is a trainer pokemon.
|
||||||
|
* @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.AI_LEVEL,
|
||||||
|
level: NumberHolder,
|
||||||
|
levelCap: number,
|
||||||
|
isTrainer: boolean,
|
||||||
|
isBoss: boolean,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify how many move slots the AI has.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS
|
||||||
|
* @param pokemon {@link Pokemon} The pokemon being considered.
|
||||||
|
* @param moveSlots {@link NumberHolder} The amount of move slots.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.AI_MOVE_SLOTS,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
moveSlots: NumberHolder,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify whether a pokemon has its passive.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS
|
||||||
|
* @param pokemon {@link Pokemon} The pokemon to modify.
|
||||||
|
* @param hasPassive {@link BooleanHolder} Whether it has its passive.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.PASSIVE_ACCESS,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
hasPassive: BooleanHolder,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify the game modes settings.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.GAME_MODE_MODIFY
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.GAME_MODE_MODIFY): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify what level a pokemon can access a move.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.MOVE_ACCESS
|
||||||
|
* @param pokemon {@link Pokemon} What pokemon would learn the move.
|
||||||
|
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
||||||
|
* @param move {@link MoveId} The move in question.
|
||||||
|
* @param level {@link NumberHolder} The level threshold for access.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.MOVE_ACCESS,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
moveSource: MoveSourceType,
|
||||||
|
move: MoveId,
|
||||||
|
level: NumberHolder,
|
||||||
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify what weight a pokemon gives to move generation
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.MOVE_WEIGHT
|
||||||
|
* @param pokemon {@link Pokemon} What pokemon would learn the move.
|
||||||
|
* @param moveSource {@link MoveSourceType} What source the pokemon would get the move from.
|
||||||
|
* @param move {@link MoveId} The move in question.
|
||||||
|
* @param weight {@link NumberHolder} The weight of the move.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.MOVE_WEIGHT,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
moveSource: MoveSourceType,
|
||||||
|
move: MoveId,
|
||||||
|
weight: NumberHolder,
|
||||||
|
): boolean;
|
||||||
|
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that conditionally enable or disable automatic party healing during biome transitions
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.PARTY_HEAL}
|
||||||
|
* @returns Whether party healing is enabled or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.PARTY_HEAL): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that conditionally enable or disable the shop
|
||||||
|
* @returns Whether the shop is or is not available after a wave
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.SHOP): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that validate whether a pokemon can be added to the player's party or not
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.POKEMON_ADD_TO_PARTY}
|
||||||
|
* @param pokemon - The pokemon being caught
|
||||||
|
* @return Whether the pokemon can be added to the party or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.POKEMON_ADD_TO_PARTY, pokemon: EnemyPokemon): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that validate whether a pokemon is allowed to fuse or not
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.POKEMON_FUSION}
|
||||||
|
* @param pokemon - The pokemon being checked
|
||||||
|
* @returns Whether the selected pokemon is allowed to fuse or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.POKEMON_FUSION, pokemon: PlayerPokemon): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that validate whether particular moves can or cannot be used
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.POKEMON_MOVE}
|
||||||
|
* @param moveId - The move being checked
|
||||||
|
* @returns Whether the move can be used or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.POKEMON_MOVE, moveId: MoveId): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that validate whether particular items are or are not sold in the shop
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.SHOP_ITEM}
|
||||||
|
* @param shopItem - The item being checked
|
||||||
|
* @returns Whether the item should be added to the shop or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.SHOP_ITEM, shopItem: ModifierTypeOption | null): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that validate whether particular items will be given as a reward after a wave
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.WAVE_REWARD}
|
||||||
|
* @param reward - The reward being checked
|
||||||
|
* @returns Whether the reward should be added to the reward options or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.WAVE_REWARD, reward: ModifierTypeOption | null): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges that prevent recovery from fainting
|
||||||
|
* @param challengeType - {@linkcode ChallengeType.PREVENT_REVIVE}
|
||||||
|
* @returns Whether fainting is a permanent status or not
|
||||||
|
*/
|
||||||
|
export function applyChallenges(challengeType: ChallengeType.PREVENT_REVIVE): boolean;
|
||||||
|
|
||||||
|
export function applyChallenges(challengeType: ChallengeType, ...args: any[]): boolean {
|
||||||
|
let ret = false;
|
||||||
|
globalScene.gameMode.challenges.forEach(c => {
|
||||||
|
if (c.value !== 0) {
|
||||||
|
switch (challengeType) {
|
||||||
|
case ChallengeType.STARTER_CHOICE:
|
||||||
|
ret ||= c.applyStarterChoice(args[0], args[1], args[2]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.STARTER_POINTS:
|
||||||
|
ret ||= c.applyStarterPoints(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.STARTER_COST:
|
||||||
|
ret ||= c.applyStarterCost(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.STARTER_MODIFY:
|
||||||
|
ret ||= c.applyStarterModify(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.POKEMON_IN_BATTLE:
|
||||||
|
ret ||= c.applyPokemonInBattle(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.FIXED_BATTLES:
|
||||||
|
ret ||= c.applyFixedBattle(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.TYPE_EFFECTIVENESS:
|
||||||
|
ret ||= c.applyTypeEffectiveness(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.AI_LEVEL:
|
||||||
|
ret ||= c.applyLevelChange(args[0], args[1], args[2], args[3]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.AI_MOVE_SLOTS:
|
||||||
|
ret ||= c.applyMoveSlot(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.PASSIVE_ACCESS:
|
||||||
|
ret ||= c.applyPassiveAccess(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.GAME_MODE_MODIFY:
|
||||||
|
ret ||= c.applyGameModeModify();
|
||||||
|
break;
|
||||||
|
case ChallengeType.MOVE_ACCESS:
|
||||||
|
ret ||= c.applyMoveAccessLevel(args[0], args[1], args[2], args[3]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.MOVE_WEIGHT:
|
||||||
|
ret ||= c.applyMoveWeight(args[0], args[1], args[2], args[3]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.FLIP_STAT:
|
||||||
|
ret ||= c.applyFlipStat(args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.PARTY_HEAL:
|
||||||
|
ret ||= c.applyPartyHeal();
|
||||||
|
break;
|
||||||
|
case ChallengeType.SHOP:
|
||||||
|
ret ||= c.applyShop();
|
||||||
|
break;
|
||||||
|
case ChallengeType.POKEMON_ADD_TO_PARTY:
|
||||||
|
ret ||= c.applyPokemonAddToParty(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.POKEMON_FUSION:
|
||||||
|
ret ||= c.applyPokemonFusion(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.POKEMON_MOVE:
|
||||||
|
ret ||= c.applyPokemonMove(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.SHOP_ITEM:
|
||||||
|
ret ||= c.applyShopItem(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.WAVE_REWARD:
|
||||||
|
ret ||= c.applyWaveReward(args[0]);
|
||||||
|
break;
|
||||||
|
case ChallengeType.PREVENT_REVIVE:
|
||||||
|
ret ||= c.applyPreventRevive();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges to the given starter (and form) to check its validity.
|
||||||
|
* Differs from {@linkcode checkSpeciesValidForChallenge} which only checks form changes.
|
||||||
|
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
||||||
|
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
||||||
|
* @param soft - 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 BooleanHolder(true);
|
||||||
|
applyChallenges(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 => {
|
||||||
|
// Form check to deal with cases such as Basculin -> Basculegion
|
||||||
|
// TODO: does this miss anything if checking forms of a stage 2 Pokémon?
|
||||||
|
if (!e?.preFormKey || e.preFormKey === species.forms[props.formIndex].formKey) {
|
||||||
|
speciesToCheck.push(e.speciesId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges to the given species (and form) to check its validity.
|
||||||
|
* Differs from {@linkcode checkStarterValidForChallenge} which also checks evolutions.
|
||||||
|
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
||||||
|
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
||||||
|
* @param soft - 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) {
|
||||||
|
const isValidForChallenge = new BooleanHolder(true);
|
||||||
|
applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
|
||||||
|
if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) {
|
||||||
|
return isValidForChallenge.value;
|
||||||
|
}
|
||||||
|
// If the form in props is valid, return true before checking other form changes
|
||||||
|
if (soft && isValidForChallenge.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = pokemonFormChanges[species.speciesId].some(f1 => {
|
||||||
|
// Exclude form changes that require the mon to be on the field to begin with
|
||||||
|
if (!("item" in f1.trigger)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return species.forms.some((f2, formIndex) => {
|
||||||
|
if (f1.formKey === f2.formKey) {
|
||||||
|
const formProps = { ...props, formIndex };
|
||||||
|
const isFormValidForChallenge = new BooleanHolder(true);
|
||||||
|
applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps);
|
||||||
|
return isFormValidForChallenge.value;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user