Compare commits

..

No commits in common. "6a58d1b928f1feeb571a7196fd4eca221368292f" and "32d4102594c43a2d303d22bef3203c40393b6732" have entirely different histories.

24 changed files with 136 additions and 334 deletions

View File

@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the Feature**
<!-- A clear and concise description of what you want to happen. -->
<!-- Add a link to the feature if it is an existing move/ability/etc -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@ -1,39 +0,0 @@
name: Feature Request
description: Suggest an idea for this project
title: "[Feature] "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request!
- type: textarea
id: relation
attributes:
label: Is your feature request related to a problem? Please describe.
description: Clear and concise description of what the problem is.
placeholder: E.g. "I'm always frustrated when [...]"
validations:
required: true
- type: markdown
attributes:
value: |
---
- type: textarea
id: description
attributes:
label: Describe the Feature
description: A clear and concise description of what you want to happen. Add a link to the feature if it is an existing move/ability/etc.
validations:
required: true
- type: markdown
attributes:
value: |
---
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
validations:
required: true

View File

@ -5,12 +5,12 @@
## What are the changes? ## What are the changes?
<!-- Summarize what are the changes from a user perspective on the application --> <!-- Summarize what are the changes from a user perspective on the application -->
## Why am I doing these changes the user will see? ## Why am I doing these changes?
<!-- Explain why you decided to introduce these changes --> <!-- Explain why you decided to introduce these changes -->
<!-- Does it come from an issue or another PR? Please link it --> <!-- Does it come from an issue or another PR? Please link it -->
<!-- Explain why you believe this can enhance user experience --> <!-- Explain why you believe this can enhance user experience -->
## What are the changes from a developer perspective? ## What did change?
<!-- Explicitly state what are the changes introduced by the PR --> <!-- Explicitly state what are the changes introduced by the PR -->
<!-- You can make use of a comparison between what was the state before and after your PR changes --> <!-- You can make use of a comparison between what was the state before and after your PR changes -->
@ -30,7 +30,6 @@
- [ ] The PR is self-contained and cannot be split into smaller PRs? - [ ] The PR is self-contained and cannot be split into smaller PRs?
- [ ] Have I provided a clear explanation of the changes? - [ ] Have I provided a clear explanation of the changes?
- [ ] Have I considered writing automated tests for the issue? - [ ] Have I considered writing automated tests for the issue?
- [ ] If I have text, did I add placeholders for them in locales?
- [ ] Have I tested the changes (manually)? - [ ] Have I tested the changes (manually)?
- [ ] Are all unit tests still passing? (`npm run test`) - [ ] Are all unit tests still passing? (`npm run test`)
- [ ] Are the changes visual? - [ ] Are the changes visual?

View File

@ -941,19 +941,14 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr { export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
private weatherType: WeatherType; private weatherType: WeatherType;
protected condition: PokemonDefendCondition | null;
constructor(weatherType: WeatherType, condition?: PokemonDefendCondition) { constructor(weatherType: WeatherType) {
super(); super();
this.weatherType = weatherType; this.weatherType = weatherType;
this.condition = condition ?? null;
} }
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (this.condition !== null && !this.condition(pokemon, attacker, move)) {
return false;
}
if (!pokemon.scene.arena.weather?.isImmutable()) { if (!pokemon.scene.arena.weather?.isImmutable()) {
return pokemon.scene.arena.trySetWeather(this.weatherType, true); return pokemon.scene.arena.trySetWeather(this.weatherType, true);
} }
@ -5097,7 +5092,7 @@ export function initAbilities() {
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.SOUND_BASED), 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.SOUND_BASED), 0.5)
.ignorable(), .ignorable(),
new Ability(Abilities.SAND_SPIT, 8) new Ability(Abilities.SAND_SPIT, 8)
.attr(PostDefendWeatherChangeAbAttr, WeatherType.SANDSTORM, (target, user, move) => move.category !== MoveCategory.STATUS), .attr(PostDefendWeatherChangeAbAttr, WeatherType.SANDSTORM),
new Ability(Abilities.ICE_SCALES, 8) new Ability(Abilities.ICE_SCALES, 8)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.SPECIAL, 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.SPECIAL, 0.5)
.ignorable(), .ignorable(),

View File

@ -3222,7 +3222,7 @@ export class PlayerPokemon extends Pokemon {
} }
if (!dataSource) { if (!dataSource) {
this.moveset = []; this.generateAndPopulateMoveset();
} }
this.generateCompatibleTms(); this.generateCompatibleTms();
} }

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passive", "passive": "Passive",
"passiveUnlocked": "Passive freigeschaltet", "passiveUnlocked": "Passive freigeschaltet",
"passiveLocked": "Passive gesperrt", "passiveLocked": "Passive gesperrt",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Band", "ribbon": "Band",
"hasWon": "Hat Klassik-Modus gewonnen", "hasWon": "Hat Klassik-Modus gewonnen",
"hasNotWon": "Hat Klassik-Modus nicht gewonnen", "hasNotWon": "Hat Klassik-Modus nicht gewonnen",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "Pokédex-Nummer", "sortByNumber": "Pokédex-Nummer",
"sortByCost": "Kosten", "sortByCost": "Kosten",
"sortByCandies": "Anzahl Bonbons", "sortByCandies": "Anzahl Bonbons",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passive", "passive": "Passive",
"passiveUnlocked": "Passive Unlocked", "passiveUnlocked": "Passive Unlocked",
"passiveLocked": "Passive Locked", "passiveLocked": "Passive Locked",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Ribbon", "ribbon": "Ribbon",
"hasWon": "Ribbon - Yes", "hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No", "hasNotWon": "Ribbon - No",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "No.", "sortByNumber": "No.",
"sortByCost": "Cost", "sortByCost": "Cost",
"sortByCandies": "Candy Count", "sortByCandies": "Candy Count",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passive", "passive": "Passive",
"passiveUnlocked": "Pasiva Desbloq.", "passiveUnlocked": "Pasiva Desbloq.",
"passiveLocked": "Pasiva Bloq.", "passiveLocked": "Pasiva Bloq.",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Ribbon", "ribbon": "Ribbon",
"hasWon": "Ya ha ganado", "hasWon": "Ya ha ganado",
"hasNotWon": "Aún no ha ganado", "hasNotWon": "Aún no ha ganado",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "Núm.", "sortByNumber": "Núm.",
"sortByCost": "Coste", "sortByCost": "Coste",
"sortByCandies": "# Caramelos", "sortByCandies": "# Caramelos",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passif", "passive": "Passif",
"passiveUnlocked": "Passif débloqué", "passiveUnlocked": "Passif débloqué",
"passiveLocked": "Passif verrouillé", "passiveLocked": "Passif verrouillé",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Ruban", "ribbon": "Ruban",
"hasWon": "Ruban - Oui", "hasWon": "Ruban - Oui",
"hasNotWon": "Ruban - Non", "hasNotWon": "Ruban - Non",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "Par N°", "sortByNumber": "Par N°",
"sortByCost": "Par cout", "sortByCost": "Par cout",
"sortByCandies": "Par bonbons", "sortByCandies": "Par bonbons",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passive", "passive": "Passive",
"passiveUnlocked": "Passiva sbloccata", "passiveUnlocked": "Passiva sbloccata",
"passiveLocked": "Passiva bloccata", "passiveLocked": "Passiva bloccata",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Ribbon", "ribbon": "Ribbon",
"hasWon": "Ribbon - Yes", "hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No", "hasNotWon": "Ribbon - No",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "Num. Dex", "sortByNumber": "Num. Dex",
"sortByCost": "Costo", "sortByCost": "Costo",
"sortByCandies": "Caramelle", "sortByCandies": "Caramelle",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "패시브", "passive": "패시브",
"passiveUnlocked": "패시브 해금", "passiveUnlocked": "패시브 해금",
"passiveLocked": "패시브 잠김", "passiveLocked": "패시브 잠김",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "클리어 여부", "ribbon": "클리어 여부",
"hasWon": "클리어 함", "hasWon": "클리어 함",
"hasNotwon": "클리어 안함", "hasNotwon": "클리어 안함",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "도감번호", "sortByNumber": "도감번호",
"sortByCost": "코스트", "sortByCost": "코스트",
"sortByCandies": "사탕 수", "sortByCandies": "사탕 수",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "Passiva", "passive": "Passiva",
"passiveUnlocked": "Passiva Desbloq.", "passiveUnlocked": "Passiva Desbloq.",
"passiveLocked": "Passiva Bloq.", "passiveLocked": "Passiva Bloq.",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "Fita", "ribbon": "Fita",
"hasWon": "Fita - Sim", "hasWon": "Fita - Sim",
"hasNotWon": "Fita - Não", "hasNotWon": "Fita - Não",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "Número", "sortByNumber": "Número",
"sortByCost": "Custo", "sortByCost": "Custo",
"sortByCandies": "# Doces", "sortByCandies": "# Doces",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "被动", "passive": "被动",
"passiveUnlocked": "被动解锁", "passiveUnlocked": "被动解锁",
"passiveLocked": "被动未解锁", "passiveLocked": "被动未解锁",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "缎带", "ribbon": "缎带",
"hasWon": "有缎带", "hasWon": "有缎带",
"hasNotWon": "无缎带", "hasNotWon": "无缎带",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "编号", "sortByNumber": "编号",
"sortByCost": "费用", "sortByCost": "费用",
"sortByCandies": "糖果", "sortByCandies": "糖果",

View File

@ -13,18 +13,9 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "被動", "passive": "被動",
"passiveUnlocked": "被動解鎖", "passiveUnlocked": "被動解鎖",
"passiveLocked": "被動未解鎖", "passiveLocked": "被動未解鎖",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "緞帶", "ribbon": "緞帶",
"hasWon": "有緞帶", "hasWon": "有緞帶",
"hasNotWon": "無緞帶", "hasNotWon": "無緞帶",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "編號", "sortByNumber": "編號",
"sortByCost": "花費", "sortByCost": "花費",
"sortByCandies": "糖果", "sortByCandies": "糖果",

View File

@ -642,10 +642,6 @@ export class SelectStarterPhase extends Phase {
this.scene.arena.init(); this.scene.arena.init();
this.scene.sessionPlayTime = 0; this.scene.sessionPlayTime = 0;
this.scene.lastSavePlayTime = 0; this.scene.lastSavePlayTime = 0;
// Ensures Keldeo (or any future Pokemon that have this type of form change) starts in the correct form
this.scene.getParty().forEach((p: PlayerPokemon) => {
this.scene.triggerPokemonFormChange(p, SpeciesFormChangeMoveLearnedTrigger);
});
this.end(); this.end();
}); });
} }

View File

@ -8,10 +8,15 @@ import { generateStarter, getMovePosition } from "#app/test/utils/gameManagerUti
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import { Status, StatusEffect } from "#app/data/status-effect"; import { Status, StatusEffect } from "#app/data/status-effect";
import { GameModes, getGameMode } from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode";
import { CommandPhase, DamagePhase, EncounterPhase, EnemyCommandPhase, SelectStarterPhase, TurnInitPhase } from "#app/phases"; import {
CommandPhase, DamagePhase, EncounterPhase,
EnemyCommandPhase, SelectStarterPhase,
TurnInitPhase,
} from "#app/phases";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { removeEnemyHeldItems } from "../utils/testUtils";
describe("Abilities - Intimidate", () => { describe("Abilities - Intimidate", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -40,6 +45,7 @@ describe("Abilities - Intimidate", () => {
it("single - wild with switch", async () => { it("single - wild with switch", async () => {
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -70,6 +76,7 @@ describe("Abilities - Intimidate", () => {
it("single - boss should only trigger once then switch", async () => { it("single - boss should only trigger once then switch", async () => {
game.override.startingWave(10); game.override.startingWave(10);
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -99,6 +106,7 @@ describe("Abilities - Intimidate", () => {
it("single - trainer should only trigger once with switch", async () => { it("single - trainer should only trigger once with switch", async () => {
game.override.startingWave(5); game.override.startingWave(5);
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -129,6 +137,7 @@ describe("Abilities - Intimidate", () => {
game.override.battleType("double"); game.override.battleType("double");
game.override.startingWave(5); game.override.startingWave(5);
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -155,6 +164,7 @@ describe("Abilities - Intimidate", () => {
game.override.battleType("double"); game.override.battleType("double");
game.override.startingWave(3); game.override.startingWave(3);
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -181,6 +191,7 @@ describe("Abilities - Intimidate", () => {
game.override.battleType("double"); game.override.battleType("double");
game.override.startingWave(10); game.override.startingWave(10);
await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
game.onNextPrompt( game.onNextPrompt(
"CheckSwitchPhase", "CheckSwitchPhase",
Mode.CONFIRM, Mode.CONFIRM,
@ -207,6 +218,7 @@ describe("Abilities - Intimidate", () => {
game.override.startingWave(2); game.override.startingWave(2);
game.override.moveset([Moves.AERIAL_ACE]); game.override.moveset([Moves.AERIAL_ACE]);
await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -233,6 +245,7 @@ describe("Abilities - Intimidate", () => {
game.override.startingWave(2); game.override.startingWave(2);
game.override.moveset([Moves.SPLASH]); game.override.moveset([Moves.SPLASH]);
await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -258,6 +271,7 @@ describe("Abilities - Intimidate", () => {
game.override.enemyMoveset([Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH]); game.override.enemyMoveset([Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH]);
game.override.startingWave(5); game.override.startingWave(5);
await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -297,6 +311,7 @@ describe("Abilities - Intimidate", () => {
game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
game.override.startingWave(5); game.override.startingWave(5);
await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]);
removeEnemyHeldItems(game.scene);
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -336,6 +351,7 @@ describe("Abilities - Intimidate", () => {
game.override.startingWave(3); game.override.startingWave(3);
vi.spyOn(Overrides, "OPP_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "COIN_CASE" }]); vi.spyOn(Overrides, "OPP_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "COIN_CASE" }]);
await game.runToSummon([Species.MIGHTYENA]); await game.runToSummon([Species.MIGHTYENA]);
removeEnemyHeldItems(game.scene);
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);
const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
@ -362,6 +378,7 @@ describe("Abilities - Intimidate", () => {
}); });
await game.phaseInterceptor.run(EncounterPhase); await game.phaseInterceptor.run(EncounterPhase);
removeEnemyHeldItems(game.scene);
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);
const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;

View File

@ -40,7 +40,7 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); await game.startBattle([Species.PIKACHU, Species.STONJOURNER]);
game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM)); game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM));
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
@ -54,7 +54,7 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); await game.startBattle([Species.PIKACHU, Species.STONJOURNER]);
game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE)); game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE));
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
@ -68,7 +68,7 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.STONJOURNER, Species.REGIELEKI]); await game.startBattle([Species.STONJOURNER, Species.PIKACHU]);
game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE)); game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE));
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);

View File

@ -1,57 +0,0 @@
import GameManager from "#app/test/utils/gameManager";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { getMovePosition } from "../utils/gameManagerUtils";
import { WeatherType } from "#app/enums/weather-type.js";
describe("Ability Timing", () => {
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.override.battleType("single");
game.override.disableCrits();
game.override.enemySpecies(Species.MAGIKARP);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.starterSpecies(Species.SILICOBRA);
game.override.ability(Abilities.SAND_SPIT);
game.override.moveset([Moves.SPLASH, Moves.COIL]);
});
it("should trigger when hit with damaging move", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
await game.startBattle();
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.toNextTurn();
expect(game.scene.arena.weather.weatherType).toBe(WeatherType.SANDSTORM);
}, 20000);
it("should not trigger when targetted with status moves", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
await game.startBattle();
game.doAttack(getMovePosition(game.scene, 0, Moves.COIL));
await game.toNextTurn();
expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.SANDSTORM);
}, 20000);
});

View File

@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "../utils/testUtils"; import { removeEnemyHeldItems, SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Octolock", () => { describe("Moves - Octolock", () => {
describe("integration tests", () => { describe("integration tests", () => {
@ -41,6 +41,7 @@ describe("Moves - Octolock", () => {
it("Reduces DEf and SPDEF by 1 each turn", { timeout: 10000 }, async () => { it("Reduces DEf and SPDEF by 1 each turn", { timeout: 10000 }, async () => {
await game.startBattle([Species.GRAPPLOCT]); await game.startBattle([Species.GRAPPLOCT]);
removeEnemyHeldItems(game.scene);
const enemyPokemon = game.scene.getEnemyField(); const enemyPokemon = game.scene.getEnemyField();
@ -62,6 +63,7 @@ describe("Moves - Octolock", () => {
it("Traps the target pokemon", { timeout: 10000 }, async () => { it("Traps the target pokemon", { timeout: 10000 }, async () => {
await game.startBattle([Species.GRAPPLOCT]); await game.startBattle([Species.GRAPPLOCT]);
removeEnemyHeldItems(game.scene);
const enemyPokemon = game.scene.getEnemyField(); const enemyPokemon = game.scene.getEnemyField();

View File

@ -1,21 +1,31 @@
import GameWrapper from "#app/test/utils/gameWrapper"; import GameWrapper from "#app/test/utils/gameWrapper";
import { Mode } from "#app/ui/ui"; import {Mode} from "#app/ui/ui";
import { generateStarter, waitUntil } from "#app/test/utils/gameManagerUtils"; import {generateStarter, waitUntil} from "#app/test/utils/gameManagerUtils";
import { CommandPhase, EncounterPhase, FaintPhase, LoginPhase, NewBattlePhase, SelectStarterPhase, SelectTargetPhase, TitlePhase, TurnEndPhase, TurnInitPhase, TurnStartPhase } from "#app/phases"; import {
CommandPhase,
EncounterPhase,
FaintPhase,
LoginPhase,
NewBattlePhase,
SelectStarterPhase,
SelectTargetPhase,
TitlePhase, TurnEndPhase, TurnInitPhase,
TurnStartPhase,
} from "#app/phases";
import BattleScene from "#app/battle-scene.js"; import BattleScene from "#app/battle-scene.js";
import PhaseInterceptor from "#app/test/utils/phaseInterceptor"; import PhaseInterceptor from "#app/test/utils/phaseInterceptor";
import TextInterceptor from "#app/test/utils/TextInterceptor"; import TextInterceptor from "#app/test/utils/TextInterceptor";
import { GameModes, getGameMode } from "#app/game-mode"; import {GameModes, getGameMode} from "#app/game-mode";
import fs from "fs"; import fs from "fs";
import { AES, enc } from "crypto-js"; import {AES, enc} from "crypto-js";
import { updateUserInfo } from "#app/account"; import {updateUserInfo} from "#app/account";
import InputsHandler from "#app/test/utils/inputsHandler"; import InputsHandler from "#app/test/utils/inputsHandler";
import ErrorInterceptor from "#app/test/utils/errorInterceptor"; import ErrorInterceptor from "#app/test/utils/errorInterceptor";
import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import {EnemyPokemon, PlayerPokemon} from "#app/field/pokemon";
import { MockClock } from "#app/test/utils/mocks/mockClock"; import {MockClock} from "#app/test/utils/mocks/mockClock";
import { Command } from "#app/ui/command-ui-handler"; import {Command} from "#app/ui/command-ui-handler";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; import PartyUiHandler, {PartyUiMode} from "#app/ui/party-ui-handler";
import Trainer from "#app/field/trainer"; import Trainer from "#app/field/trainer";
import { ExpNotification } from "#enums/exp-notification"; import { ExpNotification } from "#enums/exp-notification";
import { GameDataType } from "#enums/game-data-type"; import { GameDataType } from "#enums/game-data-type";
@ -26,8 +36,6 @@ import { BattlerIndex } from "#app/battle.js";
import TargetSelectUiHandler from "#app/ui/target-select-ui-handler.js"; import TargetSelectUiHandler from "#app/ui/target-select-ui-handler.js";
import { OverridesHelper } from "./overridesHelper"; import { OverridesHelper } from "./overridesHelper";
import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js";
import overrides from "#app/overrides.js";
import { removeEnemyHeldItems } from "./testUtils";
/** /**
* Class to manage the game state and transitions between phases. * Class to manage the game state and transitions between phases.
@ -132,9 +140,6 @@ export default class GameManager {
}); });
await this.phaseInterceptor.run(EncounterPhase); await this.phaseInterceptor.run(EncounterPhase);
if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) {
removeEnemyHeldItems(this.scene);
}
} }
/** /**

View File

@ -34,5 +34,4 @@ export function arrayOfRange(start: integer, end: integer) {
export function removeEnemyHeldItems(scene: BattleScene) { export function removeEnemyHeldItems(scene: BattleScene) {
scene.clearEnemyHeldItemModifiers(); scene.clearEnemyHeldItemModifiers();
scene.clearEnemyModifiers(); scene.clearEnemyModifiers();
console.log("Enemy held items removed");
} }

View File

@ -27,10 +27,10 @@ export class DropDownLabel {
public text: string; public text: string;
public sprite?: Phaser.GameObjects.Sprite; public sprite?: Phaser.GameObjects.Sprite;
constructor(label: string, sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.OFF) { constructor(label: string, sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.ON) {
this.text = label || ""; this.text = label || "";
this.sprite = sprite; this.sprite = sprite;
this.state = state; this.state = state || DropDownState.ON;
} }
} }
@ -262,13 +262,12 @@ export class DropDown extends Phaser.GameObjects.Container {
public options: DropDownOption[]; public options: DropDownOption[];
private window: Phaser.GameObjects.NineSlice; private window: Phaser.GameObjects.NineSlice;
private cursorObj: Phaser.GameObjects.Image; private cursorObj: Phaser.GameObjects.Image;
public dropDownType: DropDownType = DropDownType.MULTI; private dropDownType: DropDownType = DropDownType.MULTI;
public cursor: number = 0; public cursor: number = 0;
private lastCursor: number = -1;
public defaultCursor: number = 0; public defaultCursor: number = 0;
private onChange: () => void; private onChange: () => void;
private lastDir: SortDirection = SortDirection.ASC; private lastDir: SortDirection = SortDirection.ASC;
private defaultSettings: any[]; private defaultValues: any[];
constructor(scene: BattleScene, x: number, y: number, options: DropDownOption[], onChange: () => void, type: DropDownType = DropDownType.MULTI, optionSpacing: number = 2) { constructor(scene: BattleScene, x: number, y: number, options: DropDownOption[], onChange: () => void, type: DropDownType = DropDownType.MULTI, optionSpacing: number = 2) {
const windowPadding = 5; const windowPadding = 5;
@ -293,7 +292,7 @@ export class DropDown extends Phaser.GameObjects.Container {
this.options.unshift(new DropDownOption(scene, "ALL", new DropDownLabel(i18next.t("filterBar:all"), undefined, this.checkForAllOn() ? DropDownState.ON : DropDownState.OFF))); this.options.unshift(new DropDownOption(scene, "ALL", new DropDownLabel(i18next.t("filterBar:all"), undefined, this.checkForAllOn() ? DropDownState.ON : DropDownState.OFF)));
} }
this.defaultSettings = this.getSettings(); this.defaultValues = this.getVals();
// Place ui elements in the correct spot // Place ui elements in the correct spot
options.forEach((option, index) => { options.forEach((option, index) => {
@ -340,8 +339,8 @@ export class DropDown extends Phaser.GameObjects.Container {
resetCursor(): boolean { resetCursor(): boolean {
// If we are an hybrid dropdown in "hover" mode, don't move the cursor back to 0 // If we are an hybrid dropdown in "hover" mode, don't move the cursor back to 0
if (this.dropDownType === DropDownType.HYBRID && this.checkForAllOff()) { if (this.dropDownType === DropDownType.HYBRID && this.checkForAllOff() && this.cursor > 0) {
return this.setCursor(this.lastCursor); return false;
} }
return this.setCursor(this.defaultCursor); return this.setCursor(this.defaultCursor);
} }
@ -362,7 +361,6 @@ export class DropDown extends Phaser.GameObjects.Container {
this.cursorObj.setVisible(true); this.cursorObj.setVisible(true);
// If hydrid type, we need to update the filters when going up/down in the list // If hydrid type, we need to update the filters when going up/down in the list
if (this.dropDownType === DropDownType.HYBRID) { if (this.dropDownType === DropDownType.HYBRID) {
this.lastCursor = cursor;
this.onChange(); this.onChange();
} }
} }
@ -459,43 +457,23 @@ export class DropDown extends Phaser.GameObjects.Container {
} }
} }
/**
* Get the current selected settings dictionary for each option
* @returns an array of dictionaries with the current state of each option
* - the settings dictionary is like this { val: any, state: DropDownState, cursor: boolean, dir: SortDirection }
*/
private getSettings(): any[] {
const settings = [];
for (let i = 0; i < this.options.length; i++) {
settings.push({ val: this.options[i].val, state: this.options[i].state , cursor: (this.cursor === i), dir: this.options[i].dir });
}
return settings;
}
/** /**
* Check whether the values of all options are the same as the default ones * Check whether the values of all options are the same as the default ones
* @returns true if they are the same, false otherwise * @returns true if they are the same, false otherwise
*/ */
public hasDefaultValues(): boolean { public hasDefaultValues(): boolean {
const currentValues = this.getSettings(); const currentValues = this.getVals();
const compareValues = (keys: string[]): boolean => {
return currentValues.length === this.defaultSettings.length &&
currentValues.every((value, index) =>
keys.every(key => value[key] === this.defaultSettings[index][key])
);
};
switch (this.dropDownType) { switch (this.dropDownType) {
case DropDownType.MULTI: case DropDownType.MULTI:
case DropDownType.RADIAL:
return compareValues(["val", "state"]);
case DropDownType.HYBRID: case DropDownType.HYBRID:
return compareValues(["val", "state", "cursor"]); return currentValues.length === this.defaultValues.length && currentValues.every((value, index) => value === this.defaultValues[index]);
case DropDownType.RADIAL:
return currentValues.every((value, index) => value["val"] === this.defaultValues[index]["val"] && value["state"] === this.defaultValues[index]["state"]);
case DropDownType.SINGLE: case DropDownType.SINGLE:
return compareValues(["val", "state", "dir"]); return currentValues[0]["dir"] === this.defaultValues[0]["dir"] && currentValues[0]["val"] === this.defaultValues[0]["val"];
default: default:
return false; return false;
@ -506,29 +484,46 @@ export class DropDown extends Phaser.GameObjects.Container {
* Set all values to their default state * Set all values to their default state
*/ */
public resetToDefault(): void { public resetToDefault(): void {
if (this.defaultSettings.length > 0) { this.setCursor(this.defaultCursor);
this.setCursor(this.defaultCursor);
this.lastDir = SortDirection.ASC;
for (let i = 0; i < this.options.length; i++) { for (let i = 0; i < this.options.length; i++) {
// reset values with the defaultValues const option = this.options[i];
if (this.dropDownType === DropDownType.SINGLE) { // reset values
if (this.defaultSettings[i].state === DropDownState.OFF) { switch (this.dropDownType) {
this.options[i].setOptionState(DropDownState.OFF); case DropDownType.HYBRID:
this.options[i].setDirection(SortDirection.ASC); case DropDownType.MULTI:
this.options[i].toggle.setVisible(false); if (this.defaultValues.includes(option.val)) {
} else { option.setOptionState(DropDownState.ON);
this.options[i].setOptionState(DropDownState.ON);
this.options[i].setDirection(SortDirection.ASC);
this.options[i].toggle.setVisible(true);
}
} else { } else {
if (this.defaultSettings[i]) { option.setOptionState(DropDownState.OFF);
this.options[i].setOptionState(this.defaultSettings[i]["state"]); }
break;
case DropDownType.RADIAL:
const targetValue = this.defaultValues.find(value => value.val === option.val);
option.setOptionState(targetValue.state);
break;
case DropDownType.SINGLE:
if (option.val === this.defaultValues[0].val) {
if (option.state !== DropDownState.ON) {
this.toggleOptionState(i);
}
if (option.dir !== this.defaultValues[0].dir) {
this.toggleOptionState(i);
} }
} }
break;
} }
} }
// Select or unselect "ALL" button if applicable
if (this.dropDownType === DropDownType.MULTI || this.dropDownType === DropDownType.HYBRID) {
if (this.checkForAllOn()) {
this.options[0].setOptionState(DropDownState.ON);
} else {
this.options[0].setOptionState(DropDownState.OFF);
}
}
} }
/** /**

View File

@ -1,5 +1,5 @@
import BattleScene from "#app/battle-scene.js"; import BattleScene from "#app/battle-scene.js";
import { DropDown, DropDownType } from "./dropdown"; import { DropDown } from "./dropdown";
import { StarterContainer } from "./starter-container"; import { StarterContainer } from "./starter-container";
import { addTextObject, getTextColor, TextStyle } from "./text"; import { addTextObject, getTextColor, TextStyle } from "./text";
import { UiTheme } from "#enums/ui-theme"; import { UiTheme } from "#enums/ui-theme";
@ -120,13 +120,11 @@ export class FilterBar extends Phaser.GameObjects.Container {
/** /**
* Move the leftmost dropdown to the left of the FilterBar instead of below it * Move the leftmost dropdown to the left of the FilterBar instead of below it
*/ */
offsetHybridFilters(): void { offsetFirstFilter(): void {
for (let i=0; i<this.dropDowns.length; i++) { if (this.dropDowns[0]) {
if (this.dropDowns[i].dropDownType === DropDownType.HYBRID) { this.dropDowns[0].autoSize();
this.dropDowns[i].autoSize(); this.dropDowns[0].x -= this.dropDowns[0].getWidth();
this.dropDowns[i].x = - this.dropDowns[i].getWidth(); this.dropDowns[0].y = 0;
this.dropDowns[i].y = 0;
}
} }
} }

View File

@ -431,16 +431,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
new DropDownLabel(i18next.t("filterBar:passiveUnlocked"), undefined, DropDownState.ON), new DropDownLabel(i18next.t("filterBar:passiveUnlocked"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:passiveLocked"), undefined, DropDownState.EXCLUDE), new DropDownLabel(i18next.t("filterBar:passiveLocked"), undefined, DropDownState.EXCLUDE),
]; ];
const costReductionLabels = [
new DropDownLabel(i18next.t("filterBar:costReduction"), undefined, DropDownState.OFF),
new DropDownLabel(i18next.t("filterBar:costReductionUnlocked"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:costReductionLocked"), undefined, DropDownState.EXCLUDE),
];
const unlocksOptions = [ const unlocksOptions = [
new DropDownOption(this.scene, "PASSIVE", passiveLabels), new DropDownOption(this.scene, "PASSIVE", passiveLabels),
new DropDownOption(this.scene, "COST_REDUCTION", costReductionLabels),
]; ];
this.filterBar.addFilter(DropDownColumn.UNLOCKS, i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.RADIAL)); this.filterBar.addFilter(DropDownColumn.UNLOCKS, i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.RADIAL));
@ -451,30 +443,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
new DropDownLabel(i18next.t("filterBar:hasWon"), undefined, DropDownState.ON), new DropDownLabel(i18next.t("filterBar:hasWon"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:hasNotWon"), undefined, DropDownState.EXCLUDE), new DropDownLabel(i18next.t("filterBar:hasNotWon"), undefined, DropDownState.EXCLUDE),
]; ];
const hiddenAbilityLabels = [
new DropDownLabel(i18next.t("filterBar:hiddenAbility"), undefined, DropDownState.OFF),
new DropDownLabel(i18next.t("filterBar:hasHiddenAbility"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:noHiddenAbility"), undefined, DropDownState.EXCLUDE),
];
const pokerusLabels = [
new DropDownLabel(i18next.t("filterBar:pokerus"), undefined, DropDownState.OFF),
new DropDownLabel(i18next.t("filterBar:hasPokerus"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:noPokerus"), undefined, DropDownState.EXCLUDE),
];
const miscOptions = [ const miscOptions = [
new DropDownOption(this.scene, "WIN", winLabels), new DropDownOption(this.scene, "WIN", winLabels),
new DropDownOption(this.scene, "HIDDEN_ABILITY", hiddenAbilityLabels),
new DropDownOption(this.scene, "POKERUS", pokerusLabels),
]; ];
this.filterBar.addFilter(DropDownColumn.MISC, i18next.t("filterBar:miscFilter"), new DropDown(this.scene, 0, 0, miscOptions, this.updateStarters, DropDownType.RADIAL)); this.filterBar.addFilter(DropDownColumn.MISC, i18next.t("filterBar:miscFilter"), new DropDown(this.scene, 0, 0, miscOptions, this.updateStarters, DropDownType.RADIAL));
// sort filter // sort filter
const sortOptions = [ const sortOptions = [
new DropDownOption(this.scene, 0, new DropDownLabel(i18next.t("filterBar:sortByNumber"), undefined, DropDownState.ON)), new DropDownOption(this.scene, 0, new DropDownLabel(i18next.t("filterBar:sortByNumber"))),
new DropDownOption(this.scene, 1, new DropDownLabel(i18next.t("filterBar:sortByCost"))), new DropDownOption(this.scene, 1, new DropDownLabel(i18next.t("filterBar:sortByCost"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 2, new DropDownLabel(i18next.t("filterBar:sortByCandies"))), new DropDownOption(this.scene, 2, new DropDownLabel(i18next.t("filterBar:sortByCandies"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 3, new DropDownLabel(i18next.t("filterBar:sortByIVs"))), new DropDownOption(this.scene, 3, new DropDownLabel(i18next.t("filterBar:sortByIVs"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 4, new DropDownLabel(i18next.t("filterBar:sortByName"))) new DropDownOption(this.scene, 4, new DropDownLabel(i18next.t("filterBar:sortByName"), undefined, DropDownState.OFF))
]; ];
this.filterBar.addFilter(DropDownColumn.SORT, i18next.t("filterBar:sortFilter"), new DropDown(this.scene, 0, 0, sortOptions, this.updateStarters, DropDownType.SINGLE)); this.filterBar.addFilter(DropDownColumn.SORT, i18next.t("filterBar:sortFilter"), new DropDown(this.scene, 0, 0, sortOptions, this.updateStarters, DropDownType.SINGLE));
this.filterBarContainer.add(this.filterBar); this.filterBarContainer.add(this.filterBar);
@ -482,7 +462,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.filterBarContainer); this.starterSelectContainer.add(this.filterBarContainer);
// Offset the generation filter dropdown to avoid covering the filtered pokemon // Offset the generation filter dropdown to avoid covering the filtered pokemon
this.filterBar.offsetHybridFilters(); this.filterBar.offsetFirstFilter();
if (!this.scene.uiTheme) { if (!this.scene.uiTheme) {
starterContainerWindow.setVisible(false); starterContainerWindow.setVisible(false);
@ -934,12 +914,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
*/ */
resetFilters() : void { resetFilters() : void {
const genDropDown: DropDown = this.filterBar.getFilter(DropDownColumn.GEN); const genDropDown: DropDown = this.filterBar.getFilter(DropDownColumn.GEN);
if (this.scene.gameMode.isChallenge) {
// In challenge mode all gens are selected by default
genDropDown.defaultCursor = 0;
} else {
// in other modes, gen 1 is selected by default, and all options disabled
genDropDown.defaultCursor = 1;
}
this.filterBar.setValsToDefault(); this.filterBar.setValsToDefault();
// for all modes except challenge, disable all gen options to enable hovering behavior
if (!this.scene.gameMode.isChallenge) { if (!this.scene.gameMode.isChallenge) {
// if not in a challenge, in Gen hybrid filter hovering mode, set the cursor to the Gen1 genDropDown.unselectAllOptions();
genDropDown.setCursor(1);
} }
} }
@ -2120,11 +2107,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const isCaught = !!(caughtVariants & DexAttr.NON_SHINY); const isCaught = !!(caughtVariants & DexAttr.NON_SHINY);
const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught; const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0; const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0;
const isCostReduced = this.scene.gameData.starterData[container.species.speciesId].valueReduction > 0;
const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0; const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0;
const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0; const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0;
const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined; const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined;
const isHA = this.scene.gameData.starterData[container.species.speciesId].abilityAttr & AbilityAttr.ABILITY_HIDDEN;
const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation); const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation);
@ -2154,16 +2139,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
} }
}); });
const fitsCostReduction = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.ON) {
return isCostReduced;
} else if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.EXCLUDE) {
return !isCostReduced;
} else if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.OFF) {
return true;
}
});
const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
if (container.species.speciesId < 10) { if (container.species.speciesId < 10) {
} }
@ -2176,27 +2151,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
} }
}); });
const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (fitsGen && fitsType && fitsShiny && fitsPassive && fitsWin) {
if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) {
return isHA;
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.EXCLUDE) {
return !isHA;
} else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.OFF) {
return true;
}
});
const fitsPokerus = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
if (misc.val === "POKERUS" && misc.state === DropDownState.ON) {
return this.pokerusSpecies.includes(container.species);
} else if (misc.val === "POKERUS" && misc.state === DropDownState.EXCLUDE) {
return !this.pokerusSpecies.includes(container.species);
} else if (misc.val === "POKERUS" && misc.state === DropDownState.OFF) {
return true;
}
});
if (fitsGen && fitsType && fitsShiny && fitsPassive && fitsCostReduction && fitsWin && fitsHA && fitsPokerus) {
this.filteredStarterContainers.push(container); this.filteredStarterContainers.push(container);
} }
}); });