Merge branch 'beta' into pokerouge

This commit is contained in:
damocleas 2025-08-07 21:22:47 -04:00 committed by GitHub
commit aa240bfdf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 122 additions and 121 deletions

@ -1 +1 @@
Subproject commit fa35780fed762017c89d1e9ece8a2779dff56c4d
Subproject commit ab2716d5440c25f73986664aa3f3131821c3c392

View File

@ -16,7 +16,7 @@ export type * from "#moves/move";
* Map of move subclass names to their respective classes.
* Does not include the ChargeMove subclasses. For that, use `ChargingMoveClassMap`.
*
* @privateremarks
* @privateRemarks
* The `never` field (`declare private _: never`) in some classes is necessary
* to ensure typescript does not improperly narrow a failed `is` guard to `never`.
*

View File

@ -242,8 +242,8 @@ export class BattleScene extends SceneBase {
public battleStyle: BattleStyle = BattleStyle.SWITCH;
/**
* Defines whether or not to show type effectiveness hints
* - true: No hints
* - false: Show hints for moves
* - true: Show hints for moves
* - false: No hints
*/
public typeHints = false;

View File

@ -1284,7 +1284,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
/**
* Set stat stages when the user gets hit by a critical hit
*
* @privateremarks
* @privateRemarks
* It is the responsibility of the caller to ensure that this ability attribute is only applied
* when the user has been hit by a critical hit; such an event is not checked here.
*
@ -2043,7 +2043,7 @@ export class AllyStatMultiplierAbAttr extends AbAttr {
/**
* @param stat - The stat being modified
* @param multipler - The multiplier to apply to the stat
* @param multiplier - The multiplier to apply to the stat
* @param ignorable - Whether the multiplier can be ignored by mold breaker-like moves and abilities
*/
constructor(stat: BattleStat, multiplier: number, ignorable = true) {
@ -6444,23 +6444,23 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr {
public override canApply({ pokemon, source, damage }: PostDamageAbAttrParams): boolean {
const moveHistory = pokemon.getMoveHistory();
// Will not activate when the Pokémon's HP is lowered by cutting its own HP
const fordbiddenAttackingMoves = [MoveId.BELLY_DRUM, MoveId.SUBSTITUTE, MoveId.CURSE, MoveId.PAIN_SPLIT];
const forbiddenAttackingMoves = [MoveId.BELLY_DRUM, MoveId.SUBSTITUTE, MoveId.CURSE, MoveId.PAIN_SPLIT];
if (moveHistory.length > 0) {
const lastMoveUsed = moveHistory[moveHistory.length - 1];
if (fordbiddenAttackingMoves.includes(lastMoveUsed.move)) {
if (forbiddenAttackingMoves.includes(lastMoveUsed.move)) {
return false;
}
}
// Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.
const fordbiddenDefendingMoves = [MoveId.DRAGON_TAIL, MoveId.CIRCLE_THROW];
const forbiddenDefendingMoves = [MoveId.DRAGON_TAIL, MoveId.CIRCLE_THROW];
if (source) {
const enemyMoveHistory = source.getMoveHistory();
if (enemyMoveHistory.length > 0) {
const enemyLastMoveUsed = enemyMoveHistory[enemyMoveHistory.length - 1];
// Will not activate if the Pokémon's HP falls below half while it is in the air during Sky Drop.
if (
fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move) ||
forbiddenDefendingMoves.includes(enemyLastMoveUsed.move) ||
(enemyLastMoveUsed.move === MoveId.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER)
) {
return false;

View File

@ -46,7 +46,7 @@ import {
} from "#mystery-encounters/mystery-encounter-requirements";
import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config";
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { MoveInfoOverlay } from "#ui/move-info-overlay";
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common";
import i18next from "i18next";

View File

@ -45,7 +45,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
import { trainerConfigs } from "#trainers/trainer-config";
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
import type { OptionSelectConfig } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
import { randSeedInt, randSeedShuffle } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";

View File

@ -37,7 +37,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
import { MoveRequirement } from "#mystery-encounters/mystery-encounter-requirements";
import { DANCING_MOVES } from "#mystery-encounters/requirement-groups";
import { PokemonData } from "#system/pokemon-data";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";

View File

@ -33,7 +33,7 @@ import {
MoneyRequirement,
} from "#mystery-encounters/mystery-encounter-requirements";
import i18next from "#plugins/i18n";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { randSeedItem } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";

View File

@ -18,7 +18,7 @@ import {
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import i18next from "i18next";
/** i18n namespace for the encounter */

View File

@ -42,7 +42,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
import { PartySizeRequirement } from "#mystery-encounters/mystery-encounter-requirements";
import { PokemonData } from "#system/pokemon-data";
import { MusicPreference } from "#system/settings";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { isNullOrUndefined, NumberHolder, randInt, randSeedInt, randSeedItem, randSeedShuffle } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";

View File

@ -27,7 +27,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
import { PokemonData } from "#system/pokemon-data";
import type { HeldModifierConfig } from "#types/held-modifier-config";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { isNullOrUndefined, randSeedShuffle } from "#utils/common";
import { getEnumValues } from "#utils/enums";
import i18next from "i18next";

View File

@ -156,7 +156,7 @@ export class MysteryEncounterOption implements IMysteryEncounterOption {
return true;
}
console.log(
"Mystery Encounter Edge Case: Requirement not met due to primay pokemon overlapping with support pokemon. There's no valid primary pokemon left.",
"Mystery Encounter Edge Case: Requirement not met due to primary pokemon overlapping with support pokemon. There's no valid primary pokemon left.",
);
return false;
}

View File

@ -576,7 +576,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
*/
/**
* @statif Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType
* @static Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType
* NOTE: if new functions are added to {@linkcode MysteryEncounter} class
* @param encounterType
* @returns this
@ -605,7 +605,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
}
/**
* Defines an option + phasefor the encounter.
* Defines an option + phase for the encounter.
* Use for easy/streamlined options.
* There should be at least 2 options defined and no more than 4.
* If complex use {@linkcode MysteryEncounterBuilder.withOption}
@ -627,7 +627,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
}
/**
* Defines an option + phasefor the encounter.
* Defines an option + phase for the encounter.
* Use for easy/streamlined options.
* There should be at least 2 options defined and no more than 4.
* If complex use {@linkcode MysteryEncounterBuilder.withOption}

View File

@ -6,7 +6,7 @@ import { isNullOrUndefined } from "#utils/common";
import i18next from "i18next";
/**
* Will inject all relevant dialogue tokens that exist in the {@linkcode BattlegScene.currentBattle.mysteryEncounter.dialogueTokens}, into i18n text.
* Will inject all relevant dialogue tokens that exist in the {@linkcode globalScene.currentBattle.mysteryEncounter.dialogueTokens}, into i18n text.
* Also adds BBCodeText fragments for colored text, if applicable
* @param keyOrString
* @param primaryStyle Can define a text style to be applied to the entire string. Must be defined for BBCodeText styles to be applied correctly

View File

@ -46,7 +46,7 @@ import type { PokemonData } from "#system/pokemon-data";
import type { TrainerConfig } from "#trainers/trainer-config";
import { trainerConfigs } from "#trainers/trainer-config";
import type { HeldModifierConfig } from "#types/held-modifier-config";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import type { PartyOption, PokemonSelectFilter } from "#ui/party-ui-handler";
import { PartyUiMode } from "#ui/party-ui-handler";
import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common";

View File

@ -4045,7 +4045,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* @param damage integer
* @param ignoreSegments boolean, not currently used
* @param preventEndure used to update damage if endure or sturdy
* @param ignoreFaintPhas flag on whether to add FaintPhase if pokemon after applying damage faints
* @param ignoreFaintPhase flag on whether to add FaintPhase if pokemon after applying damage faints
* @returns integer representing damage dealt
*/
damage(damage: number, _ignoreSegments = false, preventEndure = false, ignoreFaintPhase = false): number {
@ -5206,38 +5206,38 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
updateFusionPalette(ignoreOveride?: boolean): void {
if (!this.getFusionSpeciesForm(ignoreOveride)) {
updateFusionPalette(ignoreOverride?: boolean): void {
if (!this.getFusionSpeciesForm(ignoreOverride)) {
[this.getSprite(), this.getTintSprite()]
.filter(s => !!s)
.map(s => {
s.pipelineData[`spriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}`] = [];
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}`] = [];
s.pipelineData[`spriteColors${ignoreOverride && this.summonData.speciesForm ? "Base" : ""}`] = [];
s.pipelineData[`fusionSpriteColors${ignoreOverride && this.summonData.speciesForm ? "Base" : ""}`] = [];
});
return;
}
const speciesForm = this.getSpeciesForm(ignoreOveride);
const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOveride);
const speciesForm = this.getSpeciesForm(ignoreOverride);
const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride);
const spriteKey = speciesForm.getSpriteKey(
this.getGender(ignoreOveride) === Gender.FEMALE,
this.getGender(ignoreOverride) === Gender.FEMALE,
speciesForm.formIndex,
this.shiny,
this.variant,
);
const backSpriteKey = speciesForm
.getSpriteKey(this.getGender(ignoreOveride) === Gender.FEMALE, speciesForm.formIndex, this.shiny, this.variant)
.getSpriteKey(this.getGender(ignoreOverride) === Gender.FEMALE, speciesForm.formIndex, this.shiny, this.variant)
.replace("pkmn__", "pkmn__back__");
const fusionSpriteKey = fusionSpeciesForm.getSpriteKey(
this.getFusionGender(ignoreOveride) === Gender.FEMALE,
this.getFusionGender(ignoreOverride) === Gender.FEMALE,
fusionSpeciesForm.formIndex,
this.fusionShiny,
this.fusionVariant,
);
const fusionBackSpriteKey = fusionSpeciesForm
.getSpriteKey(
this.getFusionGender(ignoreOveride) === Gender.FEMALE,
this.getFusionGender(ignoreOverride) === Gender.FEMALE,
fusionSpeciesForm.formIndex,
this.fusionShiny,
this.fusionVariant,
@ -5522,8 +5522,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
[this.getSprite(), this.getTintSprite()]
.filter(s => !!s)
.map(s => {
s.pipelineData[`spriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}`] = spriteColors;
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}`] =
s.pipelineData[`spriteColors${ignoreOverride && this.summonData.speciesForm ? "Base" : ""}`] = spriteColors;
s.pipelineData[`fusionSpriteColors${ignoreOverride && this.summonData.speciesForm ? "Base" : ""}`] =
fusionSpriteColors;
});

View File

@ -105,7 +105,7 @@ import {
TempExtraModifierModifier,
TempStatStageBoosterModifier,
TerastallizeAccessModifier,
TerrastalizeModifier,
TerastallizeModifier,
TmModifier,
TurnHealModifier,
TurnHeldItemTransferModifier,
@ -431,7 +431,7 @@ export class TerastallizeModifierType extends PokemonModifierType {
super(
"",
`${PokemonType[teraType].toLowerCase()}_tera_shard`,
(type, args) => new TerrastalizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType),
(type, args) => new TerastallizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType),
(pokemon: PlayerPokemon) => {
if (
[pokemon.species.speciesId, pokemon.fusionSpecies?.speciesId].filter(

View File

@ -2073,7 +2073,7 @@ export abstract class ConsumablePokemonModifier extends ConsumableModifier {
}
}
export class TerrastalizeModifier extends ConsumablePokemonModifier {
export class TerastallizeModifier extends ConsumablePokemonModifier {
public declare type: TerastallizeModifierType;
public teraType: PokemonType;
@ -2084,9 +2084,9 @@ export class TerrastalizeModifier extends ConsumablePokemonModifier {
}
/**
* Checks if {@linkcode TerrastalizeModifier} should be applied
* Checks if {@linkcode TerastallizeModifier} should be applied
* @param playerPokemon The {@linkcode PlayerPokemon} that consumes the item
* @returns `true` if the {@linkcode TerrastalizeModifier} should be applied
* @returns `true` if the {@linkcode TerastallizeModifier} should be applied
*/
override shouldApply(playerPokemon?: PlayerPokemon): boolean {
return (
@ -2098,7 +2098,7 @@ export class TerrastalizeModifier extends ConsumablePokemonModifier {
}
/**
* Applies {@linkcode TerrastalizeModifier}
* Applies {@linkcode TerastallizeModifier}
* @param pokemon The {@linkcode PlayerPokemon} that consumes the item
* @returns `true` if hp was restored
*/
@ -3875,7 +3875,7 @@ const ModifierClassMap = Object.freeze({
ResetNegativeStatStageModifier,
FieldEffectModifier,
ConsumablePokemonModifier,
TerrastalizeModifier,
TerastallizeModifier,
PokemonHpRestoreModifier,
PokemonStatusHealModifier,
ConsumablePokemonMoveModifier,

View File

@ -11,7 +11,7 @@ export abstract class Phase {
/**
* The string name of the phase, used to identify the phase type for {@linkcode is}
*
* @privateremarks
* @privateRemarks
*
* When implementing a phase, you must set the `phaseName` property to the name of the phase.
*/

View File

@ -112,7 +112,7 @@ export class CommandPhase extends FieldPhase {
* Clear out all unusable moves in front of the currently acting pokemon's move queue.
*/
// TODO: Refactor move queue handling to ensure that this method is not necessary.
private clearUnusuableMoves(): void {
private clearUnusableMoves(): void {
const playerPokemon = this.getPokemon();
const moveQueue = playerPokemon.getMoveQueue();
if (moveQueue.length === 0) {
@ -143,7 +143,7 @@ export class CommandPhase extends FieldPhase {
* @returns Whether a queued move was successfully set to be executed.
*/
private tryExecuteQueuedMove(): boolean {
this.clearUnusuableMoves();
this.clearUnusableMoves();
const playerPokemon = globalScene.getPlayerField()[this.fieldIndex];
const moveQueue = playerPokemon.getMoveQueue();

View File

@ -5,7 +5,7 @@ import { ChallengeType } from "#enums/challenge-type";
import { UiMode } from "#enums/ui-mode";
import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier";
import { BattlePhase } from "#phases/battle-phase";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { BooleanHolder, randSeedInt } from "#utils/common";

View File

@ -16,7 +16,7 @@ import type { Modifier } from "#modifiers/modifier";
import { getDailyRunStarterModifiers, regenerateModifierPoolThresholds } from "#modifiers/modifier-type";
import type { SessionSaveData } from "#system/game-data";
import { vouchers } from "#system/voucher";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#utils/common";
import i18next from "i18next";

View File

@ -144,7 +144,7 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole
handler: () => changeGamepadHandler(g),
})),
{
label: i18next.t("settings:cancelContollerChoice"),
label: i18next.t("settings:cancelControllerChoice"),
handler: cancelHandler,
},
],

View File

@ -36,7 +36,7 @@ interface ArenaEffectInfo {
/** The enum string representation of the effect */
name: string;
/** {@linkcode ArenaEffectType} type of effect */
effecType: ArenaEffectType;
effectType: ArenaEffectType;
/** The maximum duration set by the effect */
maxDuration: number;
@ -246,7 +246,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
// Creates a proxy object to decide which text object needs to be updated
let textObject: Phaser.GameObjects.Text;
switch (fieldEffectInfo.effecType) {
switch (fieldEffectInfo.effectType) {
case ArenaEffectType.PLAYER:
textObject = this.flyoutTextPlayer;
break;
@ -300,7 +300,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
const existingTrapTagIndex = isArenaTrapTag
? this.fieldEffectInfo.findIndex(
e => tagAddedEvent.arenaTagType === e.tagType && arenaEffectType === e.effecType,
e => tagAddedEvent.arenaTagType === e.tagType && arenaEffectType === e.effectType,
)
: -1;
let name: string = getFieldEffectText(ArenaTagType[tagAddedEvent.arenaTagType]);
@ -318,7 +318,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
this.fieldEffectInfo.push({
name,
effecType: arenaEffectType,
effectType: arenaEffectType,
maxDuration: tagAddedEvent.duration,
duration: tagAddedEvent.duration,
tagType: tagAddedEvent.arenaTagType,
@ -353,7 +353,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
? WeatherType[fieldEffectChangedEvent.newWeatherType]
: TerrainType[fieldEffectChangedEvent.newTerrainType],
),
effecType:
effectType:
fieldEffectChangedEvent instanceof WeatherChangedEvent ? ArenaEffectType.WEATHER : ArenaEffectType.TERRAIN,
maxDuration: fieldEffectChangedEvent.duration,
duration: fieldEffectChangedEvent.duration,

View File

@ -1,6 +1,6 @@
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
import { AbstractOptionSelectUiHandler } from "#ui/abstact-option-select-ui-handler";
import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
export class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler {
modalContainer: Phaser.GameObjects.Container;

View File

@ -198,11 +198,11 @@ export class PlayerBattleInfo extends BattleInfo {
this.lastLevelCapped = isLevelCapped;
if (this.lastExp !== pokemon.exp || this.lastLevel !== pokemon.level) {
const durationMultipler = Math.max(
const durationMultiplier = Math.max(
Phaser.Tweens.Builders.GetEaseFunction("Cubic.easeIn")(1 - Math.min(pokemon.level - this.lastLevel, 10) / 10),
0.1,
);
await this.updatePokemonExp(pokemon, false, durationMultipler);
await this.updatePokemonExp(pokemon, false, durationMultiplier);
} else if (isLevelCapped !== oldLevelCapped) {
this.setLevel(pokemon.level);
}

View File

@ -42,7 +42,7 @@ export class CommandUiHandler extends UiHandler {
ui.add(this.commandsContainer);
this.teraButton = globalScene.add.sprite(-32, 15, "button_tera");
this.teraButton.setName("terrastallize-button");
this.teraButton.setName("terastallize-button");
this.teraButton.setScale(1.3);
this.teraButton.setFrame("fire");
this.teraButton.setPipeline(globalScene.spritePipeline, {

View File

@ -1,8 +1,8 @@
import { globalScene } from "#app/global-scene";
import { Button } from "#enums/buttons";
import { UiMode } from "#enums/ui-mode";
import type { OptionSelectConfig } from "#ui/abstact-option-select-ui-handler";
import { AbstractOptionSelectUiHandler } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
import i18next from "i18next";
export class ConfirmUiHandler extends AbstractOptionSelectUiHandler {

View File

@ -2,7 +2,7 @@ import { pokerogueApi } from "#api/pokerogue-api";
import { globalScene } from "#app/global-scene";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
import type { ModalConfig } from "#ui/modal-ui-handler";

View File

@ -7,7 +7,7 @@ import { Button } from "#enums/buttons";
import { GameDataType } from "#enums/game-data-type";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { AdminMode, getAdminModeName } from "#ui/admin-ui-handler";
import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler";
import { BgmBar } from "#ui/bgm-bar";

View File

@ -843,7 +843,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
/**
* Start the tweens responsible for animating the option's appearance
*
* @privateremarks
* @privateRemarks
* This method is unusual. It "returns" (one via the actual return, one by via appending to the `promiseHolder`
* parameter) two promises. The promise returned by the method resolves once the option's appearance animations have
* completed, and is meant to allow callers to synchronize with the completion of the option's appearance animations.

View File

@ -46,7 +46,7 @@ import { getVariantIcon, getVariantTint } from "#sprites/variant";
import type { StarterAttributes } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { BaseStatsOverlay } from "#ui/base-stats-overlay";
import { MessageUiHandler } from "#ui/message-ui-handler";
import { MoveInfoOverlay } from "#ui/move-info-overlay";

View File

@ -1,7 +1,7 @@
import { allAbilities, allMoves, allSpecies } from "#data/data-lists";
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { FilterTextRow } from "#ui/filter-text";
import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
import { FormModalUiHandler } from "#ui/form-modal-ui-handler";

View File

@ -33,7 +33,7 @@ import { getVariantIcon, getVariantTint } from "#sprites/variant";
import type { DexAttrProps, StarterAttributes } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
import type { OptionSelectConfig } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler";
import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown";
import { FilterBar } from "#ui/filter-bar";
import { FilterText, FilterTextRow } from "#ui/filter-text";

View File

@ -702,11 +702,11 @@ export class RunInfoUiHandler extends UiHandler {
rules.push(i18next.t("challenges:inverseBattle.shortName"));
break;
default: {
const localisationKey = Challenges[this.runInfo.challenges[i].id]
const localizationKey = Challenges[this.runInfo.challenges[i].id]
.split("_")
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("");
rules.push(i18next.t(`challenges:${localisationKey}.name`));
rules.push(i18next.t(`challenges:${localizationKey}.name`));
break;
}
}

View File

@ -401,7 +401,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
const gameModeLabel = addTextObject(
8,
5,
`${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unkown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`,
`${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unknown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`,
TextStyle.WINDOW,
);
this.add(gameModeLabel);

View File

@ -8,7 +8,7 @@ import { UiHandler } from "#ui/ui-handler";
import { addWindow } from "#ui/ui-theme";
import i18next from "i18next";
type CancelFn = (succes?: boolean) => boolean;
type CancelFn = (success?: boolean) => boolean;
/**
* Abstract class for handling UI elements related to button bindings.

View File

@ -1,5 +1,5 @@
import { UiMode } from "#enums/ui-mode";
import { AbstractOptionSelectUiHandler } from "#ui/abstact-option-select-ui-handler";
import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler";
export class OptionSelectUiHandler extends AbstractOptionSelectUiHandler {
constructor(mode: UiMode = UiMode.OPTION_SELECT) {

View File

@ -47,7 +47,7 @@ import { achvs } from "#system/achv";
import type { DexAttrProps, StarterAttributes, StarterMoveset } from "#system/game-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown";
import { FilterBar } from "#ui/filter-bar";
import { MessageUiHandler } from "#ui/message-ui-handler";
@ -901,7 +901,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonEggMovesContainer.add(eggMoveContainer);
}
this.teraIcon = globalScene.add.sprite(85, 63, "button_tera").setName("terrastallize-icon").setFrame("fire");
this.teraIcon = globalScene.add.sprite(85, 63, "button_tera").setName("terastallize-icon").setFrame("fire");
// The font size should be set per language
const instructionTextSize = textSettings.instructionTextSize;

View File

@ -879,7 +879,7 @@ export class SummaryUiHandler extends UiHandler {
!isNullOrUndefined(this.pokemon)
) {
const teraIcon = globalScene.add.sprite(123, 26, "button_tera");
teraIcon.setName("terrastallize-icon");
teraIcon.setName("terastallize-icon");
teraIcon.setFrame(PokemonType[this.pokemon.getTeraType()].toLowerCase());
profileContainer.add(teraIcon);
}

View File

@ -1,6 +1,6 @@
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
import type { ModalConfig } from "#ui/modal-ui-handler";
@ -13,7 +13,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
setup() {
super.setup();
const flattenKeys = (object?: any, topKey?: string, midleKey?: string[]): Array<any> => {
const flattenKeys = (object?: any, topKey?: string, middleKey?: string[]): Array<any> => {
return Object.keys(object ?? {})
.map((t, i) => {
const value = Object.values(object)[i];
@ -23,7 +23,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
// If the value is an object, execute the same process
// si el valor es un objeto ejecuta el mismo proceso
return flattenKeys(value, topKey ?? t, topKey ? (midleKey ? [...midleKey, t] : [t]) : undefined).filter(
return flattenKeys(value, topKey ?? t, topKey ? (middleKey ? [...middleKey, t] : [t]) : undefined).filter(
t => t.length > 0,
);
}
@ -31,7 +31,7 @@ export class TestDialogueUiHandler extends FormModalUiHandler {
// we check for null or undefined here as per above - the typeof is still an object but the value is null so we need to exit out of this and pass the null key
// Return in the format expected by i18next
return midleKey ? `${topKey}:${midleKey.map(m => m).join(".")}.${t}` : `${topKey}:${t}`;
return middleKey ? `${topKey}:${middleKey.map(m => m).join(".")}.${t}` : `${topKey}:${t}`;
}
})
.filter(t => t);

View File

@ -1,10 +1,15 @@
import { getPokemonNameWithAffix } from "#app/messages";
import { allAbilities } from "#data/data-lists";
import { AbilityId } from "#enums/ability-id";
import { Button } from "#enums/buttons";
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { GameManager } from "#test/test-utils/game-manager";
import type { PartyUiHandler } from "#ui/party-ui-handler";
import i18next from "i18next";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Abilities - Arena Trap", () => {
let phaserGame: Phaser.Game;
@ -23,68 +28,64 @@ describe("Abilities - Arena Trap", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.moveset(MoveId.SPLASH)
.ability(AbilityId.ARENA_TRAP)
.enemyAbility(AbilityId.ARENA_TRAP)
.enemySpecies(SpeciesId.RALTS)
.enemyAbility(AbilityId.BALL_FETCH)
.enemyMoveset(MoveId.TELEPORT);
.enemyMoveset(MoveId.SPLASH);
});
// TODO: Enable test when Issue #935 is addressed
it.todo("should not allow grounded Pokémon to flee", async () => {
// NB: Since switching moves bypass trapping, the only way fleeing can occur in PKR is from the player
// TODO: Implement once forced flee helper exists
it.todo("should interrupt player flee attempt and display message, unless user has Run Away");
// TODO: Figure out how to wrangle the UI into not timing out
it.todo("should interrupt player switch attempt and display message", async () => {
game.override.battleStyle("single");
await game.classicMode.startBattle([SpeciesId.DUGTRIO, SpeciesId.GOTHITELLE]);
await game.classicMode.startBattle();
const enemy = game.field.getEnemyPokemon();
const enemy = game.scene.getEnemyPokemon();
game.doSwitchPokemon(1);
game.onNextPrompt("CommandPhase", UiMode.PARTY, () => {
// no switch out command should be queued due to arena trap
expect(game.scene.currentBattle.turnCommands[0]).toBeNull();
game.move.select(MoveId.SPLASH);
// back out and end the phase to avoid timeout
console.log(game.scene.ui.getHandler().constructor.name);
(game.scene.ui.getHandler() as PartyUiHandler).processInput(Button.CANCEL);
});
await game.toNextTurn();
await game.phaseInterceptor.to("CommandPhase");
expect(enemy).toBe(game.scene.getEnemyPokemon());
expect(game.textInterceptor.logs).toContain(
i18next.t("abilityTriggers:arenaTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(enemy),
abilityName: allAbilities[AbilityId.ARENA_TRAP].name,
}),
);
});
it("should guarantee double battle with any one LURE", async () => {
game.override.startingModifier([{ name: "LURE" }]).startingWave(2);
await game.classicMode.startBattle([SpeciesId.DUGTRIO]);
await game.classicMode.startBattle();
expect(game.scene.getEnemyField().length).toBe(2);
expect(game.scene.getEnemyField()).toHaveLength(2);
});
/**
* This checks if the Player Pokemon is able to switch out/run away after the Enemy Pokemon with {@linkcode AbilityId.ARENA_TRAP}
* is forcefully moved out of the field from moves such as Roar {@linkcode MoveId.ROAR}
*
* Note: It should be able to switch out/run away
*/
it("should lift if pokemon with this ability leaves the field", async () => {
game.override
.battleStyle("double")
.enemyMoveset(MoveId.SPLASH)
.moveset([MoveId.ROAR, MoveId.SPLASH])
.ability(AbilityId.BALL_FETCH);
await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.SUDOWOODO, SpeciesId.LUNATONE]);
game.override.battleStyle("single");
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const [enemy1, enemy2] = game.scene.getEnemyField();
const [player1, player2] = game.scene.getPlayerField();
const player = game.field.getPlayerPokemon();
const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy1, "getAbility").mockReturnValue(allAbilities[AbilityId.ARENA_TRAP]);
expect(player.isTrapped()).toBe(true);
expect(enemy.isOnField()).toBe(true);
game.move.select(MoveId.ROAR);
game.move.select(MoveId.SPLASH, 1);
game.move.use(MoveId.ROAR);
await game.toEndOfTurn();
// This runs the fist command phase where the moves are selected
await game.toNextTurn();
// During the next command phase the player pokemons should not be trapped anymore
game.move.select(MoveId.SPLASH);
game.move.select(MoveId.SPLASH, 1);
await game.toNextTurn();
expect(player1.isTrapped()).toBe(false);
expect(player2.isTrapped()).toBe(false);
expect(enemy1.isOnField()).toBe(false);
expect(enemy2.isOnField()).toBe(true);
expect(player.isTrapped()).toBe(false);
expect(enemy.isOnField()).toBe(false);
});
});

View File

@ -10,7 +10,7 @@ import { EncounterPhase } from "#phases/encounter-phase";
import { SelectStarterPhase } from "#phases/select-starter-phase";
import type { TitlePhase } from "#phases/title-phase";
import { GameManager } from "#test/test-utils/game-manager";
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler";
import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler";
import type { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler";
import type { StarterSelectUiHandler } from "#ui/starter-select-ui-handler";