mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-18 14:22:19 +02:00
Merge 68016ca9c6
into 6add614e1c
This commit is contained in:
commit
b7cfb46a9a
@ -170,6 +170,7 @@ import { StatusEffect } from "#enums/status-effect";
|
||||
import { initGlobalScene } from "#app/global-scene";
|
||||
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
|
||||
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
|
||||
import { applyChallenges, ChallengeType } from "./data/challenge";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
@ -1082,6 +1083,8 @@ export default class BattleScene extends SceneBase {
|
||||
postProcess(pokemon);
|
||||
}
|
||||
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, pokemon);
|
||||
|
||||
for (let i = 0; i < pokemon.ivs.length; i++) {
|
||||
if (OPP_IVS_OVERRIDE_VALIDATED[i] > -1) {
|
||||
pokemon.ivs[i] = OPP_IVS_OVERRIDE_VALIDATED[i];
|
||||
|
@ -14,6 +14,8 @@ import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifi
|
||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||
import { speciesStarterCosts } from "./starters";
|
||||
import i18next from "i18next";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
import { Stat } from "#enums/stat";
|
||||
|
||||
|
||||
export enum SpeciesWildEvolutionDelay {
|
||||
@ -90,7 +92,7 @@ export class SpeciesFormEvolution {
|
||||
public evoFormKey: string | null;
|
||||
public level: number;
|
||||
public item: EvolutionItem | null;
|
||||
public condition: SpeciesEvolutionCondition | null;
|
||||
public condition: SpeciesEvolutionCondition | null; // TODO: Add a ChallengeType to change evolution conditions based on what kind of condition it is (use an enum)
|
||||
public wildDelay: SpeciesWildEvolutionDelay;
|
||||
public description = "";
|
||||
|
||||
@ -179,7 +181,8 @@ class TimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
class MoveEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
constructor(move: Moves) {
|
||||
super(p => p.moveset.filter(m => m.moveId === move).length > 0);
|
||||
// TODO: Remove deprecated Challenge check
|
||||
super(p => p.moveset.filter(m => m.moveId === move).length > 0 || globalScene.gameMode.hasChallenge(Challenges.METRONOME));
|
||||
this.move = move;
|
||||
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
this.description = i18next.t("pokemonEvolutions:move", { move: i18next.t(`move:${moveKey}.name`) });
|
||||
@ -218,7 +221,13 @@ class FriendshipMoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public amount: number;
|
||||
public type: PokemonType;
|
||||
constructor(amount: number, type: PokemonType) {
|
||||
super(p => p.friendship >= amount && !!p.getMoveset().find(m => m?.getMove().type === type));
|
||||
// TODO: Remove deprecated Challenge check
|
||||
super(p =>
|
||||
p.friendship >= amount &&
|
||||
(!!p.getMoveset().find(m => m?.getMove().type === type ||
|
||||
(globalScene.gameMode.hasChallenge(Challenges.METRONOME) &&
|
||||
!!globalScene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(type) > -1)
|
||||
))));
|
||||
this.amount = amount;
|
||||
this.type = type;
|
||||
this.description = i18next.t("pokemonEvolutions:friendshipMoveType", { type: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`) });
|
||||
@ -262,7 +271,10 @@ class WeatherEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
class MoveTypeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public type: PokemonType;
|
||||
constructor(type: PokemonType) {
|
||||
super(p => p.moveset.filter(m => m?.getMove().type === type).length > 0);
|
||||
// TODO: Remove deprecated Challenge check
|
||||
super(p => p.moveset.filter(m => m?.getMove().type === type).length > 0 ||
|
||||
(globalScene.gameMode.hasChallenge(Challenges.METRONOME) &&
|
||||
!!globalScene.getPlayerParty().find(p => p.getTypes(false, false, true).indexOf(type) > -1)));
|
||||
this.type = type;
|
||||
this.description = i18next.t("pokemonEvolutions:moveType", { type: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`) });
|
||||
}
|
||||
@ -281,7 +293,13 @@ class TreasureEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
class TyrogueEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
constructor(move: Moves) {
|
||||
// TODO: Remove deprecated Challenge check
|
||||
super(p =>
|
||||
(globalScene.gameMode.hasChallenge(Challenges.METRONOME) && ( // Metronome mode = no moves, do it the old fashioned way
|
||||
(move === Moves.LOW_SWEEP && p.stats[Stat.ATK] > p.stats[Stat.DEF]) ||
|
||||
(move === Moves.MACH_PUNCH && p.stats[Stat.DEF] > p.stats[Stat.ATK]) ||
|
||||
(move === Moves.RAPID_SPIN && p.stats[Stat.DEF] === p.stats[Stat.ATK])
|
||||
)) ||
|
||||
p.getMoveset(true).find(m => m && [ Moves.LOW_SWEEP, Moves.MACH_PUNCH, Moves.RAPID_SPIN ].includes(m.moveId))?.moveId === move);
|
||||
this.move = move;
|
||||
const moveKey = Moves[this.move].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("");
|
||||
@ -302,12 +320,19 @@ class MoveTimeOfDayEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
public move: Moves;
|
||||
public timesOfDay: TimeOfDay[];
|
||||
constructor(move: Moves, tod: "day" | "night") {
|
||||
// TODO: Remove deprecated Challenge check
|
||||
if (tod === "day") {
|
||||
super(p => p.moveset.filter(m => m.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
|
||||
super(p =>
|
||||
(p.moveset.filter(m => m.moveId === move).length > 0 ||
|
||||
globalScene.gameMode.hasChallenge(Challenges.METRONOME)) &&
|
||||
(globalScene.arena.getTimeOfDay() === TimeOfDay.DAWN || globalScene.arena.getTimeOfDay() === TimeOfDay.DAY));
|
||||
this.move = move;
|
||||
this.timesOfDay = [ TimeOfDay.DAWN, TimeOfDay.DAY ];
|
||||
} else if (tod === "night") {
|
||||
super(p => p.moveset.filter(m => m.moveId === move).length > 0 && (globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
|
||||
super(p =>
|
||||
(p.moveset.filter(m => m.moveId === move).length > 0 ||
|
||||
globalScene.gameMode.hasChallenge(Challenges.METRONOME)) &&
|
||||
(globalScene.arena.getTimeOfDay() === TimeOfDay.DUSK || globalScene.arena.getTimeOfDay() === TimeOfDay.NIGHT));
|
||||
this.move = move;
|
||||
this.timesOfDay = [ TimeOfDay.DUSK, TimeOfDay.NIGHT ];
|
||||
} else {
|
||||
@ -330,9 +355,10 @@ class BiomeEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
|
||||
class DunsparceEvolutionCondition extends SpeciesEvolutionCondition {
|
||||
constructor() {
|
||||
// TODO: Remove deprecated Challenge check
|
||||
super(p => {
|
||||
let ret = false;
|
||||
if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) {
|
||||
if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0 || globalScene.gameMode.hasChallenge(Challenges.METRONOME)) {
|
||||
globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
}
|
||||
return ret;
|
||||
|
@ -6,7 +6,7 @@ import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { type EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type { FixedBattleConfig } from "#app/battle";
|
||||
import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle";
|
||||
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||
@ -15,12 +15,14 @@ import { Challenges } from "#enums/challenges";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Nature } from "#enums/nature";
|
||||
import type { Moves } from "#enums/moves";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { TypeColor, TypeShadow } from "#enums/color";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { pokemonFormChanges } from "./pokemon-forms";
|
||||
import { pokemonEvolutions } from "./balance/pokemon-evolutions";
|
||||
import { ModifierPoolType, type ModifierPool, type ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||
import type { LearnMoveType } from "#app/phases/learn-move-phase";
|
||||
|
||||
/** A constant for the default max cost of the starting party before a run */
|
||||
const DEFAULT_PARTY_MAX_COST = 10;
|
||||
@ -93,6 +95,26 @@ export enum ChallengeType {
|
||||
* Modifies what the pokemon stats for Flip Stat Mode.
|
||||
*/
|
||||
FLIP_STAT,
|
||||
/**
|
||||
* Modifies enemy mons AFTER post process function
|
||||
*/
|
||||
ENEMY_POKEMON_MODIFY,
|
||||
/**
|
||||
* Prevents the learning of moves
|
||||
*/
|
||||
BAN_MOVE_LEARNING,
|
||||
/**
|
||||
* Negates PP Usage
|
||||
*/
|
||||
MODIFY_PP_USE,
|
||||
/**
|
||||
* Modifies modifier pools of specified type
|
||||
*/
|
||||
MODIFIER_POOL_MODIFY,
|
||||
/**
|
||||
* Modifies the shop options
|
||||
*/
|
||||
SHOP_MODIFY,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,6 +448,57 @@ export abstract class Challenge {
|
||||
applyFlipStat(_pokemon: Pokemon, _baseStats: number[]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for ENEMY_POKEMON_MODIFY. Derived classes should alter this.
|
||||
* @param _pokemon {@link EnemyPokemon} the mon to be modified
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyEnemyPokemonModify(_pokemon: EnemyPokemon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for BAN_MOVE_LEARNING. Derived classes should alter this.
|
||||
* @param _pokemon {@link Pokemon} Pokemon who wants to learn the move
|
||||
* @param _move {@link Moves} Move being learned
|
||||
* @param _learnType {@link LearnMoveType} How the move is being learned
|
||||
* @param _valid: {@link BooleanHolder} Whether the move is valid for this challenge
|
||||
* @returns {@link boolean} Whether the move should be restricted from learning
|
||||
*/
|
||||
applyBanMoveLearning(_pokemon: Pokemon, _move: Moves, _learnType: LearnMoveType, _valid: Utils.BooleanHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for MODIFY_PP_USE. Derived classes should alter this.
|
||||
* @param _pokemon {@link Pokemon} Pokemon using the move
|
||||
* @param _move {@link Moves} Move being used
|
||||
* @param _usedPP {@link Utils.NumberHolder} Holds the value associated with how much PP should be used
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyModifyPPUsage(_pokemon: Pokemon, _move: Moves, _usedPP: Utils.NumberHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for MODIFIER_POOL_MODIFY. Derived classes should alter this.
|
||||
* @param _poolType {@link ModifierPoolType} What kind of item pool
|
||||
* @param _modifierPool {@link ModifierPool} Pool to modify
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyModifierPoolModify(_poolType: ModifierPoolType, _modifierPool: ModifierPool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An apply function for SHOP_MODIFY. Derived classes should alter this.
|
||||
* @param _options {@link ModifierTypeOption} Array of shop options
|
||||
* @returns {@link boolean} Whether this function did anything.
|
||||
*/
|
||||
applyShopModify(_options: ModifierTypeOption[]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
type ChallengeCondition = (data: GameData) => boolean;
|
||||
@ -833,6 +906,29 @@ export class FreshStartChallenge extends Challenge {
|
||||
return true;
|
||||
}
|
||||
|
||||
override applyModifierPoolModify(poolType: ModifierPoolType, modifierPool: ModifierPool): boolean {
|
||||
if (poolType !== ModifierPoolType.PLAYER) {
|
||||
return false;
|
||||
}
|
||||
let ret = false;
|
||||
|
||||
let idx;
|
||||
const bans = ["EVIOLITE", "MINI_BLACK_HOLE"];
|
||||
const t = [ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.ULTRA, ModifierTier.ROGUE, ModifierTier.MASTER];
|
||||
for (let i = 0; i < t.length; i++) {
|
||||
idx = 0;
|
||||
while (idx > -1) {
|
||||
idx = modifierPool[t[i]].findIndex(p => bans.includes(p.modifierType.id));
|
||||
if (idx > -1) {
|
||||
modifierPool[t[i]].splice(idx, 1);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
override getDifficulty(): number {
|
||||
return 0;
|
||||
}
|
||||
@ -864,6 +960,14 @@ export class InverseBattleChallenge extends Challenge {
|
||||
return 0;
|
||||
}
|
||||
|
||||
override applyEnemyPokemonModify(pokemon: EnemyPokemon): boolean {
|
||||
if (pokemon.species.speciesId === Species.ETERNATUS) {
|
||||
pokemon.moveset[2] = new PokemonMove(Moves.THUNDERBOLT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean {
|
||||
if (effectiveness.value < 1) {
|
||||
effectiveness.value = 2;
|
||||
@ -905,6 +1009,97 @@ export class FlipStatChallenge extends Challenge {
|
||||
}
|
||||
}
|
||||
|
||||
export class MetronomeChallenge extends Challenge {
|
||||
constructor() {
|
||||
super(Challenges.METRONOME, 1);
|
||||
}
|
||||
|
||||
override applyStarterModify(pokemon: Pokemon): boolean {
|
||||
pokemon.moveset = [new PokemonMove(Moves.METRONOME, 0, 3)];
|
||||
return true;
|
||||
}
|
||||
|
||||
override applyEnemyPokemonModify(pokemon: EnemyPokemon): boolean {
|
||||
pokemon.moveset = [new PokemonMove(Moves.METRONOME, 0, 3)];
|
||||
return true;
|
||||
}
|
||||
|
||||
override applyBanMoveLearning(
|
||||
_pokemon: Pokemon,
|
||||
_move: Moves,
|
||||
_learnType: LearnMoveType,
|
||||
valid: Utils.BooleanHolder,
|
||||
): boolean {
|
||||
valid.value = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure 0 PP is used, called when applying other PP usage modifiers such as Pressure
|
||||
* @param _pokemon {@link Pokemon} unused
|
||||
* @param _move {@link Moves} unused
|
||||
* @param usedPP
|
||||
* @returns true
|
||||
*/
|
||||
override applyModifyPPUsage(_pokemon: Pokemon, _move: Moves, usedPP: Utils.NumberHolder): boolean {
|
||||
usedPP.value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
override applyModifierPoolModify(poolType: ModifierPoolType, modifierPool: ModifierPool): boolean {
|
||||
if (poolType !== ModifierPoolType.PLAYER) {
|
||||
return false;
|
||||
}
|
||||
let ret = false;
|
||||
|
||||
let idx;
|
||||
const bans = [
|
||||
"TM_COMMON",
|
||||
"ETHER",
|
||||
"MAX_ETHER",
|
||||
"ELIXIR",
|
||||
"MAX_ELIXIR",
|
||||
"PP_UP",
|
||||
"MEMORY_MUSHROOM",
|
||||
"TM_GREAT",
|
||||
"TM_ULTRA",
|
||||
"PP_MAX",
|
||||
];
|
||||
const t = [ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.ULTRA, ModifierTier.ROGUE, ModifierTier.MASTER];
|
||||
for (let i = 0; i < t.length; i++) {
|
||||
idx = 0;
|
||||
while (idx > -1) {
|
||||
idx = modifierPool[t[i]].findIndex(p => bans.includes(p.modifierType.id));
|
||||
if (idx > -1) {
|
||||
modifierPool[t[i]].splice(idx, 1);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
override applyShopModify(options: ModifierTypeOption[]): boolean {
|
||||
const removals = ["ETHER", "MAX_ETHER", "ELIXIR", "MAX_ELIXIR", "MEMORY_MUSHROOM"]; // Pending rework, these need to match locale key
|
||||
const opstart = options.length;
|
||||
removals.map(r => {
|
||||
const idx = options.findIndex(o => o.type.localeKey.split(".")[1] === r); // Currently the quickest way to get the id
|
||||
if (idx >= 0) {
|
||||
options.splice(idx, 1);
|
||||
}
|
||||
});
|
||||
return opstart > options.length;
|
||||
}
|
||||
|
||||
static loadChallenge(source: MetronomeChallenge | any): MetronomeChallenge {
|
||||
const newChallenge = new MetronomeChallenge();
|
||||
newChallenge.value = source.value;
|
||||
newChallenge.severity = source.severity;
|
||||
return newChallenge;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowers the amount of starter points available.
|
||||
*/
|
||||
@ -1125,6 +1320,66 @@ export function applyChallenges(
|
||||
|
||||
export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean;
|
||||
|
||||
/**
|
||||
* Apply all challenges that modify Enemy Pokemon generation (after post process funcs)
|
||||
* @param challengeType {@link ChallengeType} ChallengeType.ENEMY_POKEMON_MODIFY
|
||||
* @param pokemon {@link EnemyPokemon} Pokemon to be modified
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(challengeType: ChallengeType.ENEMY_POKEMON_MODIFY, pokemon: EnemyPokemon): boolean;
|
||||
|
||||
/**
|
||||
* Apply all challenges that restrict Pokemon from learning certain moves
|
||||
* @param challengeType {@link ChallengeType} ChallengeType.BAN_MOVE_LEARNING
|
||||
* @param pokemon {@link Pokemon} The mon attempting to learn
|
||||
* @param move {@link Moves} The move being learned
|
||||
* @param learnType {@link LearnMoveType} how the move is being learned
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(
|
||||
challengeType: ChallengeType.BAN_MOVE_LEARNING,
|
||||
pokemon: Pokemon,
|
||||
move: Moves,
|
||||
learnType: LearnMoveType,
|
||||
valid: Utils.BooleanHolder,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* Apply all challenges that modify how much PP is used
|
||||
* @param challengeType {@link ChallengeType} ChallengeType.MODIFY_PP_USE
|
||||
* @param pokemon {@link Pokemon} Pokemon using the move
|
||||
* @param move {@link Moves} Move being used
|
||||
* @param usedPP {@link Utils.NumberHolder} Holds the value associated with how much PP should be used
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(
|
||||
challengeType: ChallengeType.MODIFY_PP_USE,
|
||||
pokemon: Pokemon,
|
||||
move: Moves,
|
||||
usedPP: Utils.NumberHolder,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* Apply all challenges that modify modifier pools //TODO: Modifier rework will need to look at this
|
||||
* @param challengeType {@link ChallengeType} ChallengeType.MODIFIER_POOL_MODIFY
|
||||
* @param poolType {@link ModifierPoolType} Which kind of pool is being changed (wild held items, player rewards etc)
|
||||
* @param modifierPool {@link ModifierPool} The item pool the challenge may attempt to modify
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(
|
||||
challengeType: ChallengeType.MODIFIER_POOL_MODIFY,
|
||||
poolType: ModifierPoolType,
|
||||
modifierPool: ModifierPool,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* Apply all challenges that modify the shop
|
||||
* @param challengeType ChallengeType.SHOP_MODIFY
|
||||
* @param options {@link ModifierTypeOption} List of shop options including the prices
|
||||
* @returns True if any challenge was successfully applied.
|
||||
*/
|
||||
export function applyChallenges(challengeType: ChallengeType.SHOP_MODIFY, options: ModifierTypeOption[]): boolean;
|
||||
|
||||
export function applyChallenges(challengeType: ChallengeType, ...args: any[]): boolean {
|
||||
let ret = false;
|
||||
globalScene.gameMode.challenges.forEach(c => {
|
||||
@ -1172,6 +1427,21 @@ export function applyChallenges(challengeType: ChallengeType, ...args: any[]): b
|
||||
case ChallengeType.FLIP_STAT:
|
||||
ret ||= c.applyFlipStat(args[0], args[1]);
|
||||
break;
|
||||
case ChallengeType.ENEMY_POKEMON_MODIFY:
|
||||
ret ||= c.applyEnemyPokemonModify(args[0]);
|
||||
break;
|
||||
case ChallengeType.BAN_MOVE_LEARNING:
|
||||
ret ||= c.applyBanMoveLearning(args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
case ChallengeType.MODIFY_PP_USE:
|
||||
ret ||= c.applyModifyPPUsage(args[0], args[1], args[2]);
|
||||
break;
|
||||
case ChallengeType.MODIFIER_POOL_MODIFY:
|
||||
ret ||= c.applyModifierPoolModify(args[0], args[1]);
|
||||
break;
|
||||
case ChallengeType.SHOP_MODIFY:
|
||||
ret ||= c.applyShopModify(args[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1199,6 +1469,8 @@ export function copyChallenge(source: Challenge | any): Challenge {
|
||||
return InverseBattleChallenge.loadChallenge(source);
|
||||
case Challenges.FLIP_STAT:
|
||||
return FlipStatChallenge.loadChallenge(source);
|
||||
case Challenges.METRONOME:
|
||||
return MetronomeChallenge.loadChallenge(source);
|
||||
}
|
||||
throw new Error("Unknown challenge copied");
|
||||
}
|
||||
@ -1212,6 +1484,7 @@ export function initChallenges() {
|
||||
new FreshStartChallenge(),
|
||||
new InverseBattleChallenge(),
|
||||
new FlipStatChallenge(),
|
||||
new MetronomeChallenge(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8090,7 +8090,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
||||
return false;
|
||||
}
|
||||
const userTypes = user.getTypes();
|
||||
const validTypes = this.getTypeResistances(globalScene.gameMode, moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types
|
||||
const validTypes = this.getTypeResistances(moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types
|
||||
if (!validTypes.length) {
|
||||
return false;
|
||||
}
|
||||
@ -8106,7 +8106,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
||||
* Retrieve the types resisting a given type. Used by Conversion 2
|
||||
* @returns An array populated with Types, or an empty array if no resistances exist (Unknown or Stellar type)
|
||||
*/
|
||||
getTypeResistances(gameMode: GameMode, type: number): PokemonType[] {
|
||||
getTypeResistances(type: number): PokemonType[] {
|
||||
const typeResistances: PokemonType[] = [];
|
||||
|
||||
for (let i = 0; i < Object.keys(PokemonType).length; i++) {
|
||||
|
@ -54,6 +54,7 @@ import { allMoves } from "#app/data/moves/move";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/bugTypeSuperfan";
|
||||
@ -190,6 +191,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
||||
)
|
||||
.withMaxAllowedEncounters(1)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withIntroSpriteConfigs([]) // These are set in onInit()
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withIntroDialogue([
|
||||
|
@ -80,7 +80,7 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
|
||||
MysteryEncounterType.CLOWNING_AROUND,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE, Challenges.METRONOME)
|
||||
.withSceneWaveRangeRequirement(80, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||
.withAnimations(EncounterAnim.SMOKESCREEN)
|
||||
.withAutoHideIntroVisuals(false)
|
||||
|
@ -41,6 +41,7 @@ import { PokeballType } from "#enums/pokeball";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import i18next from "i18next";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounters/dancingLessons";
|
||||
@ -99,6 +100,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withIntroSpriteConfigs([]) // Uses a real Pokemon sprite instead of ME Intro Visuals
|
||||
.withAnimations(EncounterAnim.DANCE)
|
||||
.withHideWildIntroMessage(true)
|
||||
|
@ -11,6 +11,11 @@ import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounte
|
||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { CanLearnTMRequirement } from "../mystery-encounter-requirements";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** i18n namespace for encounter */
|
||||
const namespace = "mysteryEncounters/departmentStoreSale";
|
||||
@ -55,34 +60,37 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
|
||||
.withTitle(`${namespace}:title`)
|
||||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withSimpleOption(
|
||||
{
|
||||
buttonLabel: `${namespace}:option.1.label`,
|
||||
buttonTooltip: `${namespace}:option.1.tooltip`,
|
||||
},
|
||||
async () => {
|
||||
// Choose TMs
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
while (i < 5) {
|
||||
// 2/2/1 weight on TM rarity
|
||||
const roll = randSeedInt(5);
|
||||
if (roll < 2) {
|
||||
modifiers.push(modifierTypes.TM_COMMON);
|
||||
} else if (roll < 4) {
|
||||
modifiers.push(modifierTypes.TM_GREAT);
|
||||
} else {
|
||||
modifiers.push(modifierTypes.TM_ULTRA);
|
||||
.withOption(
|
||||
MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withPrimaryPokemonRequirement(new CanLearnTMRequirement())
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option.1.label`,
|
||||
buttonTooltip: `${namespace}:option.1.tooltip`,
|
||||
})
|
||||
.withOptionPhase(async () => {
|
||||
// Choose TMs
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
while (i < 5) {
|
||||
// 2/2/1 weight on TM rarity
|
||||
const roll = randSeedInt(5);
|
||||
if (roll < 2) {
|
||||
modifiers.push(modifierTypes.TM_COMMON);
|
||||
} else if (roll < 4) {
|
||||
modifiers.push(modifierTypes.TM_GREAT);
|
||||
} else {
|
||||
modifiers.push(modifierTypes.TM_ULTRA);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
setEncounterRewards({
|
||||
guaranteedModifierTypeFuncs: modifiers,
|
||||
fillRemaining: false,
|
||||
});
|
||||
leaveEncounterWithoutBattle();
|
||||
},
|
||||
setEncounterRewards({
|
||||
guaranteedModifierTypeFuncs: modifiers,
|
||||
fillRemaining: false,
|
||||
});
|
||||
leaveEncounterWithoutBattle();
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.withSimpleOption(
|
||||
{
|
||||
@ -96,7 +104,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
|
||||
while (i < 3) {
|
||||
// 2/1 weight on base stat booster vs PP Up
|
||||
const roll = randSeedInt(3);
|
||||
if (roll === 0) {
|
||||
if (roll === 0 && !globalScene.gameMode.hasChallenge(Challenges.METRONOME)) {
|
||||
modifiers.push(modifierTypes.PP_UP);
|
||||
} else {
|
||||
modifiers.push(modifierTypes.BASE_STAT_BOOSTER);
|
||||
|
@ -46,6 +46,7 @@ import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-en
|
||||
import type { PokeballType } from "#enums/pokeball";
|
||||
import { doShinySparkleAnim } from "#app/field/anims";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/globalTradeSystem";
|
||||
@ -208,6 +209,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, receivedPokemonData);
|
||||
const modifiers = tradedPokemon
|
||||
.getHeldItems()
|
||||
.filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
||||
@ -329,6 +331,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, receivedPokemonData);
|
||||
const modifiers = tradedPokemon
|
||||
.getHeldItems()
|
||||
.filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
||||
|
@ -22,6 +22,7 @@ import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/partTimer";
|
||||
@ -36,6 +37,7 @@ export const PartTimerEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
spriteKey: "part_timer_crate",
|
||||
|
@ -30,6 +30,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { PokemonType } from "#enums/pokemon-type";
|
||||
import { getPokeballTintColor } from "#app/data/pokeball";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/theExpertPokemonBreeder";
|
||||
@ -123,6 +124,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
|
||||
MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withScenePartySizeRequirement(4, 6, true) // Must have at least 4 legal pokemon in party
|
||||
.withIntroSpriteConfigs([]) // These are set in onInit()
|
||||
|
@ -29,6 +29,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/theStrongStuff";
|
||||
@ -46,6 +47,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder
|
||||
MysteryEncounterType.THE_STRONG_STUFF,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withScenePartySizeRequirement(3, 6) // Must have at least 3 pokemon in party
|
||||
.withMaxAllowedEncounters(1)
|
||||
|
@ -34,6 +34,7 @@ import i18next from "i18next";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/theWinstrateChallenge";
|
||||
@ -47,6 +48,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = MysteryEncounter
|
||||
MysteryEncounterType.THE_WINSTRATE_CHALLENGE,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withSceneWaveRangeRequirement(100, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
|
@ -27,6 +27,7 @@ import { Moves } from "#enums/moves";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
import { randSeedInt } from "#app/utils";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
@ -46,6 +47,7 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
|
||||
MysteryEncounterType.TRASH_TO_TREASURE,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withDisallowedChallenges(Challenges.METRONOME)
|
||||
.withSceneWaveRangeRequirement(60, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||
.withMaxAllowedEncounters(1)
|
||||
.withFleeAllowed(false)
|
||||
|
@ -129,7 +129,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
||||
MysteryEncounterType.WEIRD_DREAM,
|
||||
)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE, Challenges.SINGLE_GENERATION)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE, Challenges.SINGLE_GENERATION, Challenges.METRONOME)
|
||||
// TODO: should reset minimum wave to 10 when there are more Rogue tiers in pool. Matching Dark Deal minimum for now.
|
||||
.withSceneWaveRangeRequirement(30, 140)
|
||||
.withIntroSpriteConfigs([
|
||||
|
@ -650,6 +650,39 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
|
||||
}
|
||||
}
|
||||
|
||||
export class CanLearnTMRequirement extends EncounterPokemonRequirement {
|
||||
min: number;
|
||||
excludeDisallowedPokemon: boolean;
|
||||
/**
|
||||
* Constructs a new CanLearnTMRequirement
|
||||
* @param min Minimum number of party members who can learn a TM, defaults to 1.
|
||||
* @param excludeDisallowed Whether to exclude ineligible party members, defaults to false
|
||||
*/
|
||||
constructor(min = 1, excludeDisallowed = false) {
|
||||
super();
|
||||
this.min = min;
|
||||
this.excludeDisallowedPokemon = excludeDisallowed;
|
||||
}
|
||||
|
||||
override meetsRequirement(): boolean {
|
||||
const partyPokemon = globalScene.getPlayerParty();
|
||||
if (isNullOrUndefined(partyPokemon)) {
|
||||
return false;
|
||||
}
|
||||
return this.queryParty(partyPokemon).length >= this.min;
|
||||
}
|
||||
|
||||
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
||||
return partyPokemon.filter(
|
||||
pokemon => (!this.excludeDisallowedPokemon || pokemon.isAllowedInBattle()) && pokemon.compatibleTms.length >= 0,
|
||||
);
|
||||
}
|
||||
|
||||
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
||||
return ["canLearnTM", ""];
|
||||
}
|
||||
}
|
||||
|
||||
export class AbilityRequirement extends EncounterPokemonRequirement {
|
||||
requiredAbilities: Abilities[];
|
||||
minNumberOfPokemon: number;
|
||||
|
@ -51,17 +51,23 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
|
||||
return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries party for mons meeting move requirements
|
||||
* @param partyPokemon {@link PlayerPokemon} party to query
|
||||
* @returns list of {@link PlayerPokemon} that match query
|
||||
*/
|
||||
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
||||
if (!this.invertQuery) {
|
||||
return partyPokemon.filter(pokemon =>
|
||||
// every required move should be included
|
||||
this.requiredMoves.every(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)),
|
||||
return partyPokemon.filter(
|
||||
pokemon =>
|
||||
// every required move should be included
|
||||
this.requiredMoves.length === this.getAllPokemonMoves(pokemon).length,
|
||||
);
|
||||
}
|
||||
return partyPokemon.filter(
|
||||
pokemon =>
|
||||
// none of the "required" moves should be included
|
||||
!this.requiredMoves.some(requiredMove => this.getAllPokemonMoves(pokemon).includes(requiredMove)),
|
||||
this.getAllPokemonMoves(pokemon).length === 0,
|
||||
);
|
||||
}
|
||||
|
||||
@ -73,19 +79,24 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
|
||||
return pkm.getLevelMoves().map(([_level, move]) => move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the moves with matching criteria
|
||||
* @param pkm {@link PlayerPokemon} to check
|
||||
* @returns list of {@link Moves} moves matching criteria
|
||||
*/
|
||||
private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] {
|
||||
const allPokemonMoves: Moves[] = [];
|
||||
|
||||
if (!this.excludeLevelMoves) {
|
||||
allPokemonMoves.push(...(this.getPokemonLevelMoves(pkm) ?? []));
|
||||
allPokemonMoves.push(...(this.getPokemonLevelMoves(pkm).filter(m => this.requiredMoves.includes(m)) ?? []));
|
||||
}
|
||||
|
||||
if (!this.excludeTmMoves) {
|
||||
allPokemonMoves.push(...(pkm.compatibleTms ?? []));
|
||||
allPokemonMoves.push(...pkm.generateCompatibleTms(false, false).filter(m => this.requiredMoves.includes(m)));
|
||||
}
|
||||
|
||||
if (!this.excludeEggMoves) {
|
||||
allPokemonMoves.push(...(pkm.getEggMoves() ?? []));
|
||||
allPokemonMoves.push(...(pkm.getEggMoves()?.filter(m => this.requiredMoves.includes(m)) ?? []));
|
||||
}
|
||||
|
||||
return allPokemonMoves;
|
||||
|
@ -65,6 +65,7 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { PokemonType } from "#enums/pokemon-type";
|
||||
import { getNatureName } from "#app/data/nature";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
|
||||
/**
|
||||
* Animates exclamation sprite over trainer's head at start of encounter
|
||||
@ -394,6 +395,8 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
|
||||
enemyPokemon.mysteryEncounterBattleEffects = config.mysteryEncounterBattleEffects;
|
||||
}
|
||||
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, enemyPokemon);
|
||||
|
||||
// Requires re-priming summon data to update everything properly
|
||||
enemyPokemon.primeSummonData(enemyPokemon.summonData);
|
||||
|
||||
|
@ -38,6 +38,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||
import type { Abilities } from "#enums/abilities";
|
||||
import type { PokeballType } from "#enums/pokeball";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
|
||||
/** Will give +1 level every 10 waves */
|
||||
export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1;
|
||||
@ -643,6 +644,7 @@ export async function catchPokemon(
|
||||
showCatchObtainMessage = true,
|
||||
isObtain = false,
|
||||
): Promise<void> {
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, pokemon);
|
||||
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
|
||||
|
||||
if (
|
||||
|
@ -6,4 +6,5 @@ export enum Challenges {
|
||||
FRESH_START,
|
||||
INVERSE_BATTLE,
|
||||
FLIP_STAT,
|
||||
METRONOME,
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ import { Species } from "#enums/species";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { DamageAnimPhase } from "#app/phases/damage-anim-phase";
|
||||
import { FaintPhase } from "#app/phases/faint-phase";
|
||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
||||
import { LearnMovePhase, LearnMoveType } from "#app/phases/learn-move-phase";
|
||||
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||
import { MoveEndPhase } from "#app/phases/move-end-phase";
|
||||
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
|
||||
@ -6360,13 +6360,20 @@ export class PlayerPokemon extends Pokemon {
|
||||
return this.getFieldIndex();
|
||||
}
|
||||
|
||||
generateCompatibleTms(): void {
|
||||
this.compatibleTms = [];
|
||||
/**
|
||||
* Finds the list of TMs this PlayerPokemon is compatible with based on species, form, and challenges
|
||||
* @param alsoSet Whether this PlayerPokemon's compatibleTms list should be set by this function
|
||||
* @param applyChal Whether to apply challenges which would ban the mon from learning specific moves
|
||||
* @returns {@link Moves} the list of compatible TM moves for this PlayerPokemon
|
||||
*/
|
||||
generateCompatibleTms(alsoSet: boolean = true, applyChal: boolean = true): Moves[] {
|
||||
const ret: Moves[] = [];
|
||||
const compatible = new Utils.BooleanHolder(false);
|
||||
|
||||
const tms = Object.keys(tmSpecies);
|
||||
for (const tm of tms) {
|
||||
const moveId = Number.parseInt(tm) as Moves;
|
||||
let compatible = false;
|
||||
compatible.value = false;
|
||||
for (const p of tmSpecies[tm]) {
|
||||
if (Array.isArray(p)) {
|
||||
const [pkm, form] = p;
|
||||
@ -6375,24 +6382,32 @@ export class PlayerPokemon extends Pokemon {
|
||||
(this.fusionSpecies && pkm === this.fusionSpecies.speciesId)) &&
|
||||
form === this.getFormKey()
|
||||
) {
|
||||
compatible = true;
|
||||
compatible.value = true;
|
||||
break;
|
||||
}
|
||||
} else if (
|
||||
p === this.species.speciesId ||
|
||||
(this.fusionSpecies && p === this.fusionSpecies.speciesId)
|
||||
) {
|
||||
compatible = true;
|
||||
compatible.value = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reverseCompatibleTms.indexOf(moveId) > -1) {
|
||||
compatible = !compatible;
|
||||
compatible.value = !compatible.value;
|
||||
}
|
||||
if (compatible) {
|
||||
this.compatibleTms.push(moveId);
|
||||
if (compatible.value && applyChal) {
|
||||
applyChallenges(ChallengeType.BAN_MOVE_LEARNING, this, moveId, LearnMoveType.TM, compatible);
|
||||
}
|
||||
if (compatible.value) {
|
||||
ret.push(moveId);
|
||||
}
|
||||
}
|
||||
if (alsoSet) {
|
||||
this.compatibleTms = ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
tryPopulateMoveset(moveset: StarterMoveset): boolean {
|
||||
@ -7054,14 +7069,12 @@ export class EnemyPokemon extends Pokemon {
|
||||
new PokemonMove(Moves.FLAMETHROWER),
|
||||
new PokemonMove(Moves.COSMIC_POWER),
|
||||
];
|
||||
if (globalScene.gameMode.hasChallenge(Challenges.INVERSE_BATTLE)) {
|
||||
this.moveset[2] = new PokemonMove(Moves.THUNDERBOLT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.generateAndPopulateMoveset();
|
||||
break;
|
||||
}
|
||||
applyChallenges(ChallengeType.ENEMY_POKEMON_MODIFY, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,6 +127,7 @@ import type { PermanentStat, TempBattleStat } from "#enums/stat";
|
||||
import { getStatKey, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import i18next from "i18next";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
|
||||
const outputModifierData = false;
|
||||
const useMaxWeightForOutput = false;
|
||||
@ -2032,10 +2033,12 @@ export const modifierTypes = {
|
||||
}),
|
||||
|
||||
BERRY: () =>
|
||||
new ModifierTypeGenerator((_party: Pokemon[], pregenArgs?: any[]) => {
|
||||
new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in BerryType) {
|
||||
return new BerryModifierType(pregenArgs[0] as BerryType);
|
||||
}
|
||||
const ppReduction = new NumberHolder(1); // How much PP is reduced when using a move in this game mode
|
||||
applyChallenges(ChallengeType.MODIFY_PP_USE, party[0], Moves.NONE, ppReduction);
|
||||
const berryTypes = getEnumValues(BerryType);
|
||||
let randBerryType: BerryType;
|
||||
const rand = randSeedInt(12);
|
||||
@ -2043,7 +2046,8 @@ export const modifierTypes = {
|
||||
randBerryType = BerryType.SITRUS;
|
||||
} else if (rand < 4) {
|
||||
randBerryType = BerryType.LUM;
|
||||
} else if (rand < 6) {
|
||||
} else if (rand < 6 && ppReduction.value !== 0) {
|
||||
// If PP isn't reduced, it doesn't need to be restored
|
||||
randBerryType = BerryType.LEPPA;
|
||||
} else {
|
||||
randBerryType = berryTypes[randSeedInt(berryTypes.length - 3) + 2];
|
||||
@ -2392,7 +2396,7 @@ export const modifierTypes = {
|
||||
),
|
||||
};
|
||||
|
||||
interface ModifierPool {
|
||||
export interface ModifierPool {
|
||||
[tier: string]: WeightedModifierType[];
|
||||
}
|
||||
|
||||
@ -2691,7 +2695,7 @@ const modifierPool: ModifierPool = {
|
||||
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
|
||||
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
|
||||
const { gameMode, gameData } = globalScene;
|
||||
if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) {
|
||||
if (gameMode.isDaily || gameData.isUnlocked(Unlockables.EVIOLITE)) {
|
||||
return party.some(p => {
|
||||
// Check if Pokemon's species (or fusion species, if applicable) can evolve or if they're G-Max'd
|
||||
if (
|
||||
@ -2948,11 +2952,7 @@ const modifierPool: ModifierPool = {
|
||||
),
|
||||
new WeightedModifierType(
|
||||
modifierTypes.MINI_BLACK_HOLE,
|
||||
() =>
|
||||
globalScene.gameMode.isDaily ||
|
||||
(!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))
|
||||
? 1
|
||||
: 0,
|
||||
() => (globalScene.gameMode.isDaily || globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE) ? 1 : 0),
|
||||
1,
|
||||
),
|
||||
].map(m => {
|
||||
@ -3154,6 +3154,7 @@ export function getModifierPoolForType(poolType: ModifierPoolType): ModifierPool
|
||||
pool = dailyStarterModifierPool;
|
||||
break;
|
||||
}
|
||||
applyChallenges(ChallengeType.MODIFIER_POOL_MODIFY, poolType, pool);
|
||||
return pool;
|
||||
}
|
||||
|
||||
@ -3165,9 +3166,6 @@ export const itemPoolChecks: Map<ModifierTypeKeys, boolean | undefined> = new Ma
|
||||
|
||||
export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount = 0) {
|
||||
const pool = getModifierPoolForType(poolType);
|
||||
itemPoolChecks.forEach((_v, k) => {
|
||||
itemPoolChecks.set(k, false);
|
||||
});
|
||||
|
||||
const ignoredIndexes = {};
|
||||
const modifierTableData = {};
|
||||
@ -3452,7 +3450,9 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: number, baseC
|
||||
[new ModifierTypeOption(modifierTypes.FULL_RESTORE(), 0, baseCost * 2.25)],
|
||||
[new ModifierTypeOption(modifierTypes.SACRED_ASH(), 0, baseCost * 10)],
|
||||
];
|
||||
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();
|
||||
const opts = options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();
|
||||
applyChallenges(ChallengeType.SHOP_MODIFY, opts);
|
||||
return opts;
|
||||
}
|
||||
|
||||
export function getEnemyBuffModifierForWave(
|
||||
|
@ -13,6 +13,8 @@ import i18next from "i18next";
|
||||
import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
import { BooleanHolder } from "#app/utils";
|
||||
|
||||
export enum LearnMoveType {
|
||||
/** For learning a move via level-up, evolution, or other non-item-based event */
|
||||
@ -48,6 +50,13 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
|
||||
const move = allMoves[this.moveId];
|
||||
const currentMoveset = pokemon.getMoveset();
|
||||
|
||||
const canLearn = new BooleanHolder(true);
|
||||
applyChallenges(ChallengeType.BAN_MOVE_LEARNING, pokemon, this.moveId, 0, canLearn);
|
||||
|
||||
if (!canLearn.value) {
|
||||
return this.end();
|
||||
}
|
||||
|
||||
// The game first checks if the Pokemon already has the move and ends the phase if it does.
|
||||
const hasMoveAlready = currentMoveset.some(m => m.moveId === move.id) && this.moveId !== Moves.SKETCH;
|
||||
if (hasMoveAlready) {
|
||||
|
@ -50,6 +50,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import i18next from "i18next";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge";
|
||||
|
||||
export class MovePhase extends BattlePhase {
|
||||
protected _pokemon: Pokemon;
|
||||
@ -349,9 +350,11 @@ export class MovePhase extends BattlePhase {
|
||||
|
||||
// "commit" to using the move, deducting PP.
|
||||
if (!this.ignorePp) {
|
||||
const ppUsed = 1 + this.getPpIncreaseFromPressure(targets);
|
||||
const ppUsed = new NumberHolder(1 + this.getPpIncreaseFromPressure(targets));
|
||||
|
||||
this.move.usePp(ppUsed);
|
||||
applyChallenges(ChallengeType.MODIFY_PP_USE, this.pokemon, this.move.moveId, ppUsed);
|
||||
|
||||
this.move.usePp(ppUsed.value);
|
||||
globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 1 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_TWO_VICTORY: new ChallengeAchv(
|
||||
@ -554,7 +554,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 2 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_THREE_VICTORY: new ChallengeAchv(
|
||||
@ -567,7 +567,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 3 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_FOUR_VICTORY: new ChallengeAchv(
|
||||
@ -580,7 +580,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 4 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_FIVE_VICTORY: new ChallengeAchv(
|
||||
@ -593,7 +593,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 5 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_SIX_VICTORY: new ChallengeAchv(
|
||||
@ -606,7 +606,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 6 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_SEVEN_VICTORY: new ChallengeAchv(
|
||||
@ -619,7 +619,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 7 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_EIGHT_VICTORY: new ChallengeAchv(
|
||||
@ -632,7 +632,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 8 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GEN_NINE_VICTORY: new ChallengeAchv(
|
||||
@ -645,7 +645,7 @@ export const achvs = {
|
||||
c instanceof SingleGenerationChallenge &&
|
||||
c.value === 9 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_NORMAL: new ChallengeAchv(
|
||||
@ -658,7 +658,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 1 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_FIGHTING: new ChallengeAchv(
|
||||
@ -671,7 +671,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 2 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_FLYING: new ChallengeAchv(
|
||||
@ -684,7 +684,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 3 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_POISON: new ChallengeAchv(
|
||||
@ -697,7 +697,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 4 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GROUND: new ChallengeAchv(
|
||||
@ -710,7 +710,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 5 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_ROCK: new ChallengeAchv(
|
||||
@ -723,7 +723,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 6 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_BUG: new ChallengeAchv(
|
||||
@ -736,7 +736,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 7 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GHOST: new ChallengeAchv(
|
||||
@ -749,7 +749,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 8 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_STEEL: new ChallengeAchv(
|
||||
@ -762,7 +762,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 9 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_FIRE: new ChallengeAchv(
|
||||
@ -775,7 +775,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 10 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_WATER: new ChallengeAchv(
|
||||
@ -788,7 +788,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 11 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_GRASS: new ChallengeAchv(
|
||||
@ -801,7 +801,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 12 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_ELECTRIC: new ChallengeAchv(
|
||||
@ -814,7 +814,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 13 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_PSYCHIC: new ChallengeAchv(
|
||||
@ -827,7 +827,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 14 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_ICE: new ChallengeAchv(
|
||||
@ -840,7 +840,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 15 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_DRAGON: new ChallengeAchv(
|
||||
@ -853,7 +853,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 16 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_DARK: new ChallengeAchv(
|
||||
@ -866,7 +866,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 17 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
MONO_FAIRY: new ChallengeAchv(
|
||||
@ -879,7 +879,7 @@ export const achvs = {
|
||||
c instanceof SingleTypeChallenge &&
|
||||
c.value === 18 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
FRESH_START: new ChallengeAchv(
|
||||
@ -892,7 +892,7 @@ export const achvs = {
|
||||
c instanceof FreshStartChallenge &&
|
||||
c.value > 0 &&
|
||||
!globalScene.gameMode.challenges.some(
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT].includes(c.id) && c.value > 0,
|
||||
c => [Challenges.INVERSE_BATTLE, Challenges.FLIP_STAT, Challenges.METRONOME].includes(c.id) && c.value > 0,
|
||||
),
|
||||
),
|
||||
INVERSE_BATTLE: new ChallengeAchv(
|
||||
@ -901,7 +901,10 @@ export const achvs = {
|
||||
"INVERSE_BATTLE.description",
|
||||
"inverse",
|
||||
100,
|
||||
c => c instanceof InverseBattleChallenge && c.value > 0,
|
||||
c =>
|
||||
c instanceof InverseBattleChallenge &&
|
||||
c.value > 0 &&
|
||||
!globalScene.gameMode.challenges.some(c => c.id === Challenges.METRONOME && c.value > 0),
|
||||
),
|
||||
FLIP_STATS: new ChallengeAchv(
|
||||
"FLIP_STATS",
|
||||
@ -909,7 +912,10 @@ export const achvs = {
|
||||
"FLIP_STATS.description",
|
||||
"dubious_disc",
|
||||
100,
|
||||
c => c instanceof FlipStatChallenge && c.value > 0,
|
||||
c =>
|
||||
c instanceof FlipStatChallenge &&
|
||||
c.value > 0 &&
|
||||
!globalScene.gameMode.challenges.some(c => c.id === Challenges.METRONOME && c.value > 0),
|
||||
),
|
||||
FLIP_INVERSE: new ChallengeAchv(
|
||||
"FLIP_INVERSE",
|
||||
@ -920,7 +926,8 @@ export const achvs = {
|
||||
c =>
|
||||
c instanceof FlipStatChallenge &&
|
||||
c.value > 0 &&
|
||||
globalScene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0),
|
||||
globalScene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0) &&
|
||||
!globalScene.gameMode.challenges.some(c => c.id === Challenges.METRONOME && c.value > 0),
|
||||
).setSecret(),
|
||||
BREEDERS_IN_SPACE: new Achv("BREEDERS_IN_SPACE", "", "BREEDERS_IN_SPACE.description", "moon_stone", 50).setSecret(),
|
||||
};
|
||||
|
@ -84,7 +84,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
||||
describe("Option 1 - TM Shop", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = DepartmentStoreSaleEncounter.options[0];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option.1.label`,
|
||||
|
Loading…
Reference in New Issue
Block a user