Create Nuzlocke-related challenges

- "No Free Heal": Disables the automatic healing
that occurs after every 10th wave,
replacing it with a normal shop phase

- "Hardcore": Fainted Pokémon can't be revived

- "Limited Catch": Only the first wild Pokémon encounter
of every biome can be added to your current party
This commit is contained in:
NightKev 2024-09-18 02:26:30 -07:00
parent 414e0a5447
commit df73978bb4
16 changed files with 924 additions and 411 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -2,6 +2,7 @@ import BattleScene from "#app/battle-scene";
import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { tmPoolTiers, tmSpecies } from "#app/data/balance/tms";
import { getBerryEffectDescription, getBerryName } from "#app/data/berry";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move";
import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball";
@ -9,6 +10,7 @@ import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, Species
import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect";
import { Type } from "#app/data/type";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { GameMode } from "#app/game-mode";
import { getPokemonNameWithAffix } from "#app/messages";
import {
AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier
@ -19,7 +21,7 @@ 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 { formatMoney, getEnumKeys, getEnumValues, IntegerHolder, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils";
import { BooleanHolder, formatMoney, getEnumKeys, getEnumValues, IntegerHolder, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
@ -1284,7 +1286,7 @@ function skipInClassicAfterWave(wave: integer, defaultWeight: integer): Weighted
* @param defaultWeight ModifierType default weight
* @returns A WeightedModifierTypeWeightFunc
*/
function skipInLastClassicWaveOrDefault(defaultWeight: integer) : WeightedModifierTypeWeightFunc {
function skipInLastClassicWaveOrDefault(defaultWeight: number): WeightedModifierTypeWeightFunc {
return skipInClassicAfterWave(199, defaultWeight);
}
@ -1302,7 +1304,7 @@ function lureWeightFunc(maxBattles: number, weight: number): WeightedModifierTyp
};
}
class WeightedModifierType {
export class WeightedModifierType {
public modifierType: ModifierType;
public weight: integer | WeightedModifierTypeWeightFunc;
public maxWeight: integer;
@ -1598,7 +1600,7 @@ export const modifierTypes = {
MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new BoostBugSpawnModifier(type)),
};
interface ModifierPool {
export interface ModifierPool {
[tier: string]: WeightedModifierType[]
}
@ -1910,10 +1912,10 @@ const enemyBuffModifierPool: ModifierPool = {
].map(m => {
m.setTier(ModifierTier.ULTRA); return m;
}),
[ModifierTier.ROGUE]: [ ].map((m: WeightedModifierType) => {
[ModifierTier.ROGUE]: [].map((m: WeightedModifierType) => {
m.setTier(ModifierTier.ROGUE); return m;
}),
[ModifierTier.MASTER]: [ ].map((m: WeightedModifierType) => {
[ModifierTier.MASTER]: [].map((m: WeightedModifierType) => {
m.setTier(ModifierTier.MASTER); return m;
})
};
@ -2018,7 +2020,7 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
let tierMaxWeight = 0;
let i = 0;
pool[t].reduce((total: integer, modifierType: WeightedModifierType) => {
const weightedModifierType = modifierType as WeightedModifierType;
const weightedModifierType = modifierType;
const existingModifiers = party[0].scene.findModifiers(m => m.type.id === weightedModifierType.modifierType.id, poolType === ModifierPoolType.PLAYER);
const itemModifierType = weightedModifierType.modifierType instanceof ModifierTypeGenerator
? weightedModifierType.modifierType.generateType(party)
@ -2028,8 +2030,8 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
|| itemModifierType instanceof FormChangeItemModifierType
|| existingModifiers.find(m => m.stackCount < m.getMaxStackCount(party[0].scene, true))
? weightedModifierType.weight instanceof Function
? (weightedModifierType.weight as Function)(party, rerollCount)
: weightedModifierType.weight as integer
? weightedModifierType.weight(party, rerollCount)
: weightedModifierType.weight
: 0;
if (weightedModifierType.maxWeight) {
const modifierId = weightedModifierType.modifierType.id;
@ -2174,12 +2176,23 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo
* @param tier If specified will generate item of tier
* @param allowLuckUpgrades `true` to allow items to upgrade tiers (the little animation that plays and is affected by luck)
*/
function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], retryCount: integer, party: PlayerPokemon[], tier?: ModifierTier, allowLuckUpgrades?: boolean): ModifierTypeOption {
function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], retryCount: number, party: PlayerPokemon[], tier?: ModifierTier, allowLuckUpgrades?: boolean): ModifierTypeOption {
allowLuckUpgrades = allowLuckUpgrades ?? true;
let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier, undefined, 0, allowLuckUpgrades);
let r = 0;
while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group).length) {
let isValidForChallenge = new BooleanHolder(true);
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate, isValidForChallenge);
while (
(
existingOptions.length
&& ++r < retryCount
&& existingOptions.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 ?? tier, candidate?.upgradeCount, 0, allowLuckUpgrades);
isValidForChallenge = new BooleanHolder(true);
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate, isValidForChallenge);
}
return candidate!;
}
@ -2209,7 +2222,7 @@ export function overridePlayerModifierTypeOptions(options: ModifierTypeOption[],
}
}
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer): ModifierTypeOption[] {
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: number, baseCost: number, gameMode: GameMode): ModifierTypeOption[] {
if (!(waveIndex % 10)) {
return [];
}
@ -2244,7 +2257,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(item => {
const isValidForChallenge = new BooleanHolder(true);
applyChallenges(gameMode, ChallengeType.SHOP_ITEM_BLACKLIST, item, isValidForChallenge);
return isValidForChallenge.value;
});
}
export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: PersistentModifier[], scene: BattleScene): EnemyPersistentModifier {
@ -2319,8 +2336,8 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): PokemonHeld
* @param retryCount Max allowed tries before the next tier down is checked for a valid ModifierType
* @param allowLuckUpgrades Default true. If false, will not allow ModifierType to randomly upgrade to next tier
*/
function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0, allowLuckUpgrades: boolean = true): ModifierTypeOption | null {
const player = !poolType;
function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: number, retryCount: number = 0, allowLuckUpgrades: boolean = true): ModifierTypeOption | null {
const player = poolType === ModifierPoolType.PLAYER;
const pool = getModifierPoolForType(poolType);
let thresholds: object;
switch (poolType) {
@ -2370,7 +2387,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
}
tier += upgradeCount;
while (tier && (!modifierPool.hasOwnProperty(tier) || !modifierPool[tier].length)) {
while (tier && (!pool.hasOwnProperty(tier) || !pool[tier].length)) {
tier--;
if (upgradeCount) {
upgradeCount--;
@ -2381,7 +2398,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
if (tier < ModifierTier.MASTER && allowLuckUpgrades) {
const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length;
const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2));
while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) {
while (pool.hasOwnProperty(tier + upgradeCount + 1) && pool[tier + upgradeCount + 1].length) {
if (!randSeedInt(upgradeOdds)) {
upgradeCount++;
} else {

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 { PokemonPhase } from "#app/phases/pokemon-phase";
import { VictoryPhase } from "#app/phases/victory-phase";
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,22 +1,23 @@
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 { speciesStarterCosts } from "#app/data/balance/starters";
import { Abilities } from "#app/enums/abilities";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Biome } from "#app/enums/biome";
import { Moves } from "#app/enums/moves";
import { EncoreTag, TrappedTag } from "#app/data/battler-tags";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { getMoveTargets, MoveTargetSet } from "#app/data/move";
import { PokeballType } from "#app/enums/pokeball";
import { FieldPosition, PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { FieldPhase } from "#app/phases/field-phase";
import { SelectTargetPhase } from "#app/phases/select-target-phase";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import { FieldPhase } from "./field-phase";
import { SelectTargetPhase } from "./select-target-phase";
import { BooleanHolder, isNullOrUndefined } from "#app/utils";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { isNullOrUndefined } from "#app/utils";
import i18next from "i18next";
export class CommandPhase extends FieldPhase {
protected fieldIndex: integer;
@ -94,6 +95,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,6 +1,7 @@
import BattleScene from "#app/battle-scene";
import * as Utils from "#app/utils";
import { BattlePhase } from "./battle-phase";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { BattlePhase } from "#app/phases/battle-phase";
import { BooleanHolder, fixedInt } from "#app/utils";
export class PartyHealPhase extends BattlePhase {
private resumeBgm: boolean;
@ -14,21 +15,34 @@ export class PartyHealPhase extends BattlePhase {
start() {
super.start();
const isHealPhaseActive = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.NO_HEAL_PHASE, isHealPhaseActive);
if (!isHealPhaseActive.value) {
return this.end();
}
const bgmPlaying = this.scene.isBgmPlaying();
if (bgmPlaying) {
this.scene.fadeOutBgm(1000, false);
}
const canBeRevived = new BooleanHolder(true);
this.scene.ui.fadeOut(1000).then(() => {
for (const pokemon of this.scene.getParty()) {
applyChallenges(this.scene.gameMode, ChallengeType.PREVENT_REVIVE, pokemon, canBeRevived);
if (canBeRevived.value || !pokemon.isFainted()) {
pokemon.hp = pokemon.getMaxHp();
pokemon.resetStatus();
for (const move of pokemon.moveset) {
move!.ppUsed = 0; // TODO: is this bang correct?
if (move) {
move.ppUsed = 0;
}
}
pokemon.updateInfo(true);
}
}
const healSong = this.scene.playSoundWithoutBgm("heal");
this.scene.time.delayedCall(Utils.fixedInt(healSong.totalDuration * 1000), () => {
this.scene.time.delayedCall(fixedInt(healSong.totalDuration * 1000), () => {
healSong.destroy();
if (this.resumeBgm && bgmPlaying) {
this.scene.playBgm();

View File

@ -1,16 +1,35 @@
import BattleScene from "#app/battle-scene";
import {
ExtraModifierModifier,
HealShopCostModifier,
Modifier,
PokemonHeldItemModifier,
TempExtraModifierModifier
} from "#app/modifier/modifier";
import { ModifierTier } from "#app/modifier/modifier-tier";
import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions } from "#app/modifier/modifier-type";
import { ExtraModifierModifier, HealShopCostModifier, Modifier, PokemonHeldItemModifier, TempExtraModifierModifier } from "#app/modifier/modifier";
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import * as Utils from "#app/utils";
import { BattlePhase } from "./battle-phase";
import {
CustomModifierSettings,
FusePokemonModifierType,
getPlayerModifierTypeOptions,
getPlayerShopModifierTypeOptionsForWave,
ModifierPoolType,
ModifierType,
ModifierTypeOption,
PokemonModifierType,
PokemonMoveModifierType,
PokemonPpRestoreModifierType,
PokemonPpUpModifierType,
regenerateModifierPoolThresholds,
RememberMoveModifierType,
TmModifierType
} from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { CustomModifierSettings } from "#app/modifier/modifier-type";
import { BattlePhase } from "#app/phases/battle-phase";
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import { isNullOrUndefined, NumberHolder } from "#app/utils";
import i18next from "i18next";
export class SelectModifierPhase extends BattlePhase {
private rerollCount: integer;
@ -42,7 +61,7 @@ export class SelectModifierPhase extends BattlePhase {
if (!this.isCopy) {
regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount);
}
const modifierCount = new Utils.IntegerHolder(3);
const modifierCount = new NumberHolder(3);
if (this.isPlayer()) {
this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount);
this.scene.applyModifiers(TempExtraModifierModifier, true, modifierCount);
@ -140,7 +159,7 @@ export class SelectModifierPhase extends BattlePhase {
}
break;
default:
const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1));
const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1), this.scene.gameMode);
const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT];
if (shopOption.type) {
modifierType = shopOption.type;

View File

@ -1,16 +1,18 @@
import BattleScene from "#app/battle-scene";
import { BattlerIndex, BattleType, ClassicFixedBossWaves } from "#app/battle";
import { CustomModifierSettings, modifierTypes } from "#app/modifier/modifier-type";
import { BattleEndPhase } from "./battle-end-phase";
import { NewBattlePhase } from "./new-battle-phase";
import { PokemonPhase } from "./pokemon-phase";
import { AddEnemyBuffModifierPhase } from "./add-enemy-buff-modifier-phase";
import { EggLapsePhase } from "./egg-lapse-phase";
import { GameOverPhase } from "./game-over-phase";
import { ModifierRewardPhase } from "./modifier-reward-phase";
import { SelectModifierPhase } from "./select-modifier-phase";
import { TrainerVictoryPhase } from "./trainer-victory-phase";
import BattleScene from "#app/battle-scene";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { handleMysteryEncounterVictory } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { CustomModifierSettings, modifierTypes } from "#app/modifier/modifier-type";
import { AddEnemyBuffModifierPhase } from "#app/phases/add-enemy-buff-modifier-phase";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { NewBattlePhase } from "#app/phases/new-battle-phase";
import { PokemonPhase } from "#app/phases/pokemon-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
import { BooleanHolder } from "#app/utils";
export class VictoryPhase extends PokemonPhase {
/** If true, indicates that the phase is intended for EXP purposes only, and not to continue a battle to next phase */
@ -40,6 +42,9 @@ export class VictoryPhase extends PokemonPhase {
return this.end();
}
const isHealPhaseActive = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.NO_HEAL_PHASE, isHealPhaseActive);
if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType === BattleType.WILD ? p.isOnField() : !p?.isFainted(true))) {
this.scene.pushPhase(new BattleEndPhase(this.scene));
if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
@ -51,7 +56,7 @@ export class VictoryPhase extends PokemonPhase {
// Should get Lock Capsule on 165 before shop phase so it can be used in the rewards shop
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.LOCK_CAPSULE));
}
if (this.scene.currentBattle.waveIndex % 10) {
if (this.scene.currentBattle.waveIndex % 10 || (this.scene.currentBattle.waveIndex === 0 && !isHealPhaseActive.value)) {
this.scene.pushPhase(new SelectModifierPhase(this.scene, undefined, undefined, this.getFixedBattleCustomModifiers()));
} else if (this.scene.gameMode.isDaily) {
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_CHARM));

View File

@ -0,0 +1,62 @@
import { Abilities } from "#enums/abilities";
import { Challenges } from "#enums/challenges";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Challenge - Hardcore", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.challengeMode.addChallenge(Challenges.HARDCORE);
game.override
.battleType("single")
.ability(Abilities.BALL_FETCH)
.moveset(Moves.THUNDERBOLT)
.startingLevel(2000)
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH);
});
it.todo("prevents revival items from showing up in the shop", async () => {
game.override.startingWave(191);
await game.challengeMode.startBattle();
game.move.select(Moves.THUNDERBOLT);
await game.phaseInterceptor.to("SelectModifierPhase");
expect(1);
});
it.todo("prevents revival items from showing up in rewards", async () => {
game.modifiers
.addCheck("REVIVE")
.addCheck("MAX_REVIVE")
.addCheck("REVIVER_SEED");
await game.challengeMode.startBattle();
game.move.select(Moves.THUNDERBOLT);
await game.phaseInterceptor.to("SelectModifierPhase");
game.modifiers
.testCheck("REVIVE", false)
.testCheck("MAX_REVIVE", false)
.testCheck("REVIVER_SEED", false);
});
});

View File

@ -0,0 +1,43 @@
import { CommandPhase } from "#app/phases/command-phase";
import { Command } from "#app/ui/command-ui-handler";
import { Challenges } from "#enums/challenges";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Challenge - Limited Catch", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.challengeMode.addChallenge(Challenges.LIMITED_CATCH);
game.override.battleType("single");
});
it("prevents catching pokemon outside of the first wave of the biome", async () => {
game.override
.startingWave(3)
.pokeballs([ 0, 0, 0, 0, 100 ]);
await game.challengeMode.startBattle([ Species.FEEBAS ]);
const phase = game.scene.getCurrentPhase() as CommandPhase;
phase.handleCommand(Command.BALL, 4);
await game.phaseInterceptor.to("BattleEndPhase");
expect(game.scene.getParty().length).toBe(1);
});
});

View File

@ -0,0 +1,55 @@
import { Abilities } from "#enums/abilities";
import { Challenges } from "#enums/challenges";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Challenge - No Auto Heal", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.challengeMode.addChallenge(Challenges.NO_AUTO_HEAL);
game.override
.battleType("single")
.starterSpecies(Species.FEEBAS)
.ability(Abilities.BALL_FETCH)
.moveset(Moves.THUNDERBOLT)
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH);
});
it("prevents PartyHealPhase from healing the player's pokemon", async () => {
game.override
.startingWave(10)
.startingLevel(100);
await game.challengeMode.startBattle();
const player = game.scene.getPlayerField()[0];
player.damageAndUpdate(1);
game.move.select(Moves.THUNDERBOLT);
await game.phaseInterceptor.to("SelectModifierPhase", false);
game.doSelectModifier();
await game.toNextTurn();
expect(player.hp).toBe(player.getMaxHp() - 1);
expect(player.moveset[0]?.ppUsed).toBe(1);
});
});

View File

@ -1,13 +1,11 @@
import { MapModifier } from "#app/modifier/modifier";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "./utils/gameManager";
import { Moves } from "#app/enums/moves";
import { Biome } from "#app/enums/biome";
import { Mode } from "#app/ui/ui";
import { Moves } from "#app/enums/moves";
import { MapModifier } from "#app/modifier/modifier";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import { Mode } from "#app/ui/ui";
import { Species } from "#enums/species";
//const TIMEOUT = 20 * 1000;
import GameManager from "#test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Daily Mode", () => {
let phaserGame: Phaser.Game;

View File

@ -1,16 +1,15 @@
import { BattleStyle } from "#app/enums/battle-style";
import { Species } from "#app/enums/species";
import { Challenge, copyChallenge } from "#app/data/challenge";
import overrides from "#app/overrides";
import { CommandPhase } from "#app/phases/command-phase";
import { EncounterPhase } from "#app/phases/encounter-phase";
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
import { Mode } from "#app/ui/ui";
import { generateStarter } from "../gameManagerUtils";
import { GameManagerHelper } from "./gameManagerHelper";
import { Challenge } from "#app/data/challenge";
import { CommandPhase } from "#app/phases/command-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { Mode } from "#app/ui/ui";
import { BattleStyle } from "#enums/battle-style";
import { Challenges } from "#enums/challenges";
import { copyChallenge } from "data/challenge";
import { Species } from "#enums/species";
import { generateStarter } from "#test/utils/gameManagerUtils";
import { GameManagerHelper } from "#test/utils/helpers/gameManagerHelper";
/**
* Helper to handle Challenge mode specifics
@ -25,7 +24,7 @@ export class ChallengeModeHelper extends GameManagerHelper {
* @param value - The challenge value.
* @param severity - The challenge severity.
*/
addChallenge(id: Challenges, value: number, severity: number) {
addChallenge(id: Challenges, value: number = 1, severity: number = 1) {
const challenge = copyChallenge({ id, value, severity });
this.challenges.push(challenge);
}

View File

@ -1,19 +1,20 @@
import { StatusEffect } from "#app/data/status-effect";
import { Variant } from "#app/data/variant";
import { Weather, WeatherType } from "#app/data/weather";
import { Abilities } from "#app/enums/abilities";
import { Biome } from "#app/enums/biome";
import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import * as GameMode from "#app/game-mode";
import { GameModes, getGameMode } from "#app/game-mode";
import { ModifierOverride } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { vi } from "vitest";
import { GameManagerHelper } from "./gameManagerHelper";
import { Unlockables } from "#app/system/unlockables";
import { Variant } from "#app/data/variant";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Abilities } from "#enums/abilities";
import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PokeballType } from "#enums/pokeball";
import { Species } from "#enums/species";
import { GameManagerHelper } from "#test/utils/helpers/gameManagerHelper";
import { vi } from "vitest";
/**
* Helper to handle overrides in tests
@ -27,14 +28,14 @@ export class OverridesHelper extends GameManagerHelper {
/**
* Override the starting biome
* @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line
* @param biome the biome to set
* @param biome The {@linkcode Biome} to set
* @returns `this`
*/
public startingBiome(biome: Biome): this {
this.game.scene.newArena(biome);
this.log(`Starting biome set to ${Biome[biome]} (=${biome})!`);
return this;
}
/**
* Override the starting wave (index)
* @param wave the wave (index) to set. Classic: `1`-`200`
@ -47,8 +48,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) starting level
* @param level the (pokemon) level to set
* Override the player pokemon's starting level
* @param level the level to set
* @returns `this`
*/
public startingLevel(level: Species | number): this {
@ -69,8 +70,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) starting held items
* @param items the items to hold
* Override the player pokemon's starting held items
* @param items the {@linkcode ModifierOverride | items} to hold
* @returns `this`
*/
public startingHeldItems(items: ModifierOverride[]): this {
@ -80,8 +81,35 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) {@linkcode Species | species}
* @param species the (pokemon) {@linkcode Species | species} to set
* Override the player's pokeball inventory
* @param pokeballs Array specifying the amount of each pokeball to set, or `null` if disabling the override
* @param enable Whether to enable or disable the override, default `true`
* @returns `this`
*/
pokeballs(pokeballs: [number, number, number, number, number] | null, enable: boolean = true): this {
if (!pokeballs) {
pokeballs = [ 5, 0, 0, 0, 0 ];
}
pokeballs = pokeballs!;
const pokeballOverride = {
active: enable,
pokeballs: {
[PokeballType.POKEBALL]: pokeballs[0],
[PokeballType.GREAT_BALL]: pokeballs[1],
[PokeballType.ULTRA_BALL]: pokeballs[2],
[PokeballType.ROGUE_BALL]: pokeballs[3],
[PokeballType.MASTER_BALL]: pokeballs[4],
},
};
vi.spyOn(Overrides, "POKEBALL_OVERRIDE", "get").mockReturnValue(pokeballOverride);
this.log(`Pokeball override ${enable ? `set to [${pokeballs}]!` : "disabled!"}`);
return this;
}
/**
* Override the player pokemon's species.
* It's preferred to use `startBattle([Species.PKMN1, Species.PKMN2, ...])` if possible.
* @param species the {@linkcode Species} to set
* @returns `this`
*/
public starterSpecies(species: Species | number): this {
@ -112,8 +140,15 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemons) forms
* @param forms the (pokemon) forms to set
* Override the player pokemons' forms
* @param forms the forms to set
* @example
* ```ts
* game.override.starterForms({
* [Species.KYOGRE]: 1,
* [Species.PIKACHU]: 3,
* });
* ```
* @returns `this`
*/
public starterForms(forms: Partial<Record<Species, number>>): this {
@ -127,7 +162,7 @@ export class OverridesHelper extends GameManagerHelper {
/**
* Override the player's starting modifiers
* @param modifiers the modifiers to set
* @param modifiers the {@linkcode ModifierOverride | modifiers} to set
* @returns `this`
*/
public startingModifier(modifiers: ModifierOverride[]): this {
@ -137,8 +172,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) {@linkcode Abilities | ability}
* @param ability the (pokemon) {@linkcode Abilities | ability} to set
* Override the player pokemon's ability
* @param ability the {@linkcode Abilities | ability} to set
* @returns `this`
*/
public ability(ability: Abilities): this {
@ -148,8 +183,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) **passive** {@linkcode Abilities | ability}
* @param passiveAbility the (pokemon) **passive** {@linkcode Abilities | ability} to set
* Override the player pokemon's **passive** ability
* @param passiveAbility the **passive** {@linkcode Abilities | ability} to set
* @returns `this`
*/
public passiveAbility(passiveAbility: Abilities): this {
@ -159,8 +194,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) {@linkcode Moves | moves}set
* @param moveset the {@linkcode Moves | moves}set to set
* Override the player pokemon's moveset
* @param moveset the {@linkcode Moves | moveset} to set
* @returns `this`
*/
public moveset(moveset: Moves | Moves[]): this {
@ -174,9 +209,9 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the player (pokemon) {@linkcode StatusEffect | status-effect}
* @param statusEffect the {@linkcode StatusEffect | status-effect} to set
* @returns
* Override the player pokemon's status effect
* @param statusEffect the {@linkcode StatusEffect | status effect} to set
* @returns `this`
*/
public statusEffect(statusEffect: StatusEffect): this {
vi.spyOn(Overrides, "STATUS_OVERRIDE", "get").mockReturnValue(statusEffect);
@ -210,8 +245,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the {@linkcode WeatherType | weather (type)}
* @param type {@linkcode WeatherType | weather type} to set
* Override the weather
* @param type The {@linkcode WeatherType} to set
* @returns `this`
*/
public weather(type: WeatherType): this {
@ -237,8 +272,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the battle type (single or double)
* @param battleType battle type to set
* Override the battle type
* @param battleType - The battle type to set ("single" or "double"), `null` to disable
* @returns `this`
*/
public battleType(battleType: "single" | "double" | null): this {
@ -248,8 +283,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) {@linkcode Species | species}
* @param species the (pokemon) {@linkcode Species | species} to set
* Override the enemy pokemon's species
* @param species the {@linkcode Species} to set
* @returns `this`
*/
public enemySpecies(species: Species | number): this {
@ -280,7 +315,7 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) {@linkcode Abilities | ability}
* Override the enemy pokemon's ability
* @param ability the (pokemon) {@linkcode Abilities | ability} to set
* @returns `this`
*/
@ -291,8 +326,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) **passive** {@linkcode Abilities | ability}
* @param passiveAbility the (pokemon) **passive** {@linkcode Abilities | ability} to set
* Override the enemy pokemon's **passive** ability
* @param passiveAbility the **passive** {@linkcode Abilities | ability} to set
* @returns `this`
*/
public enemyPassiveAbility(passiveAbility: Abilities): this {
@ -302,8 +337,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) {@linkcode Moves | moves}set
* @param moveset the {@linkcode Moves | moves}set to set
* Override the enemy pokemon's moveset
* @param moveset the {@linkcode Moves | moveset} to set
* @returns `this`
*/
public enemyMoveset(moveset: Moves | Moves[]): this {
@ -317,7 +352,7 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) level
* Override the enemy pokemon's level
* @param level the level to set
* @returns `this`
*/
@ -328,8 +363,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) {@linkcode StatusEffect | status-effect}
* @param statusEffect the {@linkcode StatusEffect | status-effect} to set
* Override the enemy pokemon's status effect
* @param statusEffect the {@linkcode StatusEffect} to set
* @returns
*/
public enemyStatusEffect(statusEffect: StatusEffect): this {
@ -339,8 +374,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (pokemon) held items
* @param items the items to hold
* Override the enemy pokemon's held items
* @param items the {@linkcode ModifierOverride | items} to hold
* @returns `this`
*/
public enemyHeldItems(items: ModifierOverride[]): this {
@ -362,7 +397,7 @@ export class OverridesHelper extends GameManagerHelper {
/**
* Override the items rolled at the end of a battle
* @param items the items to be rolled
* @param items the {@linkcode ModifierOverride | items} to be rolled
* @returns `this`
*/
public itemRewards(items: ModifierOverride[]): this {
@ -420,7 +455,7 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the enemy (Pokemon) to have the given amount of health segments
* Override the enemy Pokemon to have the given amount of health segments
* @param healthSegments the number of segments to give
* - `0` (default): the health segments will be handled like in the game based on wave, level and species
* - `1`: the Pokemon will not be a boss
@ -462,8 +497,8 @@ export class OverridesHelper extends GameManagerHelper {
}
/**
* Override the encounter chance for a mystery encounter.
* @param tier - The {@linkcode MysteryEncounterTier} to encounter
* Override the encounter tier for a mystery encounter.
* @param tier What {@linkcode MysteryEncounterTier | tier} of encounter to set
* @returns `this`
*/
public mysteryEncounterTier(tier: MysteryEncounterTier): this {
@ -474,7 +509,7 @@ export class OverridesHelper extends GameManagerHelper {
/**
* Override the encounter that spawns for the scene
* @param encounterType - The {@linkcode MysteryEncounterType} of the encounter
* @param encounterType What {@linkcode MysteryEncounterType | type} of encounter to set
* @returns `this`
*/
public mysteryEncounter(encounterType: MysteryEncounterType): this {

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 = 7;
const SINGLE_SHOP_ROW_YOFFSET = 12;
@ -189,10 +189,16 @@ 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, this.scene.gameMode).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 ? -SINGLE_SHOP_ROW_YOFFSET : -DOUBLE_SHOP_ROW_YOFFSET;
@ -559,7 +565,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));
@ -828,7 +834,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));