Split Nuzlocke challenge into individual challenges

This commit is contained in:
NightKev 2024-09-18 02:26:30 -07:00
parent 6030b780f2
commit eadc8f046a
7 changed files with 380 additions and 62 deletions

View File

@ -1,20 +1,21 @@
import * as Utils from "../utils";
import i18next from "i18next";
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data";
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
import Pokemon, { PokemonMove } from "#app/field/pokemon";
import { BattleType, FixedBattleConfig } from "#app/battle";
import { Nature } from "#app/data/nature";
import { pokemonEvolutions } from "#app/data/pokemon-evolutions";
import { pokemonFormChanges } from "#app/data/pokemon-forms";
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "#app/data/pokemon-species";
import { Type } from "#app/data/type";
import { TypeColor, TypeShadow } from "#app/enums/color";
import { Moves } from "#app/enums/moves";
import Pokemon, { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
import Trainer, { TrainerVariant } from "#app/field/trainer";
import { GameMode } from "#app/game-mode";
import { Type } from "./type";
import { ModifierTypeOption } from "#app/modifier/modifier-type";
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data";
import * as Utils from "#app/utils";
import { Challenges } from "#enums/challenges";
import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type";
import { Nature } from "./nature";
import { Moves } from "#app/enums/moves";
import { TypeColor, TypeShadow } from "#app/enums/color";
import { pokemonEvolutions } from "./pokemon-evolutions";
import { pokemonFormChanges } from "./pokemon-forms";
import i18next from "i18next";
/** A constant for the default max cost of the starting party before a run */
const DEFAULT_PARTY_MAX_COST = 10;
@ -83,6 +84,31 @@ export enum ChallengeType {
* Modifies what weight AI pokemon have when generating movesets. UNIMPLEMENTED.
*/
MOVE_WEIGHT,
/**
* Checks if the heal phase should be run
* @see {@linkcode Challenge.applyNoHealPhase}
*/
NO_HEAL_PHASE,
/**
* Checks if the shop item is blacklisted
* @see {@linkcode Challenge.applyShopItemBlacklist}
*/
SHOP_ITEM_BLACKLIST,
/**
* Checks if the random item is blacklisted
* @see {@linkcode Challenge.applyRandomItemBlacklist}
*/
RANDOM_ITEM_BLACKLIST,
/**
* Checks if the cought pokemon can be add to the team
* @see {@linkcode Challenge.applyAddPokemonToParty}
*/
ADD_POKEMON_TO_PARTY,
/**
* Checks if the move is blacklisted
* @see {@linkcode Challenge.applyMoveBlacklist}
*/
MOVE_BLACKLIST,
}
/**
@ -404,6 +430,56 @@ export abstract class Challenge {
applyMoveWeight(pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, level: Utils.IntegerHolder): boolean {
return false;
}
/**
* An apply function for NO_HEAL_PHASE challenges. Derived classes should alter this.
* @param applyHealPhase {@link Utils.BooleanHolder} Whether it should apply the heal phase.
* @returns {@link boolean} Whether this function did anything.
*/
applyNoHealPhase(applyHealPhase: Utils.BooleanHolder): boolean {
return false;
}
/**
* An apply function for SHOP_ITEM_BLACKLIST challenges. Derived classes should alter this.
* @param shopItem {@link ModifierTypeOption} The shop item.
* @param isValid {@link Utils.BooleanHolder} Whether this item is valid for this challenge.
* @returns {@link boolean} Whether this function did anything.
*/
applyShopItemBlacklist(shopItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean {
return false;
}
/**
* An apply function for RANDOM_ITEM_BLACKLIST challenges. Derived classes should alter this.
* @param randomItem {@link ModifierTypeOption} The random item.
* @param isValid {@link Utils.BooleanHolder} Whether this item is valid for this challenge.
* @returns {@link boolean} Whether this function did anything.
*/
applyRandomItemBlacklist(randomItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean {
return false;
}
/**
* An apply function for ADD_POKEMON_TO_PARTY challenges. Derived classes should alter this.
* @param pokemon {@link EnemyPokemon} The pokemon cought.
* @param waveIndex {@link number} Current wave index.
* @param canBeAddToParty {@link Utils.BooleanHolder} Whether this pokemon can be added to the party.
* @returns {@link boolean} Whether this function did anything.
*/
applyAddPokemonToParty(pokemon: EnemyPokemon, waveIndex: number, canBeAddToParty: Utils.BooleanHolder): boolean {
return false;
}
/**
* An apply function for MOVE_BLACKLIST challenges. Derived classes should alter this.
* @param move {@link PokemonMove} The move thats tryed to be used.
* @param moveCanBeUsed {@link Utils.BooleanHolder} Whether this move can be used.
* @returns {@link boolean} Whether this function did anything.
*/
applyMoveBlacklist(move: PokemonMove, moveCanBeUsed: Utils.BooleanHolder): boolean {
return false;
}
}
type ChallengeCondition = (data: GameData) => boolean;
@ -772,6 +848,115 @@ export class LowerStarterPointsChallenge extends Challenge {
}
}
export class NoAutomaticHealChallenge extends Challenge {
constructor() {
super(Challenges.NO_AUTO_HEAL, 1);
}
override applyNoHealPhase(applyHealPhase: Utils.BooleanHolder): boolean {
if (this.value === 1) {
return false;
}
applyHealPhase.value = false;
return true;
}
override getDifficulty(): number {
return this.value > 0 ? 1 : 0;
}
static override loadChallenge(source: NoAutomaticHealChallenge | any): NoAutomaticHealChallenge {
const newChallenge = new NoAutomaticHealChallenge();
newChallenge.value = source.value;
newChallenge.severity = source.severity;
return newChallenge;
}
}
export class HardcoreChallenge extends Challenge {
constructor() {
super(Challenges.HARDCORE, 1);
}
override applyRandomItemBlacklist(randomItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean {
const randomItemBlackList = ["modifierType:ModifierType.REVIVE", "modifierType:ModifierType.MAX_REVIVE", "modifierType:ModifierType.SACRED_ASH", "modifierType:ModifierType.REVIVER_SEED"];
isValid.value = !randomItemBlackList.includes(randomItem.type.localeKey);
return true;
}
override applyShopItemBlacklist(shopItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean {
const shopItemBlackList = ["modifierType:ModifierType.REVIVE", "modifierType:ModifierType.MAX_REVIVE", "modifierType:ModifierType.SACRED_ASH", "modifierType:ModifierType.REVIVER_SEED"];
isValid.value = !shopItemBlackList.includes(shopItem.type.localeKey);
return true;
}
override applyMoveBlacklist(move: PokemonMove, moveCanBeUsed: Utils.BooleanHolder): boolean {
const moveBlacklist = [Moves.REVIVAL_BLESSING];
moveCanBeUsed.value = !moveBlacklist.includes(move.moveId);
return true;
}
override getDifficulty(): number {
return this.value > 0 ? 1 : 0;
}
static override loadChallenge(source: HardcoreChallenge | any): HardcoreChallenge {
const newChallenge = new HardcoreChallenge();
newChallenge.value = source.value;
newChallenge.severity = source.severity;
return newChallenge;
}
}
export class NoLegendsChallenge extends Challenge {
constructor() {
super(Challenges.NO_LEGENDS, 1);
}
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft?: boolean): boolean {
if (this.value === 1) {
return false;
}
valid.value = !pokemon.legendary && !pokemon.mythical && !pokemon.subLegendary;
return true;
}
override getDifficulty(): number {
return this.value > 0 ? 1 : 0;
}
static override loadChallenge(source: NoLegendsChallenge | any): NoLegendsChallenge {
const newChallenge = new NoLegendsChallenge();
newChallenge.value = source.value;
newChallenge.severity = source.severity;
return newChallenge;
}
}
export class LimitedCatchChallenge extends Challenge {
constructor() {
super(Challenges.LIMITED_CATCH, 1);
}
override applyAddPokemonToParty(pokemon: EnemyPokemon, waveIndex: number, canBeAddToParty: Utils.BooleanHolder): boolean {
canBeAddToParty.value = waveIndex % 10 === 1;
return true;
}
override getDifficulty(): number {
return this.value > 0 ? 1 : 0;
}
static loadChallenge(source: LimitedCatchChallenge | any): LimitedCatchChallenge {
const newChallenge = new LimitedCatchChallenge();
newChallenge.value = source.value;
newChallenge.severity = source.severity;
return newChallenge;
}
}
/**
* Apply all challenges that modify starter choice.
* @param gameMode {@link GameMode} The current gameMode
@ -892,6 +1077,51 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.MOVE_WEIGHT, pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, weight: Utils.IntegerHolder): boolean;
/**
* Apply all challenges that modify if the heal phase should be applied.
* @param gameMode {@link GameMode} The current gameMode
* @param challengeType {@link ChallengeType} ChallengeType.NO_HEAL_PHASE
* @param applyHealPhase {@link Utils.BooleanHolder} Whether it should apply the heal phase. Default is true. Set to false if heal phase should not be applied.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.NO_HEAL_PHASE, applyHealPhase: Utils.BooleanHolder): boolean;
/**
* Apply all challenges that modify if this shop item can be bought.
* @param gameMode {@link GameMode} The current gameMode
* @param challengeType {@link ChallengeType} ChallengeType.SHOP_ITEM_BLACKLIST
* @param shopItem {@link ModifierTypeOption} The shop item.
* @param isValid {@link Utils.BooleanHolder} Whether this item is valid for this challenge. Default is true. Set to false if item should not be in the shop.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.SHOP_ITEM_BLACKLIST, shopItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean;
/**
* Apply all challenges that modify if this random item can be generated.
* @param gameMode {@link GameMode} The current gameMode
* @param challengeType {@link ChallengeType} ChallengeType.RANDOM_ITEM_BLACKLIST
* @param randomItem {@link ModifierTypeOption} The random item.
* @param isValid {@link Utils.BooleanHolder} Whether this item is valid for this challenge. Default is true. Set to false if item is not valid for this challenge.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.RANDOM_ITEM_BLACKLIST, randomItem: ModifierTypeOption, isValid: Utils.BooleanHolder): boolean;
/**
* Apply all challenges that modify if that pokemon can be added to the party.
* @param gameMode {@link GameMode} The current gameMode
* @param challengeType {@link ChallengeType} ChallengeType.ADD_POKEMON_TO_PARTY
* @param pokemon {@link EnemyPokemon} The pokemon cought.
* @param waveIndex {@link number} Current wave index.
* @param canBeAddToParty {@link Utils.BooleanHolder} Whether this pokemon can be added to the party. Default is true. Set to false if pokemon won't be added to the party.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.ADD_POKEMON_TO_PARTY, pokemon: EnemyPokemon, waveIndex: number, canBeAddToParty: Utils.BooleanHolder): boolean;
/**
* Apply all challenges that modify if that move can be used.
* @param gameMode {@link GameMode} The current gameMode
* @param challengeType {@link ChallengeType} ChallengeType.MOVE_BLACKLIST
* @param move {@link PokemonMove} The move thats tryed to be used.
* @param moveCanBeUsed {@link Utils.BooleanHolder} Whether this move can be used. Default is true. Set to false if move is not valid for the challenge.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.MOVE_BLACKLIST, move: PokemonMove, moveCanBeUsed: Utils.BooleanHolder): boolean;
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType, ...args: any[]): boolean {
let ret = false;
gameMode.challenges.forEach(c => {
@ -936,6 +1166,21 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
case ChallengeType.MOVE_WEIGHT:
ret ||= c.applyMoveWeight(args[0], args[1], args[2], args[3]);
break;
case ChallengeType.NO_HEAL_PHASE:
ret ||= c.applyNoHealPhase(args[0]);
break;
case ChallengeType.SHOP_ITEM_BLACKLIST:
ret ||= c.applyShopItemBlacklist(args[0], args[1]);
break;
case ChallengeType.RANDOM_ITEM_BLACKLIST:
ret ||= c.applyShopItemBlacklist(args[0], args[1]);
break;
case ChallengeType.ADD_POKEMON_TO_PARTY:
ret ||= c.applyAddPokemonToParty(args[0], args[1], args[2]);
break;
case ChallengeType.MOVE_BLACKLIST:
ret ||= c.applyMoveBlacklist(args[0], args[1]);
break;
}
}
});
@ -961,6 +1206,14 @@ export function copyChallenge(source: Challenge | any): Challenge {
return FreshStartChallenge.loadChallenge(source);
case Challenges.INVERSE_BATTLE:
return InverseBattleChallenge.loadChallenge(source);
case Challenges.NO_AUTO_HEAL:
return NoAutomaticHealChallenge.loadChallenge(source);
case Challenges.HARDCORE:
return HardcoreChallenge.loadChallenge(source);
case Challenges.NO_LEGENDS:
return NoLegendsChallenge.loadChallenge(source);
case Challenges.LIMITED_CATCH:
return LimitedCatchChallenge.loadChallenge(source);
}
throw new Error("Unknown challenge copied");
}
@ -973,5 +1226,9 @@ export function initChallenges() {
new SingleTypeChallenge(),
new FreshStartChallenge(),
new InverseBattleChallenge(),
new NoAutomaticHealChallenge(),
new HardcoreChallenge(),
new NoLegendsChallenge(),
new LimitedCatchChallenge(),
);
}

View File

@ -5,4 +5,8 @@ export enum Challenges {
LOWER_STARTER_POINTS,
FRESH_START,
INVERSE_BATTLE,
NO_AUTO_HEAL,
HARDCORE,
NO_LEGENDS,
LIMITED_CATCH,
}

View File

@ -1,32 +1,32 @@
import * as Modifiers from "./modifier";
import { MoneyMultiplierModifier } from "./modifier";
import { allMoves, AttackMove, selfStatLowerMoves } from "../data/move";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon";
import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions";
import { tmPoolTiers, tmSpecies } from "../data/tms";
import { Type } from "../data/type";
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "../ui/party-ui-handler";
import * as Utils from "../utils";
import { getBerryEffectDescription, getBerryName } from "../data/berry";
import { Unlockables } from "../system/unlockables";
import { getStatusEffectDescriptor, StatusEffect } from "../data/status-effect";
import { SpeciesFormKey } from "../data/pokemon-species";
import BattleScene from "../battle-scene";
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "../system/voucher";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "../data/pokemon-forms";
import { ModifierTier } from "./modifier-tier";
import BattleScene from "#app/battle-scene";
import { getBerryEffectDescription, getBerryName } from "#app/data/berry";
import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move";
import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature";
import i18next from "i18next";
import { getModifierTierTextTint } from "#app/ui/text";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball";
import { EvolutionItem, pokemonEvolutions } from "#app/data/pokemon-evolutions";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
import { SpeciesFormKey } from "#app/data/pokemon-species";
import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect";
import { tmPoolTiers, tmSpecies } from "#app/data/tms";
import { Type } from "#app/data/type";
import { getStatKey, PermanentStat, Stat, TEMP_BATTLE_STATS, TempBattleStat } from "#app/enums/stat";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides";
import { Unlockables } from "#app/system/unlockables";
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher";
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
import { getModifierTierTextTint } from "#app/ui/text";
import * as Utils from "#app/utils";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { getPokemonNameWithAffix } from "#app/messages";
import { PermanentStat, TEMP_BATTLE_STATS, TempBattleStat, Stat, getStatKey } from "#app/enums/stat";
import i18next from "i18next";
import * as Modifiers from "./modifier";
import { MoneyMultiplierModifier } from "./modifier";
import { ModifierTier } from "./modifier-tier";
const outputModifierData = false;
const useMaxWeightForOutput = false;
@ -2077,6 +2077,21 @@ export function getModifierTypeFuncById(id: string): ModifierTypeFunc {
export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemon[], modifierTiers?: ModifierTier[], customModifierSettings?: CustomModifierSettings): ModifierTypeOption[] {
const options: ModifierTypeOption[] = [];
const retryCount = Math.min(count * 5, 50);
/*
// based on old version
new Array(count).fill(0).map((_, i) => {
let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers?.length > i ? modifierTiers[i] : undefined);
let r = 0;
let isValidForChallenge = new Utils.BooleanHolder(true); // <--
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate, isValidForChallenge); // <--
while ((options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) || !isValidForChallenge.value) { // <--
candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount);
isValidForChallenge = new Utils.BooleanHolder(true); // <--
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate, isValidForChallenge); // <--
}
options.push(candidate);
});
*/
if (!customModifierSettings) {
new Array(count).fill(0).map((_, i) => {
options.push(getModifierTypeOptionWithRetry(options, retryCount, party, modifierTiers && modifierTiers.length > i ? modifierTiers[i] : undefined));
@ -2170,7 +2185,7 @@ export function overridePlayerModifierTypeOptions(options: ModifierTypeOption[],
}
}
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer): ModifierTypeOption[] {
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer/*, gameMode: GameMode*/): ModifierTypeOption[] {
if (!(waveIndex % 10)) {
return [];
}
@ -2204,7 +2219,11 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, base
new ModifierTypeOption(modifierTypes.SACRED_ASH(), 0, baseCost * 10)
]
];
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();/*.filter(x => {
const isValidForChallenge = new Utils.BooleanHolder(true);
applyChallenges(gameMode, ChallengeType.SHOP_ITEM_BLACKLIST, x, isValidForChallenge);
return isValidForChallenge.value;
});*/
}
export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: Modifiers.PersistentModifier[], scene: BattleScene): Modifiers.EnemyPersistentModifier {

View File

@ -1,21 +1,23 @@
import BattleScene from "#app/battle-scene";
import { BattlerIndex } from "#app/battle";
import { getPokeballCatchMultiplier, getPokeballAtlasKey, getPokeballTintColor, doPokeballBounceAnim } from "#app/data/pokeball";
import BattleScene from "#app/battle-scene";
import { SubstituteTag } from "#app/data/battler-tags";
import { ChallengeType, applyChallenges } from "#app/data/challenge";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor } from "#app/data/pokeball";
import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { PokeballType } from "#app/enums/pokeball";
import { StatusEffect } from "#app/enums/status-effect";
import { addPokeballOpenParticles, addPokeballCaptureStars } from "#app/field/anims";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
import { EnemyPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { achvs } from "#app/system/achv";
import { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler";
import { SummaryUiMode } from "#app/ui/summary-ui-handler";
import { Mode } from "#app/ui/ui";
import { BooleanHolder } from "#app/utils";
import i18next from "i18next";
import { PokemonPhase } from "./pokemon-phase";
import { VictoryPhase } from "./victory-phase";
import { SubstituteTag } from "#app/data/battler-tags";
export class AttemptCapturePhase extends PokemonPhase {
private pokeballType: PokeballType;
@ -249,6 +251,13 @@ export class AttemptCapturePhase extends PokemonPhase {
});
};
Promise.all([pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon)]).then(() => {
const challengeCanAddToParty = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.ADD_POKEMON_TO_PARTY, pokemon, this.scene.currentBattle.waveIndex, challengeCanAddToParty);
if (!challengeCanAddToParty.value) {
removePokemon();
end();
return;
}
if (this.scene.getParty().length === 6) {
const promptRelease = () => {
this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {

View File

@ -1,7 +1,8 @@
import { BattleType, TurnCommand } from "#app/battle";
import BattleScene from "#app/battle-scene";
import { TurnCommand, BattleType } from "#app/battle";
import { TrappedTag, EncoreTag } from "#app/data/battler-tags";
import { MoveTargetSet, getMoveTargets } from "#app/data/move";
import { EncoreTag, TrappedTag } from "#app/data/battler-tags";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { getMoveTargets, MoveTargetSet } from "#app/data/move";
import { speciesStarters } from "#app/data/pokemon-species";
import { Abilities } from "#app/enums/abilities";
import { BattlerTagType } from "#app/enums/battler-tag-type";
@ -12,10 +13,11 @@ import { FieldPosition, PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import { BooleanHolder } from "#app/utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import i18next from "i18next";
import { FieldPhase } from "./field-phase";
import { SelectTargetPhase } from "./select-target-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
export class CommandPhase extends FieldPhase {
protected fieldIndex: integer;
@ -84,6 +86,18 @@ export class CommandPhase extends FieldPhase {
switch (command) {
case Command.FIGHT:
// Check if move can be used in challenge
const isValidForChallenge = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.MOVE_BLACKLIST, playerPokemon.getMoveset()[cursor]!, isValidForChallenge);
if (!isValidForChallenge.value) {
const moveName = playerPokemon.getMoveset()[cursor]?.getName();
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(i18next.t("challenges:illegalMove", { moveName: moveName }), null, () => {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
}, null, true);
break;
}
let useStruggle = false;
if (cursor === -1 ||
playerPokemon.trySelectMove(cursor, args[0] as boolean) ||

View File

@ -1,4 +1,5 @@
import BattleScene from "#app/battle-scene";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import * as Utils from "#app/utils";
import { BattlePhase } from "./battle-phase";
@ -14,6 +15,13 @@ export class PartyHealPhase extends BattlePhase {
start() {
super.start();
const isHealPhaseActive = new Utils.BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.NO_HEAL_PHASE, isHealPhaseActive);
if (!isHealPhaseActive.value) {
this.end();
return;
}
const bgmPlaying = this.scene.isBgmPlaying();
if (bgmPlaying) {
this.scene.fadeOutBgm(1000, false);

View File

@ -1,20 +1,20 @@
import BattleScene from "../battle-scene";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "../modifier/modifier-type";
import { getPokeballAtlasKey, PokeballType } from "../data/pokeball";
import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text";
import AwaitableUiHandler from "./awaitable-ui-handler";
import { Mode } from "./ui";
import { LockModifierTiersModifier, PokemonHeldItemModifier, HealShopCostModifier } from "../modifier/modifier";
import { handleTutorial, Tutorial } from "../tutorial";
import { Button } from "#enums/buttons";
import MoveInfoOverlay from "./move-info-overlay";
import { allMoves } from "../data/move";
import * as Utils from "./../utils";
import BattleScene from "#app/battle-scene";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { allMoves } from "#app/data/move";
import { getPokeballAtlasKey, PokeballType } from "#app/data/pokeball";
import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { handleTutorial, Tutorial } from "#app/tutorial";
import { BooleanHolder, formatMoney, NumberHolder } from "#app/utils";
import { Button } from "#enums/buttons";
import { ShopCursorTarget } from "#enums/shop-cursor-target";
import i18next from "i18next";
import { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import { IntegerHolder } from "./../utils";
import Phaser from "phaser";
import AwaitableUiHandler from "./awaitable-ui-handler";
import MoveInfoOverlay from "./move-info-overlay";
import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions, TextStyle } from "./text";
import { Mode } from "./ui";
export const SHOP_OPTIONS_ROW_LIMIT = 6;
@ -186,11 +186,18 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
const typeOptions = args[1] as ModifierTypeOption[];
const removeHealShop = this.scene.gameMode.hasNoShop;
const baseShopCost = new IntegerHolder(this.scene.getWaveMoneyAmount(1));
const baseShopCost = new NumberHolder(this.scene.getWaveMoneyAmount(1));
this.scene.applyModifier(HealShopCostModifier, true, baseShopCost);
const shopTypeOptions = !removeHealShop
? getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, baseShopCost.value)
? getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, baseShopCost.value).filter(shopItem => {
const isValidForChallenge = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.SHOP_ITEM_BLACKLIST, shopItem, isValidForChallenge);
return isValidForChallenge.value;
})
: [];
const optionsYOffset = shopTypeOptions.length >= SHOP_OPTIONS_ROW_LIMIT ? -8 : -24;
for (let m = 0; m < typeOptions.length; m++) {
@ -554,7 +561,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
}
const canReroll = this.scene.money >= this.rerollCost;
const formattedMoney = Utils.formatMoney(this.scene.moneyFormat, this.rerollCost);
const formattedMoney = formatMoney(this.scene.moneyFormat, this.rerollCost);
this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney }));
this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED));
@ -819,7 +826,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
const cost = Overrides.WAIVE_ROLL_FEE_OVERRIDE ? 0 : this.modifierTypeOption.cost;
const textStyle = cost <= scene.money ? TextStyle.MONEY : TextStyle.PARTY_RED;
const formattedMoney = Utils.formatMoney(scene.moneyFormat, cost);
const formattedMoney = formatMoney(scene.moneyFormat, cost);
this.itemCostText.setText(i18next.t("modifierSelectUiHandler:itemCost", { formattedMoney }));
this.itemCostText.setColor(getTextColor(textStyle, false, scene.uiTheme));