mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-07 07:59:26 +02:00
Separate Challenge Utility Functions
This commit is contained in:
parent
8976b0d3a2
commit
5c2c7cf3d1
@ -1,15 +1,11 @@
|
||||
import type { FixedBattleConfig } from "#app/battle";
|
||||
import { getRandomTrainerFunc } from "#app/battle";
|
||||
import { defaultStarterSpecies } from "#app/constants";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||
import { speciesStarterCosts } from "#balance/starters";
|
||||
import { getEggTierForSpecies } from "#data/egg";
|
||||
import { pokemonFormChanges } from "#data/pokemon-forms";
|
||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||
import { getPokemonSpeciesForm } from "#data/pokemon-species";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
import { ChallengeType } from "#enums/challenge-type";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
import { TypeColor, TypeShadow } from "#enums/color";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
@ -27,7 +23,7 @@ import { Trainer } from "#field/trainer";
|
||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||
import { PokemonMove } from "#moves/pokemon-move";
|
||||
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 { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
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.
|
||||
@ -1350,80 +1057,3 @@ export function initChallenges() {
|
||||
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,
|
||||
} from "#data/battler-tags";
|
||||
import { getBerryEffectFunc } from "#data/berry";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { allAbilities, allMoves } from "#data/data-lists";
|
||||
import { SpeciesFormChangeRevertWeatherFormTrigger } from "#data/form-change-triggers";
|
||||
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 { toTitleCase } from "#utils/strings";
|
||||
import i18next from "i18next";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*
|
||||
* ⚠️ 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.
|
||||
*
|
||||
* @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 { ChallengeType } from "#enums/challenge-type";
|
||||
import type { MoveId } from "#enums/move-id";
|
||||
import type { Pokemon } from "#field/pokemon";
|
||||
import type { Move } from "#moves/move";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { toDmgValue } from "#utils/common";
|
||||
|
||||
/**
|
||||
@ -48,12 +48,12 @@ export class PokemonMove {
|
||||
*/
|
||||
isUsable(pokemon: Pokemon, ignorePp = false, ignoreRestrictionTags = false): boolean {
|
||||
// TODO: Add Sky Drop's 1 turn stall
|
||||
const isBattleRestricted = this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon);
|
||||
const hasPp = ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1;
|
||||
const isNotChallengeRestricted = !pokemon.isPlayer() || applyChallenges(ChallengeType.POKEMON_MOVE, this.moveId);
|
||||
const isUnimplemented = this.getMove().name.endsWith(" (N)");
|
||||
|
||||
return !isBattleRestricted && hasPp && isNotChallengeRestricted && !isUnimplemented;
|
||||
return (
|
||||
!(this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId, pokemon)) &&
|
||||
(ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1) &&
|
||||
(!pokemon.isPlayer() || applyChallenges(ChallengeType.POKEMON_MOVE, this.moveId)) &&
|
||||
!this.getMove().name.endsWith(" (N)")
|
||||
);
|
||||
}
|
||||
|
||||
getMove(): Move {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { speciesStarterCosts } from "#balance/starters";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { modifierTypes } from "#data/data-lists";
|
||||
import { Gender } from "#data/gender";
|
||||
import {
|
||||
@ -35,6 +34,7 @@ import { achvs } from "#system/achv";
|
||||
import type { PartyOption } from "#ui/party-ui-handler";
|
||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
||||
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { isNullOrUndefined, randSeedInt } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import i18next from "i18next";
|
||||
|
@ -40,7 +40,6 @@ import {
|
||||
TrappedTag,
|
||||
TypeImmuneTag,
|
||||
} from "#data/battler-tags";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { allAbilities, allMoves } from "#data/data-lists";
|
||||
import { getLevelTotalExp } from "#data/exp";
|
||||
import {
|
||||
@ -149,6 +148,7 @@ import { EnemyBattleInfo } from "#ui/enemy-battle-info";
|
||||
import type { PartyOption } from "#ui/party-ui-handler";
|
||||
import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler";
|
||||
import { PlayerBattleInfo } from "#ui/player-battle-info";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import {
|
||||
BooleanHolder,
|
||||
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 { globalScene } from "#app/global-scene";
|
||||
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 { allSpecies } from "#data/data-lists";
|
||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||
@ -13,6 +13,7 @@ import { GameModes } from "#enums/game-modes";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import type { Arena } from "#field/arena";
|
||||
import { classicFixedBattles, type FixedBattleConfigs } from "#trainers/fixed-battle-configs";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#utils/common";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
@ -6,7 +6,6 @@ import Overrides from "#app/overrides";
|
||||
import { EvolutionItem, pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||
import { tmPoolTiers, tmSpecies } from "#balance/tms";
|
||||
import { getBerryEffectDescription, getBerryName } from "#data/berry";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { allMoves, modifierTypes } from "#data/data-lists";
|
||||
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
||||
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 { PartyUiHandler } from "#ui/party-ui-handler";
|
||||
import { getModifierTierTextTint } from "#ui/text";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { formatMoney, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#utils/common";
|
||||
import { getEnumKeys, getEnumValues } from "#utils/enums";
|
||||
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 { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { SubstituteTag } from "#data/battler-tags";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { Gender } from "#data/gender";
|
||||
import {
|
||||
doPokeballBounceAnim,
|
||||
@ -25,6 +24,7 @@ import { achvs } from "#system/achv";
|
||||
import type { PartyOption } from "#ui/party-ui-handler";
|
||||
import { PartyUiMode } from "#ui/party-ui-handler";
|
||||
import { SummaryUiMode } from "#ui/summary-ui-handler";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import i18next from "i18next";
|
||||
|
||||
// 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 { speciesStarterCosts } from "#balance/starters";
|
||||
import { TrappedTag } from "#data/battler-tags";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
@ -23,6 +22,7 @@ import type { MoveTargetSet } from "#moves/move";
|
||||
import { getMoveTargets } from "#moves/move-utils";
|
||||
import { FieldPhase } from "#phases/field-phase";
|
||||
import type { TurnMove } from "#types/turn-move";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import i18next from "i18next";
|
||||
|
||||
export class CommandPhase extends FieldPhase {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { ChallengeType } from "#enums/challenge-type";
|
||||
import { BattlePhase } from "#phases/battle-phase";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { fixedInt } from "#utils/common";
|
||||
|
||||
export class PartyHealPhase extends BattlePhase {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { biomeLinks, getBiomeName } from "#balance/biomes";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { BiomeId } from "#enums/biome-id";
|
||||
import { ChallengeType } from "#enums/challenge-type";
|
||||
import { UiMode } from "#enums/ui-mode";
|
||||
import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier";
|
||||
import { BattlePhase } from "#phases/battle-phase";
|
||||
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { randSeedInt } from "#utils/common";
|
||||
|
||||
export class SelectBiomePhase extends BattlePhase {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import Overrides from "#app/overrides";
|
||||
import { Phase } from "#app/phase";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { SpeciesFormChangeMoveLearnedTrigger } from "#data/form-change-triggers";
|
||||
import { Gender } from "#data/gender";
|
||||
import { ChallengeType } from "#enums/challenge-type";
|
||||
@ -10,6 +9,7 @@ import { UiMode } from "#enums/ui-mode";
|
||||
import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier";
|
||||
import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
|
||||
import type { Starter } from "#ui/starter-select-ui-handler";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { isNullOrUndefined } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { timedEventManager } from "#app/global-event-manager";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { modifierTypes } from "#data/data-lists";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
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 { handleMysteryEncounterVictory } from "#mystery-encounters/encounter-phase-utils";
|
||||
import { PokemonPhase } from "#phases/pokemon-phase";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
|
||||
export class VictoryPhase extends PokemonPhase {
|
||||
public readonly phaseName = "VictoryPhase";
|
||||
|
@ -11,7 +11,6 @@ import { speciesEggMoves } from "#balance/egg-moves";
|
||||
import { pokemonPrevolutions } from "#balance/pokemon-evolutions";
|
||||
import { speciesStarterCosts } from "#balance/starters";
|
||||
import { ArenaTrapTag } from "#data/arena-tag";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { allMoves, allSpecies } from "#data/data-lists";
|
||||
import type { Egg } from "#data/egg";
|
||||
import { pokemonFormChanges } from "#data/pokemon-forms";
|
||||
@ -63,6 +62,7 @@ import { VoucherType, vouchers } from "#system/voucher";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import type { DexData, DexEntry } from "#types/dex-data";
|
||||
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 { decrypt, encrypt } from "#utils/data";
|
||||
import { getEnumKeys } from "#utils/enums";
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||
import { applyChallenges } from "#data/challenge";
|
||||
import { allMoves } from "#data/data-lists";
|
||||
import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers";
|
||||
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 { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text";
|
||||
import { addWindow } from "#ui/ui-theme";
|
||||
import { applyChallenges } from "#utils/challenge-utils";
|
||||
import { BooleanHolder, getLocalizedSpriteKey, randInt } from "#utils/common";
|
||||
import { toTitleCase } from "#utils/strings";
|
||||
import i18next from "i18next";
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
POKERUS_STARTER_COUNT,
|
||||
speciesStarterCosts,
|
||||
} from "#balance/starters";
|
||||
import { applyChallenges, checkStarterValidForChallenge } from "#data/challenge";
|
||||
import { allAbilities, allMoves, allSpecies } from "#data/data-lists";
|
||||
import { Egg, getEggTierForSpecies } from "#data/egg";
|
||||
import { GrowthRate, getGrowthRateColor } from "#data/exp";
|
||||
@ -60,6 +59,7 @@ import { StarterContainer } from "#ui/starter-container";
|
||||
import { StatsContainer } from "#ui/stats-container";
|
||||
import { addBBCodeTextObject, addTextObject } from "#ui/text";
|
||||
import { addWindow } from "#ui/ui-theme";
|
||||
import { applyChallenges, checkStarterValidForChallenge } from "#utils/challenge-utils";
|
||||
import {
|
||||
BooleanHolder,
|
||||
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