Compare commits

...

18 Commits

Author SHA1 Message Date
Greenlamp2
dd40c8caa2
added silent option to run tests and added a missing properties in the MockText (#1967) 2024-06-08 21:24:57 +01:00
Greenlamp2
c301a54039
[Improvement] Refactored Test Phase Management with Error Handling (#1962)
* better phase management in tests

* cleanup runFrom/to

* first step of async error handling

* second step of async error handling, halt await, still an issue with select-starter test

* added back whenAboutToRun

* added back full run suite for starter-select.test.ts
2024-06-08 20:54:20 +01:00
SeafoamQueen
0af0ad5b49
[Bug] Fix run away ability (#1890)
* Added fix for Run Away ability being trapped by trapping abilities.
Added fix for ghost type pokemon not having a 100% chance to run from battles.

* Removed log statement

* Removed commented out code

* Removed ghost type run away mechanics
2024-06-08 15:46:16 -04:00
Yentis
3f9eaf4a5d
Add setting for showing type effectiveness hints (#1061)
* type hints

* fix overwritten change

* don't set color to white, just leave it unchanged

* remove unrelated code

* don't show hints if no opponents, use type effectiveness instead of move effectiveness

* fix color not going back to white when new opponent is sent

* move effectiveness to move info container

* add effectiveness overlay, partial hints only show move effectiveness, improve colors

* lint

* docs

* remove full hints, move container to right of enemy info box

* hide effectiveness while flyout is visible

* move setting to display, use default style color instead of white
2024-06-08 15:33:13 -04:00
Adrian T
5e5ece868c
[Localization][es] Add missing curly brace (#1965) 2024-06-08 15:04:50 -04:00
MadridPawmot
281f0df220
[Localization][es] Update menu.ts (#1964) 2024-06-08 14:47:01 -04:00
Lugiad
751e28d2fc
[Localization][fr] French update the menu.ts (#1955)
* Update French menu.ts

* Update French menu.ts
2024-06-08 14:38:52 -04:00
MadridPawmot
66734c396b
[Localization][es] Spanish translation (#1963)
* Translated challenges.ts to Spanish

* Added Spanish translation

* Added Spanish translation

* Translated Pokerogue exclusive items to Spanish
2024-06-08 14:35:51 -04:00
José Ricardo Fleury Oliveira
40727bdc16
[Localization] Localize "Loading asset:" text (#1961)
* localized "Loading..." texts

* fixes

* localized loading asset

* fix
2024-06-08 14:34:05 -04:00
José Ricardo Fleury Oliveira
480a2568a9
[Localization] Fixed the localization of getModeName and "Wave" text (#1953)
* localized getModeName

* wave fix
2024-06-08 11:28:45 -04:00
José Ricardo Fleury Oliveira
7cee16cee2
[Localization] Localized game-mode and save-slot-select-ui-handler (#1728)
* localized game-mode and save-slot-select-ui-handler

* Update src/locales/de/game-mode.ts

Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com>

* Update src/locales/de/save-slot-select-ui-handler.ts

Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com>

* Update French save-slot-select-ui-handler.ts

* Update French game-mode.ts

* Update French game-mode.ts

* Update Spanish game-mode.ts and save-slot-select-ui-handler.ts

* fixes

* fix 2

* Update src/locales/ko/game-mode.ts

Co-authored-by: returntoice <dieandbecome@gmail.com>

* Update src/locales/ko/save-slot-select-ui-handler.ts

Co-authored-by: returntoice <dieandbecome@gmail.com>

* fix 3

---------

Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com>
Co-authored-by: Lugiad <adrien.grivel@hotmail.fr>
Co-authored-by: GoldTra <ericpazos02@gmail.com>
Co-authored-by: returntoice <dieandbecome@gmail.com>
2024-06-08 11:03:01 -04:00
José Ricardo Fleury Oliveira
3c94d5aa83
[ptBR Localization] Added many translations (#1951)
* translations

* english parity
2024-06-08 10:53:25 -04:00
dorri-riddo
1fdfc6256f
[Localization] #1761 Korean trainer dialogue (blueberry academy) (#1950)
* [Localization] #1761 Korean trainer dialogue (blueberry academy)

* 오타 수정
2024-06-08 10:29:59 -04:00
Lee ByungHoon
a4cb75aaf0
[Bug] Fix to show current locale in setting (#1942)
* [Bug] Fix to show current locale in setting

* Add default value of lauguage option
2024-06-08 10:15:53 -04:00
Lugiad
bd5d16802a
[Localization] Added French localization for challenges (#1945)
* Update challenges.ts

* Update French challenges.ts

* Update French challenges.ts

* Update French challenges.ts

* Update French challenges.ts
2024-06-08 09:51:29 -04:00
sodam
64d36c9864
[Localization] Added Korean localization for challenges (#1946)
* traslated challenge mode script

* modified my mistake

Co-authored-by: Sangmin Lee <66083363+GINK-SS@users.noreply.github.com>

* deleted unnecessary word

---------

Co-authored-by: Sangmin Lee <66083363+GINK-SS@users.noreply.github.com>
2024-06-08 09:49:17 -04:00
Seonghyeon Cho
2d9f05030b
[Localization] Fix typo in skill name (비검천충파 -> 비검천중파) (#1937) 2024-06-08 09:47:35 -04:00
hayuna
b4cf80a984
[Bug] Override battles into single only if not fighting with trainers (#1949) 2024-06-08 09:41:56 -04:00
73 changed files with 1352 additions and 788 deletions

View File

@ -11,6 +11,7 @@
"test": "vitest run",
"test:cov": "vitest run --coverage",
"test:watch": "vitest watch --coverage",
"test:silent": "vitest run --silent",
"eslint": "eslint --fix .",
"eslint-ci": "eslint .",
"docs": "typedoc"

View File

@ -155,6 +155,13 @@ export default class BattleScene extends SceneBase {
*/
public battleStyle: integer = 0;
/**
* Defines whether or not to show type effectiveness hints
* - true: No hints
* - false: Show hints for moves
*/
public typeHints: boolean = false;
public disableMenu: boolean = false;
public gameData: GameData;
@ -1010,7 +1017,8 @@ export default class BattleScene extends SceneBase {
if (Overrides.DOUBLE_BATTLE_OVERRIDE) {
newDouble = true;
}
if (Overrides.SINGLE_BATTLE_OVERRIDE) {
/* Override battles into single only if not fighting with trainers */
if (newBattleType !== BattleType.TRAINER && Overrides.SINGLE_BATTLE_OVERRIDE) {
newDouble = false;
}

View File

@ -2949,6 +2949,7 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
/**
* Checks if enemy Pokemon is trapped by an Arena Trap-esque ability
* If the enemy is a Ghost type, it is not trapped
* If the enemy has the ability Run Away, it is not trapped.
* If the user has Magnet Pull and the enemy is not a Steel type, it is not trapped.
* If the user has Arena Trap and the enemy is not grounded, it is not trapped.
* @param pokemon The {@link Pokemon} with this {@link AbAttr}
@ -2963,6 +2964,9 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
if (otherPokemon.getTypes(true).includes(Type.GHOST) || (otherPokemon.getTypes(true).includes(Type.STELLAR) && otherPokemon.getTypes().includes(Type.GHOST))) {
trapped.value = false;
return false;
} else if (otherPokemon.hasAbility(Abilities.RUN_AWAY)) {
trapped.value = false;
return false;
}
trapped.value = true;
return true;

View File

@ -501,6 +501,52 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer):
}
}
/**
* Retrieve the color corresponding to a specific damage multiplier
* @returns A color or undefined if the default color should be used
*/
export function getTypeDamageMultiplierColor(multiplier: TypeDamageMultiplier, side: "defense" | "offense"): string | undefined {
if (side === "offense") {
switch (multiplier) {
case 0:
return "#929292";
case 0.125:
return "#FF5500";
case 0.25:
return "#FF7400";
case 0.5:
return "#FE8E00";
case 1:
return undefined;
case 2:
return "#4AA500";
case 4:
return "#4BB400";
case 8:
return "#52C200";
}
} else if (side === "defense") {
switch (multiplier) {
case 0:
return "#B1B100";
case 0.125:
return "#2DB4FF";
case 0.25:
return "#00A4FF";
case 0.5:
return "#0093FF";
case 1:
return undefined;
case 2:
return "#FE8E00";
case 4:
return "#FF7400";
case 8:
return "#FF5500";
}
}
}
export function getTypeRgb(type: Type): [ integer, integer, integer ] {
switch (type) {
case Type.NORMAL:

View File

@ -1069,6 +1069,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE);
}
/**
* @returns The type damage multiplier or undefined if it's a status move
*/
getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined {
if (move.getMove().category === MoveCategory.STATUS) {
return undefined;
}
return this.getAttackMoveEffectiveness(source, move);
}
getAttackMoveEffectiveness(source: Pokemon, pokemonMove: PokemonMove): TypeDamageMultiplier {
const move = pokemonMove.getMove();
const typeless = move.hasAttr(TypelessAttr);
@ -1588,11 +1599,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.battleInfo.updateInfo(this, instant);
}
/**
* Show or hide the type effectiveness multiplier window
* Passing undefined will hide the window
*/
updateEffectiveness(effectiveness?: string) {
this.battleInfo.updateEffectiveness(effectiveness);
}
toggleStats(visible: boolean): void {
this.battleInfo.toggleStats(visible);
}
toggleFlyout(visible: boolean): void {
this.battleInfo.flyoutMenu?.toggleFlyout(visible);
this.battleInfo.toggleFlyout(visible);
}
addExp(exp: integer) {

View File

@ -1,12 +1,13 @@
import i18next from "i18next";
import { classicFixedBattles, FixedBattleConfig, FixedBattleConfigs } from "./battle";
import BattleScene from "./battle-scene";
import { allChallenges, applyChallenges, Challenge, ChallengeType, copyChallenge } from "./data/challenge";
import { Biome } from "./data/enums/biome";
import { Species } from "./data/enums/species";
import PokemonSpecies, { allSpecies } from "./data/pokemon-species";
import { Arena } from "./field/arena";
import * as Utils from "./utils";
import * as Overrides from "./overrides";
import { allChallenges, applyChallenges, Challenge, ChallengeType, copyChallenge } from "./data/challenge";
import * as Utils from "./utils";
export enum GameModes {
CLASSIC,
@ -269,30 +270,30 @@ export class GameMode implements GameModeConfig {
getName(): string {
switch (this.modeId) {
case GameModes.CLASSIC:
return "Classic";
return i18next.t("gameMode:classic");
case GameModes.ENDLESS:
return "Endless";
return i18next.t("gameMode:endless");
case GameModes.SPLICED_ENDLESS:
return "Endless (Spliced)";
return i18next.t("gameMode:endlessSpliced");
case GameModes.DAILY:
return "Daily Run";
return i18next.t("gameMode:dailyRun");
case GameModes.CHALLENGE:
return "Challenge";
return i18next.t("gameMode:challenge");
}
}
static getModeName(modeId: GameModes): string {
switch (modeId) {
case GameModes.CLASSIC:
return "Classic";
return i18next.t("gameMode:classic");
case GameModes.ENDLESS:
return "Endless";
return i18next.t("gameMode:endless");
case GameModes.SPLICED_ENDLESS:
return "Endless (Spliced)";
return i18next.t("gameMode:endlessSpliced");
case GameModes.DAILY:
return "Daily Run";
return i18next.t("gameMode:dailyRun");
case GameModes.CHALLENGE:
return "Challenge";
return i18next.t("gameMode:challenge");
}
}
}

View File

@ -436,7 +436,7 @@ export class LoadingScene extends SceneBase {
});
this.load.on("fileprogress", file => {
assetText.setText(`Loading asset: ${file.key}`);
assetText.setText(i18next.t("menu:loadingAsset", { assetName: file.key }));
});
loadingGraphics.push(bg, graphics, progressBar, progressBox, logo, percentText, assetText);

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const deConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const deConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Klassik",
"endless": "Endlos",
"endlessSpliced": "Endlos (Fusion)",
"dailyRun": "Täglicher Run",
"unknown": "Unbekannt",
"challenge": "Challenge",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Wöchentliche Rangliste",
"noRankings": "Keine Rangliste",
"loading": "Lade…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Spieler Online",
"empty":"Leer",
"yes":"Ja",
"no":"Nein",
"disclaimer": "DISCLAIMER",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Den ausgewählten Speicherstand überschreiben?",
"loading": "Läd...",
"wave": "Welle",
"lv": "Lvl",
"empty": "Leer",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const enConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const enConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Classic",
"endless": "Endless",
"endlessSpliced": "Endless (Spliced)",
"dailyRun": "Daily Run",
"unknown": "Unknown",
"challenge": "Challenge",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Weekly Rankings",
"noRankings": "No Rankings",
"loading": "Loading…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Players Online",
"empty":"Empty",
"yes":"Yes",
"no":"No",
"disclaimer": "DISCLAIMER",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Overwrite the data in the selected slot?",
"loading": "Loading...",
"wave": "Wave",
"lv": "Lv",
"empty": "Empty",
} as const;

View File

@ -18,11 +18,11 @@ export const battle: SimpleTranslationEntries = {
"partyFull": "Tu equipo esta completo.\n¿Quieres liberar un Pokémon para meter a {{pokemonName}}?",
"pokemon": "Pokémon",
"sendOutPokemon": "¡Adelante, {{pokemonName}}!",
"hitResultCriticalHit": "!Un golpe crítico!",
"hitResultSuperEffective": "!Es supereficaz!",
"hitResultCriticalHit": "¡Un golpe crítico!",
"hitResultSuperEffective": "¡Es supereficaz!",
"hitResultNotVeryEffective": "No es muy eficaz…",
"hitResultNoEffect": "No afecta a {{pokemonName}}!",
"hitResultOneHitKO": "!KO en 1 golpe!",
"hitResultOneHitKO": "¡KO en 1 golpe!",
"attackFailed": "¡Pero ha fallado!",
"attackHitsCount": "N.º de golpes: {{count}}.",
"expGain": "{{pokemonName}} ha ganado\n{{exp}} puntos de experiencia.",
@ -56,9 +56,9 @@ export const battle: SimpleTranslationEntries = {
"skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?",
"eggHatching": "¿Y esto?",
"ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?",
"wildPokemonWithAffix": "Wild {{pokemonName}}",
"foePokemonWithAffix": "Foe {{pokemonName}}",
"useMove": "{{pokemonNameWithAffix}} used {{moveName}}!",
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
"regainHealth": "{{pokemonName}} regained\nhealth!"
"wildPokemonWithAffix": "El {{pokemonName}} salvaje",
"foePokemonWithAffix": "El {{pokemonName}} enemigo",
"useMove": "¡{{pokemonNameWithAffix}} usó {{moveName}}!",
"drainMessage": "¡{{pokemonName}} tuvo su\nenergía absorbida!",
"regainHealth": "¡{{pokemonName}} recuperó\nPS!"
} as const;

View File

@ -1,67 +1,67 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const challenges: SimpleTranslationEntries = {
"title": "Challenge Modifiers",
"points": "Bad Ideas",
"confirm_start": "Proceed with these challenges?",
"singleGeneration.name": "Mono Gen",
"singleGeneration.value.0": "Off",
"singleGeneration.desc.0": "You can only use pokemon from the chosen generation.",
"title": "Parámetros de Desafíos",
"points": "Malas Ideas",
"confirm_start": "¿Continuar con estos desafíos?",
"singleGeneration.name": "Monogeneración",
"singleGeneration.value.0": "No",
"singleGeneration.desc.0": "Solo puedes usar Pokémon de la generación elegida.",
"singleGeneration.value.1": "Gen 1",
"singleGeneration.desc.1": "You can only use pokemon from generation one.",
"singleGeneration.desc.1": "Solo puedes usar Pokémon de primera generación.",
"singleGeneration.value.2": "Gen 2",
"singleGeneration.desc.2": "You can only use pokemon from generation two.",
"singleGeneration.desc.2": "Solo puedes usar Pokémon de segunda generación.",
"singleGeneration.value.3": "Gen 3",
"singleGeneration.desc.3": "You can only use pokemon from generation three.",
"singleGeneration.desc.3": "Solo puedes usar Pokémon de tercera generación.",
"singleGeneration.value.4": "Gen 4",
"singleGeneration.desc.4": "You can only use pokemon from generation four.",
"singleGeneration.desc.4": "Solo puedes usar Pokémon de cuarta generación.",
"singleGeneration.value.5": "Gen 5",
"singleGeneration.desc.5": "You can only use pokemon from generation five.",
"singleGeneration.desc.5": "Solo puedes usar Pokémon de quinta generación.",
"singleGeneration.value.6": "Gen 6",
"singleGeneration.desc.6": "You can only use pokemon from generation six.",
"singleGeneration.desc.6": "Solo puedes usar Pokémon de sexta generación.",
"singleGeneration.value.7": "Gen 7",
"singleGeneration.desc.7": "You can only use pokemon from generation seven.",
"singleGeneration.desc.7": "Solo puedes usar Pokémon de séptima generación.",
"singleGeneration.value.8": "Gen 8",
"singleGeneration.desc.8": "You can only use pokemon from generation eight.",
"singleGeneration.desc.8": "Solo puedes usar Pokémon de octava generación.",
"singleGeneration.value.9": "Gen 9",
"singleGeneration.desc.9": "You can only use pokemon from generation nine.",
"singleType.name": "Mono Type",
"singleType.value.0": "Off",
"singleType.desc.0": "You can only use pokemon of the chosen type.",
"singleGeneration.desc.9": "Solo puedes usar Pokémon de novena generación.",
"singleType.name": "Monotipo",
"singleType.value.0": "No",
"singleType.desc.0": "Solo puedes usar Pokémon del tipo elegido",
"singleType.value.1": "Normal",
"singleType.desc.1": "You can only use pokemon with the Normal type.",
"singleType.value.2": "Fighting",
"singleType.desc.2": "You can only use pokemon with the Fighting type.",
"singleType.value.3": "Flying",
"singleType.desc.3": "You can only use pokemon with the Flying type.",
"singleType.value.4": "Poison",
"singleType.desc.4": "You can only use pokemon with the Poison type.",
"singleType.value.5": "Ground",
"singleType.desc.5": "You can only use pokemon with the Ground type.",
"singleType.value.6": "Rock",
"singleType.desc.6": "You can only use pokemon with the Rock type.",
"singleType.value.7": "Bug",
"singleType.desc.7": "You can only use pokemon with the Bug type.",
"singleType.value.8": "Ghost",
"singleType.desc.8": "You can only use pokemon with the Ghost type.",
"singleType.value.9": "Steel",
"singleType.desc.9": "You can only use pokemon with the Steel type.",
"singleType.value.10": "Fire",
"singleType.desc.10": "You can only use pokemon with the Fire type.",
"singleType.value.11": "Water",
"singleType.desc.11": "You can only use pokemon with the Water type.",
"singleType.value.12": "Grass",
"singleType.desc.12": "You can only use pokemon with the Grass type.",
"singleType.value.13": "Electric",
"singleType.desc.13": "You can only use pokemon with the Electric type.",
"singleType.value.14": "Psychic",
"singleType.desc.14": "You can only use pokemon with the Psychic type.",
"singleType.value.15": "Ice",
"singleType.desc.15": "You can only use pokemon with the Ice type.",
"singleType.value.16": "Dragon",
"singleType.desc.16": "You can only use pokemon with the Dragon type.",
"singleType.value.17": "Dark",
"singleType.desc.17": "You can only use pokemon with the Dark type.",
"singleType.value.18": "Fairy",
"singleType.desc.18": "You can only use pokemon with the Fairy type.",
"singleType.desc.1": "Solo puedes usar Pokémon de tipo Normal.",
"singleType.value.2": "Lucha",
"singleType.desc.2": "Solo puedes usar Pokémon de tipo Lucha.",
"singleType.value.3": "Volador",
"singleType.desc.3": "Solo puedes usar Pokémon de tipo Volador.",
"singleType.value.4": "Veneno",
"singleType.desc.4": "Solo puedes usar Pokémon de tipo Veneno.",
"singleType.value.5": "Tierra",
"singleType.desc.5": "Solo puedes usar Pokémon de tipo Tierra.",
"singleType.value.6": "Roca",
"singleType.desc.6": "Solo puedes usar Pokémon de tipo Roca.",
"singleType.value.7": "Bicho",
"singleType.desc.7": "Solo puedes usar Pokémon de tipo Bicho.",
"singleType.value.8": "Fantasma",
"singleType.desc.8": "Solo puedes usar Pokémon de tipo Fantasma.",
"singleType.value.9": "Acero",
"singleType.desc.9": "Solo puedes usar Pokémon de tipo Acero.",
"singleType.value.10": "Fuego",
"singleType.desc.10": "Solo puedes usar Pokémon de tipo Fuego.",
"singleType.value.11": "Agua",
"singleType.desc.11": "Solo puedes usar Pokémon de tipo Agua.",
"singleType.value.12": "Planta",
"singleType.desc.12": "Solo puedes usar Pokémon de tipo Planta.",
"singleType.value.13": "Eléctrico",
"singleType.desc.13": "Solo puedes usar Pokémon de tipo Eléctrico.",
"singleType.value.14": "Psíquico",
"singleType.desc.14": "Solo puedes usar Pokémon de tipo Psíquico.",
"singleType.value.15": "Hielo",
"singleType.desc.15": "Solo puedes usar Pokémon de tipo Hielo.",
"singleType.value.16": "Dragón",
"singleType.desc.16": "Solo puedes usar Pokémon de tipo Dragón.",
"singleType.value.17": "Siniestro",
"singleType.desc.17": "Solo puedes usar Pokémon de tipo Siniestro.",
"singleType.value.18": "Hada",
"singleType.desc.18": "Solo puedes usar Pokémon de tipo Hada.",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const esConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const esConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Clásica",
"endless": "Infinita",
"endlessSpliced": "Infinita (Fusión)",
"dailyRun": "Diaria",
"unknown": "Desconicido",
"challenge": "Desafío",
} as const;

View File

@ -45,10 +45,10 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Rankings Semanales",
"noRankings": "Sin Rankings",
"loading": "Cargando…",
"loadingAsset": "Cargando recurso: {{assetName}}",
"playersOnline": "Jugadores en Línea",
"empty":"Vacío",
"yes":"Sí",
"no":"No",
"disclaimer": "DISCLAIMER",
"disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed."
"disclaimer": "AVISO",
"disclaimerDescription": "Este juego es un producto inacabado; puede tener problemas de jugabilidad (incluyendo la posible pérdida de datos de guardado),\ncambiar sin avisar, y puede o no puede ser actualizado hasta ser completado."
} as const;

View File

@ -130,7 +130,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
},
"RARE_CANDY": { name: "Carameloraro" },
"RARER_CANDY": { name: "Rarer Candy" },
"RARER_CANDY": { name: "Caramelorarísimo" },
"MEGA_BRACELET": { name: "Mega-aro", description: "Las Megapiedras están disponibles" },
"DYNAMAX_BAND": { name: "Maximuñequera", description: "Las Maxisetas están disponibles" },
@ -162,14 +162,14 @@ export const modifierType: ModifierTypeTranslationEntries = {
"PP_UP": { name: "Más PP" },
"PP_MAX": { name: "Máx PP" },
"LURE": { name: "Lure" },
"SUPER_LURE": { name: "Super Lure" },
"MAX_LURE": { name: "Max Lure" },
"LURE": { name: "Incienso" },
"SUPER_LURE": { name: "Superincienso" },
"MAX_LURE": { name: "Incienso Máximo" },
"MEMORY_MUSHROOM": { name: "Memory Mushroom", description: "Recall one Pokémon's forgotten move" },
"MEMORY_MUSHROOM": { name: "Seta Recuerdo", description: "Recuerda un movimiento olvidado de un Pokémon." },
"EXP_SHARE": { name: "Repartir EXP", description: "Los que no combatan reciben el 20% de la EXP" },
"EXP_BALANCE": { name: "EXP. Balance", description: "Da mayor parte de la EXP recibida a los miembros del equipo que tengan menos nivel" },
"EXP_BALANCE": { name: "Equilibrar EXP", description: "Da mayor parte de la EXP recibida a los miembros del equipo que tengan menos nivel" },
"OVAL_CHARM": { name: "Amuleto Oval", description: "Cada Pokémon combatiente recibe un 10% adicional de la EXP total" },
@ -197,7 +197,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"GRIP_CLAW": { name: "Garra Garfio" },
"WIDE_LENS": { name: "Lupa" },
"MULTI_LENS": { name: "Multi Lens" },
"MULTI_LENS": { name: "Multilupa" },
"HEALING_CHARM": { name: "Amuleto curación", description: "Aumenta la efectividad de los movimientos y objetos de curacion de PS en un 10% (excepto revivir)" },
"CANDY_JAR": { name: "Candy Jar", description: "Aumenta en 1 el número de niveles añadidos por los carameloraros" },
@ -216,7 +216,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"TOXIC_ORB": { name: "Toxiesfera", description: "Extraña esfera que envenena gravemente a quien la usa en combate" },
"FLAME_ORB": { name: "Llamasfera", description: "Extraña esfera que causa quemaduras a quien la usa en combate" },
"BATON": { name: "Baton", description: "Permite pasar los efectos al cambiar de Pokémon, también evita las trampas" },
"BATON": { name: "Relevo", description: "Permite pasar los efectos al cambiar de Pokémon, también evita las trampas" },
"SHINY_CHARM": { name: "Amuleto Iris", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje sea Shiny" },
"ABILITY_CHARM": { name: "Amuleto Habilidad", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje tenga una habilidad oculta" },
@ -229,15 +229,15 @@ export const modifierType: ModifierTypeTranslationEntries = {
"GOLDEN_POKEBALL": { name: "Poké Ball Dorada", description: "Agrega 1 opción de objeto extra al final de cada combate" },
"ENEMY_DAMAGE_BOOSTER": { name: "Damage Token", description: "Aumenta el daño en un 5%" },
"ENEMY_DAMAGE_REDUCTION": { name: "Protection Token", description: "Reduce el daño recibido en un 2,5%" },
"ENEMY_HEAL": { name: "Recovery Token", description: "Cura el 2% de los PS máximo en cada turno" },
"ENEMY_ATTACK_POISON_CHANCE": { name: "Poison Token" },
"ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Paralyze Token" },
"ENEMY_ATTACK_BURN_CHANCE": { name: "Burn Token" },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Full Heal Token", description: "Agrega un 2.5% de probabilidad cada turno de curar un problema de estado" },
"ENEMY_ENDURE_CHANCE": { name: "Endure Token" },
"ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Agrega un 1% de probabilidad de que un Pokémon salvaje sea una fusión" },
"ENEMY_DAMAGE_BOOSTER": { name: "Ficha Daño", description: "Aumenta el daño en un 5%" },
"ENEMY_DAMAGE_REDUCTION": { name: "Ficha Protección", description: "Reduce el daño recibido en un 2,5%" },
"ENEMY_HEAL": { name: "Ficha Curación", description: "Cura el 2% de los PS máximo en cada turno" },
"ENEMY_ATTACK_POISON_CHANCE": { name: "Ficha Veneno" },
"ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Ficha Parálisis" },
"ENEMY_ATTACK_BURN_CHANCE": { name: "Ficha Quemadura" },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Ficha Cura Total", description: "Agrega un 2.5% de probabilidad cada turno de curar un problema de estado" },
"ENEMY_ENDURE_CHANCE": { name: "Ficha Aguante" },
"ENEMY_FUSED_CHANCE": { name: "Ficha Fusión", description: "Agrega un 1% de probabilidad de que un Pokémon salvaje sea una fusión" },
},
TempBattleStatBoosterItem: {
"x_attack": "Ataque X",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "¿Sobrescribir los datos en la ranura seleccionada?",
"loading": "Cargando...",
"wave": "Oleada",
"lv": "Nv",
"empty": "Vacío",
} as const;

View File

@ -1,67 +1,67 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const challenges: SimpleTranslationEntries = {
"title": "Challenge Modifiers",
"title": "Paramètres du Challenge",
"points": "Bad Ideas",
"confirm_start": "Proceed with these challenges?",
"singleGeneration.name": "Mono Gen",
"singleGeneration.value.0": "Off",
"singleGeneration.desc.0": "You can only use pokemon from the chosen generation.",
"singleGeneration.value.1": "Gen 1",
"singleGeneration.desc.1": "You can only use pokemon from generation one.",
"singleGeneration.value.2": "Gen 2",
"singleGeneration.desc.2": "You can only use pokemon from generation two.",
"singleGeneration.value.3": "Gen 3",
"singleGeneration.desc.3": "You can only use pokemon from generation three.",
"singleGeneration.value.4": "Gen 4",
"singleGeneration.desc.4": "You can only use pokemon from generation four.",
"singleGeneration.value.5": "Gen 5",
"singleGeneration.desc.5": "You can only use pokemon from generation five.",
"singleGeneration.value.6": "Gen 6",
"singleGeneration.desc.6": "You can only use pokemon from generation six.",
"singleGeneration.value.7": "Gen 7",
"singleGeneration.desc.7": "You can only use pokemon from generation seven.",
"singleGeneration.value.8": "Gen 8",
"singleGeneration.desc.8": "You can only use pokemon from generation eight.",
"singleGeneration.value.9": "Gen 9",
"singleGeneration.desc.9": "You can only use pokemon from generation nine.",
"singleType.name": "Mono Type",
"singleType.value.0": "Off",
"singleType.desc.0": "You can only use pokemon of the chosen type.",
"confirm_start": "Continuer avec ces paramètres ?",
"singleGeneration.name": "Mono-génération",
"singleGeneration.value.0": "Désactivé",
"singleGeneration.desc.0": "Vous ne pouvez choisir que des Pokémon de la génération sélectionnée.",
"singleGeneration.value.1": "1G",
"singleGeneration.desc.1": "Vous ne pouvez choisir que des Pokémon de 1re génération.",
"singleGeneration.value.2": "2G",
"singleGeneration.desc.2": "Vous ne pouvez choisir que des Pokémon de 2e génération.",
"singleGeneration.value.3": "3G",
"singleGeneration.desc.3": "Vous ne pouvez choisir que des Pokémon de 3e génération.",
"singleGeneration.value.4": "4G",
"singleGeneration.desc.4": "Vous ne pouvez choisir que des Pokémon de 4e génération.",
"singleGeneration.value.5": "5G",
"singleGeneration.desc.5": "Vous ne pouvez choisir que des Pokémon de 5e génération.",
"singleGeneration.value.6": "6G",
"singleGeneration.desc.6": "Vous ne pouvez choisir que des Pokémon de 6e génération.",
"singleGeneration.value.7": "7G",
"singleGeneration.desc.7": "Vous ne pouvez choisir que des Pokémon de 7e génération.",
"singleGeneration.value.8": "8G",
"singleGeneration.desc.8": "Vous ne pouvez choisir que des Pokémon de 8e génération.",
"singleGeneration.value.9": "9G",
"singleGeneration.desc.9": "Vous ne pouvez choisir que des Pokémon de 9e génération.",
"singleType.name": "Mono-type",
"singleType.value.0": "Désactivé",
"singleType.desc.0": "Vous ne pouvez choisir que des Pokémon du type sélectionné.",
"singleType.value.1": "Normal",
"singleType.desc.1": "You can only use pokemon with the Normal type.",
"singleType.value.2": "Fighting",
"singleType.desc.2": "You can only use pokemon with the Fighting type.",
"singleType.value.3": "Flying",
"singleType.desc.3": "You can only use pokemon with the Flying type.",
"singleType.desc.1": "Vous ne pouvez choisir que des Pokémon de type Normal.",
"singleType.value.2": "Combat",
"singleType.desc.2": "Vous ne pouvez choisir que des Pokémon de type Combat.",
"singleType.value.3": "Vol",
"singleType.desc.3": "Vous ne pouvez choisir que des Pokémon de type Vol.",
"singleType.value.4": "Poison",
"singleType.desc.4": "You can only use pokemon with the Poison type.",
"singleType.value.5": "Ground",
"singleType.desc.5": "You can only use pokemon with the Ground type.",
"singleType.value.6": "Rock",
"singleType.desc.6": "You can only use pokemon with the Rock type.",
"singleType.value.7": "Bug",
"singleType.desc.7": "You can only use pokemon with the Bug type.",
"singleType.value.8": "Ghost",
"singleType.desc.8": "You can only use pokemon with the Ghost type.",
"singleType.value.9": "Steel",
"singleType.desc.9": "You can only use pokemon with the Steel type.",
"singleType.value.10": "Fire",
"singleType.desc.10": "You can only use pokemon with the Fire type.",
"singleType.value.11": "Water",
"singleType.desc.11": "You can only use pokemon with the Water type.",
"singleType.value.12": "Grass",
"singleType.desc.12": "You can only use pokemon with the Grass type.",
"singleType.value.13": "Electric",
"singleType.desc.13": "You can only use pokemon with the Electric type.",
"singleType.value.14": "Psychic",
"singleType.desc.14": "You can only use pokemon with the Psychic type.",
"singleType.value.15": "Ice",
"singleType.desc.15": "You can only use pokemon with the Ice type.",
"singleType.desc.4": "Vous ne pouvez choisir que des Pokémon de type Poison.",
"singleType.value.5": "Sol",
"singleType.desc.5": "Vous ne pouvez choisir que des Pokémon de type Sol.",
"singleType.value.6": "Roche",
"singleType.desc.6": "Vous ne pouvez choisir que des Pokémon de type Roche.",
"singleType.value.7": "Insecte",
"singleType.desc.7": "Vous ne pouvez choisir que des Pokémon de type Insecte.",
"singleType.value.8": "Spectre",
"singleType.desc.8": "Vous ne pouvez choisir que des Pokémon de type Spectre.",
"singleType.value.9": "Acier",
"singleType.desc.9": "Vous ne pouvez choisir que des Pokémon de type Acier.",
"singleType.value.10": "Feu",
"singleType.desc.10": "Vous ne pouvez choisir que des Pokémon de type Feu.",
"singleType.value.11": "Eau",
"singleType.desc.11": "Vous ne pouvez choisir que des Pokémon de type Eau.",
"singleType.value.12": "Plante",
"singleType.desc.12": "Vous ne pouvez choisir que des Pokémon de type Plante.",
"singleType.value.13": "Électrik",
"singleType.desc.13": "Vous ne pouvez choisir que des Pokémon de type Électrik.",
"singleType.value.14": "Psy",
"singleType.desc.14": "Vous ne pouvez choisir que des Pokémon de type Psy.",
"singleType.value.15": "Glace",
"singleType.desc.15": "Vous ne pouvez choisir que des Pokémon de type Glace.",
"singleType.value.16": "Dragon",
"singleType.desc.16": "You can only use pokemon with the Dragon type.",
"singleType.value.17": "Dark",
"singleType.desc.17": "You can only use pokemon with the Dark type.",
"singleType.value.18": "Fairy",
"singleType.desc.18": "You can only use pokemon with the Fairy type.",
"singleType.desc.16": "Vous ne pouvez choisir que des Pokémon de type Dragon.",
"singleType.value.17": "Ténèbres",
"singleType.desc.17": "Vous ne pouvez choisir que des Pokémon de type Ténèbres.",
"singleType.value.18": "Fée",
"singleType.desc.18": "Vous ne pouvez choisir que des Pokémon de type Fée.",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const frConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const frConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Classique",
"endless": "Infini",
"endlessSpliced": "Infini (Fusions)",
"dailyRun": "Défi du jour",
"unknown": "Inconnu",
"challenge": "Challenge",
} as const;

View File

@ -40,10 +40,10 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Classement de la Semaine",
"noRankings": "Pas de Classement",
"loading": "Chargement…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Joueurs Connectés",
"empty":"Vide",
"yes":"Oui",
"no":"Non",
"disclaimer": "DISCLAIMER",
"disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed."
"disclaimer": "AVERTISSEMENT",
"disclaimerDescription": "Ce jeu nest pas un produit fini et peut contenir des problèmes de jouabilité, dont de possibles pertes de sauvegardes,\ndes modifications sans avertissement et pourrait ou non encore être mis à jour ou terminé."
} as const;

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Effacer les données de lemplacement sélectionné ?",
"loading": "Chargement…",
"wave": "Vague",
"lv": "N.",
"empty": "Vide",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const itConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const itConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Classic",
"endless": "Endless",
"endlessSpliced": "Endless (Spliced)",
"dailyRun": "Daily Run",
"unknown": "Unknown",
"challenge": "Challenge",
} as const;

View File

@ -40,13 +40,13 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Classifica Settimanale",
"noRankings": "Nessuna Classifica",
"loading": "Caricamento…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Giocatori Online",
"evolving": "Cosa?\n{{pokemonName}} si evolvendo!",
"stoppedEvolving": "{{pokemonName}} ha smesso di evolversi.",
"pauseEvolutionsQuestion": "Vuoi sospendere le evoluzioni per {{pokemonName}}?\nLe evoluzioni possono essere riattivate dalla schermata del party.",
"evolutionsPaused": "Le evoluzioni sono state sospese per {{pokemonName}}.",
"evolutionDone": "Congratulazioni!\n{{pokemonName}} si è evoluto in {{evolvedPokemonName}}!",
"empty":"Vuoto",
"yes":"Si",
"no":"No",
"disclaimer": "DISCLAIMER",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Overwrite the data in the selected slot?",
"loading": "Loading...",
"wave": "Wave",
"lv": "Lv",
"empty": "Vuoto",
} as const;

View File

@ -1,67 +1,67 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const challenges: SimpleTranslationEntries = {
"title": "Challenge Modifiers",
"title": "챌린지 조건 설정",
"points": "Bad Ideas",
"confirm_start": "Proceed with these challenges?",
"singleGeneration.name": "Mono Gen",
"singleGeneration.value.0": "Off",
"singleGeneration.desc.0": "You can only use pokemon from the chosen generation.",
"singleGeneration.value.1": "Gen 1",
"singleGeneration.desc.1": "You can only use pokemon from generation one.",
"singleGeneration.value.2": "Gen 2",
"singleGeneration.desc.2": "You can only use pokemon from generation two.",
"singleGeneration.value.3": "Gen 3",
"singleGeneration.desc.3": "You can only use pokemon from generation three.",
"singleGeneration.value.4": "Gen 4",
"singleGeneration.desc.4": "You can only use pokemon from generation four.",
"singleGeneration.value.5": "Gen 5",
"singleGeneration.desc.5": "You can only use pokemon from generation five.",
"singleGeneration.value.6": "Gen 6",
"singleGeneration.desc.6": "You can only use pokemon from generation six.",
"singleGeneration.value.7": "Gen 7",
"singleGeneration.desc.7": "You can only use pokemon from generation seven.",
"singleGeneration.value.8": "Gen 8",
"singleGeneration.desc.8": "You can only use pokemon from generation eight.",
"singleGeneration.value.9": "Gen 9",
"singleGeneration.desc.9": "You can only use pokemon from generation nine.",
"singleType.name": "Mono Type",
"singleType.value.0": "Off",
"singleType.desc.0": "You can only use pokemon of the chosen type.",
"singleType.value.1": "Normal",
"singleType.desc.1": "You can only use pokemon with the Normal type.",
"singleType.value.2": "Fighting",
"singleType.desc.2": "You can only use pokemon with the Fighting type.",
"singleType.value.3": "Flying",
"singleType.desc.3": "You can only use pokemon with the Flying type.",
"singleType.value.4": "Poison",
"singleType.desc.4": "You can only use pokemon with the Poison type.",
"singleType.value.5": "Ground",
"singleType.desc.5": "You can only use pokemon with the Ground type.",
"singleType.value.6": "Rock",
"singleType.desc.6": "You can only use pokemon with the Rock type.",
"singleType.value.7": "Bug",
"singleType.desc.7": "You can only use pokemon with the Bug type.",
"singleType.value.8": "Ghost",
"singleType.desc.8": "You can only use pokemon with the Ghost type.",
"singleType.value.9": "Steel",
"singleType.desc.9": "You can only use pokemon with the Steel type.",
"singleType.value.10": "Fire",
"singleType.desc.10": "You can only use pokemon with the Fire type.",
"singleType.value.11": "Water",
"singleType.desc.11": "You can only use pokemon with the Water type.",
"singleType.value.12": "Grass",
"singleType.desc.12": "You can only use pokemon with the Grass type.",
"singleType.value.13": "Electric",
"singleType.desc.13": "You can only use pokemon with the Electric type.",
"singleType.value.14": "Psychic",
"singleType.desc.14": "You can only use pokemon with the Psychic type.",
"singleType.value.15": "Ice",
"singleType.desc.15": "You can only use pokemon with the Ice type.",
"singleType.value.16": "Dragon",
"singleType.desc.16": "You can only use pokemon with the Dragon type.",
"singleType.value.17": "Dark",
"singleType.desc.17": "You can only use pokemon with the Dark type.",
"singleType.value.18": "Fairy",
"singleType.desc.18": "You can only use pokemon with the Fairy type.",
"confirm_start": "이 조건으로 챌린지를 진행하시겠습니까?",
"singleGeneration.name": "단일 세대",
"singleGeneration.value.0": "설정 안함",
"singleGeneration.desc.0": "선택한 세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.1": "1세대",
"singleGeneration.desc.1": "1세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.2": "2세대",
"singleGeneration.desc.2": "2세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.3": "3세대",
"singleGeneration.desc.3": "3세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.4": "4세대",
"singleGeneration.desc.4": "4세대의 포켓몬만 사용할 수 있습니다r",
"singleGeneration.value.5": "5세대",
"singleGeneration.desc.5": "5세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.6": "6세대",
"singleGeneration.desc.6": "6세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.7": "7세대",
"singleGeneration.desc.7": "7세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.8": "8세대",
"singleGeneration.desc.8": "8세대의 포켓몬만 사용할 수 있습니다.",
"singleGeneration.value.9": "9세대",
"singleGeneration.desc.9": "9세대의 포켓몬만 사용할 수 있습니다.",
"singleType.name": "단일 타입",
"singleType.value.0": "설정 안함",
"singleType.desc.0": "선택한 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.1": "노말",
"singleType.desc.1": "노말 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.2": "격투",
"singleType.desc.2": "격투 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.3": "비행",
"singleType.desc.3": "비행 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.4": "",
"singleType.desc.4": "독 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.5": "",
"singleType.desc.5": "땅 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.6": "바위 ",
"singleType.desc.6": "바위 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.7": "벌레",
"singleType.desc.7": "벌레 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.8": "고스트",
"singleType.desc.8": "고스트 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.9": "강철",
"singleType.desc.9": "강철 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.10": "불꽃",
"singleType.desc.10": "불꽃 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.11": "",
"singleType.desc.11": "물 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.12": "",
"singleType.desc.12": "풀 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.13": "전기",
"singleType.desc.13": "전기 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.14": "에스퍼",
"singleType.desc.14": "에스퍼 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.15": "얼음",
"singleType.desc.15": "얼음 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.16": "드래곤",
"singleType.desc.16": "드래곤 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.17": "",
"singleType.desc.17": "악 타입의 포켓몬만 사용할 수 있습니다.",
"singleType.value.18": "페어리",
"singleType.desc.18": "페어리 타입의 포켓몬만 사용할 수 있습니다.",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const koConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const koConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -906,51 +906,51 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"crispin": {
"encounter": {
1: "I wanna win, so that's exactly what I'll do!",
2: "I battle because I wanna battle! And you know what? That's how it should be!"
1: "이기고 싶으니까 이기고 말겠어!",
2: "싸우고 싶으면 싸운다! 이거면 충분하지 않아!?"
},
"victory": {
1: "I wanted to win…but I lost!",
2: "I lost…'cause I couldn't win!"
1: "이기고 싶었는데…졌잖아!",
2: "이기지 못해서…지고 말았어!"
},
"defeat": {
1: "Hey, wait a sec. Did I just win? I think I just won! Talk about satisfying!",
2: "Wooo! That was amazing!"
1: "잠시만. 나 지금 이긴거지? 이긴 거 맞지! 기분 좋은데!",
2: "우와아! 이거 굉장한데!"
}
},
"amarys": {
"encounter": {
1: `I want to be the one to help a certain person. That being the case, I cannot afford to lose.
$ Our battle starts now.`,
1: `네리네는 그 사람을 구원하고 싶습니다. 그렇기에 패배는 용납되지 않습니다.
$ .`,
},
"victory": {
1: "I am… not enough, I see."
1: "네리네는… 안 된다는 건가요."
},
"defeat": {
1: "Victory belongs to me. Well fought."
1: "네리네가 승리했습니다. 수고하셨습니다."
}
},
"lacey": {
"encounter": {
1: "I'll be facing you with my usual party as a member of the Elite Four."
1: "이번에는 사천왕으로서 승부하는 거니까 평소 사용하는 아이들로 상대해 드릴게요!"
},
"victory": {
1: "That was a great battle!"
1: "멋진 포켓몬 배틀이었어요!"
},
"defeat": {
1: "Let's give your Pokémon a nice round of applause for their efforts!"
1: "당신의 포켓몬의 노력에 박수를 보내주세요!"
}
},
"drayton": {
"encounter": {
1: `Man, I love chairs. Don't you love chairs? What lifesavers.
$I don't get why everyone doesn't just sit all the time. Standing up's tiring work!`,
1: `의자는 좋은 거야. 너도 그렇게 생각해? 정말 고마운 물건이지.
$ . !`,
},
"victory": {
1: "Guess I should've expected that!"
1: "전보다 더 강해질 줄이야!"
},
"defeat": {
1: "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?"
1: "헤헤헷! 내 승리야. 분한 건 알겠지만 카지처럼 나가떨어지지마, 응?"
}
},
"ramos": {

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "클래식",
"endless": "엔들리스",
"endlessSpliced": "엔들리스(융합체)",
"dailyRun": "데일리 런",
"unknown": "언노운",
"challenge": "챌린지",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "주간 랭킹",
"noRankings": "랭킹 정보 없음",
"loading": "로딩 중…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "플레이어 온라인",
"empty":"빈 슬롯",
"yes":"예",
"no":"아니오",
"disclaimer": "면책 조항",

View File

@ -3393,7 +3393,7 @@ export const move: MoveTranslationEntries = {
effect: "무수히 많은 불덩이로 공격한다. 화상 상태로 만들 때가 있다. 상대가 상태 이상인 경우 위력이 2배가 된다."
},
ceaselessEdge: {
name: "비검천파",
name: "비검천파",
effect: "조개껍질 검으로 공격한다. 조개껍질 파편은 압정이 되어 상대의 발밑에 흩어진다."
},
bleakwindStorm: {

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "선택한 슬롯에 데이터를 덮어쓰시겠습니까?",
"loading": "로딩 중...",
"wave": "웨이브",
"lv": "Lv",
"empty": "빈 슬롯",
} as const;

View File

@ -5,7 +5,7 @@ export const battle: SimpleTranslationEntries = {
"trainerAppeared": "{{trainerName}}\nquer batalhar!",
"trainerAppearedDouble": "{{trainerName}}\nquerem batalhar!",
"singleWildAppeared": "Um {{pokemonName}} selvagem apareceu!",
"trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!",
"trainerSendOut": "{{trainerName}} escolheu\n{{pokemonName}}!",
"multiWildAppeared": "Um {{pokemonName1}} e um {{pokemonName2}} selvagens\napareceram!",
"playerComeBack": "{{pokemonName}}, retorne!",
"trainerComeBack": "{{trainerName}} retirou {{pokemonName}} da batalha!",
@ -13,9 +13,9 @@ export const battle: SimpleTranslationEntries = {
"trainerGo": "{{trainerName}} escolheu {{pokemonName}}!",
"switchQuestion": "Quer trocar\nde {{pokemonName}}?",
"trainerDefeated": "Você derrotou\n{{trainerName}}!",
"moneyWon": "You got\n₽{{moneyAmount}} for winning!",
"moneyWon": "Você ganhou\n₽{{moneyAmount}} por ganhar!",
"pokemonCaught": "{{pokemonName}} foi capturado!",
"partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?",
"partyFull": "Sua equipe está cheia.\nSolte um Pokémon para ter espaço para {{pokemonName}}?",
"pokemon": "Pokémon",
"sendOutPokemon": "{{pokemonName}}, eu escolho você!!",
"hitResultCriticalHit": "Um golpe crítico!",

View File

@ -1,67 +1,67 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const challenges: SimpleTranslationEntries = {
"title": "Challenge Modifiers",
"points": "Bad Ideas",
"confirm_start": "Proceed with these challenges?",
"singleGeneration.name": "Mono Gen",
"singleGeneration.value.0": "Off",
"singleGeneration.desc.0": "You can only use pokemon from the chosen generation.",
"singleGeneration.value.1": "Gen 1",
"singleGeneration.desc.1": "You can only use pokemon from generation one.",
"singleGeneration.value.2": "Gen 2",
"singleGeneration.desc.2": "You can only use pokemon from generation two.",
"singleGeneration.value.3": "Gen 3",
"singleGeneration.desc.3": "You can only use pokemon from generation three.",
"singleGeneration.value.4": "Gen 4",
"singleGeneration.desc.4": "You can only use pokemon from generation four.",
"singleGeneration.value.5": "Gen 5",
"singleGeneration.desc.5": "You can only use pokemon from generation five.",
"singleGeneration.value.6": "Gen 6",
"singleGeneration.desc.6": "You can only use pokemon from generation six.",
"singleGeneration.value.7": "Gen 7",
"singleGeneration.desc.7": "You can only use pokemon from generation seven.",
"singleGeneration.value.8": "Gen 8",
"singleGeneration.desc.8": "You can only use pokemon from generation eight.",
"singleGeneration.value.9": "Gen 9",
"singleGeneration.desc.9": "You can only use pokemon from generation nine.",
"singleType.name": "Mono Type",
"singleType.value.0": "Off",
"singleType.desc.0": "You can only use pokemon of the chosen type.",
"title": "Desafios",
"start": "Iniciar",
"illegalEvolution": "{{pokemon}} não pode ser escolhido\nnesse desafio!",
"singleGeneration.name": "Geração Única",
"singleGeneration.value.0": "Desligado",
"singleGeneration.desc.0": "Você só pode user Pokémon de uma única geração.",
"singleGeneration.value.1": "Geração 1",
"singleGeneration.desc.1": "Você só pode user Pokémon da primeira geração.",
"singleGeneration.value.2": "Geração 2",
"singleGeneration.desc.2": "Você só pode user Pokémon da segunda geração.",
"singleGeneration.value.3": "Geração 3",
"singleGeneration.desc.3": "Você só pode user Pokémon da terceira geração.",
"singleGeneration.value.4": "Geração 4",
"singleGeneration.desc.4": "Você só pode user Pokémon da quarta geração.",
"singleGeneration.value.5": "Geração 5",
"singleGeneration.desc.5": "Você só pode user Pokémon da quinta geração.",
"singleGeneration.value.6": "Geração 6",
"singleGeneration.desc.6": "Você só pode user Pokémon da sexta geração.",
"singleGeneration.value.7": "Geração 7",
"singleGeneration.desc.7": "Você só pode user Pokémon da sétima geração.",
"singleGeneration.value.8": "Geração 8",
"singleGeneration.desc.8": "Você só pode user Pokémon da oitava geração.",
"singleGeneration.value.9": "Geração 9",
"singleGeneration.desc.9": "Você só pode user Pokémon da nona geração.",
"singleType.name": "Tipo Único",
"singleType.value.0": "Desligado",
"singleType.desc.0": "Você só pode user Pokémon de um único tipo.",
"singleType.value.1": "Normal",
"singleType.desc.1": "You can only use pokemon with the Normal type.",
"singleType.value.2": "Fighting",
"singleType.desc.2": "You can only use pokemon with the Fighting type.",
"singleType.value.3": "Flying",
"singleType.desc.3": "You can only use pokemon with the Flying type.",
"singleType.value.4": "Poison",
"singleType.desc.4": "You can only use pokemon with the Poison type.",
"singleType.value.5": "Ground",
"singleType.desc.5": "You can only use pokemon with the Ground type.",
"singleType.value.6": "Rock",
"singleType.desc.6": "You can only use pokemon with the Rock type.",
"singleType.value.7": "Bug",
"singleType.desc.7": "You can only use pokemon with the Bug type.",
"singleType.value.8": "Ghost",
"singleType.desc.8": "You can only use pokemon with the Ghost type.",
"singleType.value.9": "Steel",
"singleType.desc.9": "You can only use pokemon with the Steel type.",
"singleType.value.10": "Fire",
"singleType.desc.10": "You can only use pokemon with the Fire type.",
"singleType.value.11": "Water",
"singleType.desc.11": "You can only use pokemon with the Water type.",
"singleType.value.12": "Grass",
"singleType.desc.12": "You can only use pokemon with the Grass type.",
"singleType.value.13": "Electric",
"singleType.desc.13": "You can only use pokemon with the Electric type.",
"singleType.value.14": "Psychic",
"singleType.desc.14": "You can only use pokemon with the Psychic type.",
"singleType.value.15": "Ice",
"singleType.desc.15": "You can only use pokemon with the Ice type.",
"singleType.value.16": "Dragon",
"singleType.desc.16": "You can only use pokemon with the Dragon type.",
"singleType.value.17": "Dark",
"singleType.desc.17": "You can only use pokemon with the Dark type.",
"singleType.value.18": "Fairy",
"singleType.desc.18": "You can only use pokemon with the Fairy type.",
"singleType.desc.1": "Você só pode user Pokémon do tipo Normal.",
"singleType.value.2": "Lutador",
"singleType.desc.2": "Você só pode user Pokémon do tipo Lutador.",
"singleType.value.3": "Voador",
"singleType.desc.3": "Você só pode user Pokémon do tipo Voador.",
"singleType.value.4": "Veneno",
"singleType.desc.4": "Você só pode user Pokémon do tipo Veneno.",
"singleType.value.5": "Terra",
"singleType.desc.5": "Você só pode user Pokémon do tipo Terra.",
"singleType.value.6": "Pedra",
"singleType.desc.6": "Você só pode user Pokémon do tipo Pedra.",
"singleType.value.7": "Inseto",
"singleType.desc.7": "Você só pode user Pokémon do tipo Inseto.",
"singleType.value.8": "Fantasma",
"singleType.desc.8": "Você só pode user Pokémon do tipo Fantasma.",
"singleType.value.9": "Aço",
"singleType.desc.9": "Você só pode user Pokémon do tipo Aço.",
"singleType.value.10": "Fogo",
"singleType.desc.10": "Você só pode user Pokémon do tipo Fogo.",
"singleType.value.11": "Água",
"singleType.desc.11": "Você só pode user Pokémon do tipo Água.",
"singleType.value.12": "Grama",
"singleType.desc.12": "Você só pode user Pokémon do tipo Grama.",
"singleType.value.13": "Elétrico",
"singleType.desc.13": "Você só pode user Pokémon do tipo Elétrico.",
"singleType.value.14": "Psíquico",
"singleType.desc.14": "Você só pode user Pokémon do tipo Psíquico.",
"singleType.value.15": "Gelo",
"singleType.desc.15": "Você só pode user Pokémon do tipo Gelo.",
"singleType.value.16": "Dragão",
"singleType.desc.16": "Você só pode user Pokémon do tipo Dragão.",
"singleType.value.17": "Sombrio",
"singleType.desc.17": "Você só pode user Pokémon do tipo Sombrio.",
"singleType.value.18": "Fada",
"singleType.desc.18": "Você só pode user Pokémon do tipo Fada.",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -26,17 +27,18 @@ import { menuUiHandler } from "./menu-ui-handler";
import { modifierType } from "./modifier-type";
import { move } from "./move";
import { nature } from "./nature";
import { partyUiHandler } from "./party-ui-handler";
import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
export const ptBrConfig = {
ability: ability,
@ -58,6 +60,7 @@ export const ptBrConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -65,10 +68,12 @@ export const ptBrConfig = {
modifierType: modifierType,
move: move,
nature: nature,
partyUiHandler: partyUiHandler,
pokeball: pokeball,
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,
@ -77,5 +82,4 @@ export const ptBrConfig = {
tutorial: tutorial,
voucher: voucher,
weather: weather,
partyUiHandler: partyUiHandler
};

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Clássico",
"endless": "Infinito",
"endlessSpliced": "Infinito (Fusões)",
"dailyRun": "Desafio Diário",
"unknown": "Desconhecido",
"challenge": "Desafio",
} as const;

View File

@ -1,10 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const growth: SimpleTranslationEntries = {
"Erratic": "Instável",
"Erratic": "Muito Rápido",
"Fast": "Rápido",
"Medium_Fast": "Meio Rápido",
"Medium_Slow": "Meio Lento",
"Slow": "Lento",
"Fluctuating": "Flutuante"
"Fluctuating": "Muito Lento",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Classificação Semanal",
"noRankings": "Sem Classificação",
"loading": "Carregando…",
"loadingAsset": "Carregando recurso: {{assetName}}",
"playersOnline": "Jogadores Ativos",
"empty": "Vazio",
"yes": "Sim",
"no": "Não",
"disclaimer": "AVISO",

View File

@ -1,10 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const partyUiHandler: SimpleTranslationEntries = {
"SEND_OUT": "Send Out",
"SUMMARY": "Summary",
"CANCEL": "Cancel",
"RELEASE": "Release",
"APPLY": "Apply",
"TEACH": "Teach"
"SEND_OUT": "Trocar",
"SUMMARY": "Sumário",
"CANCEL": "Cancelar",
"RELEASE": "Soltar",
"APPLY": "Aplicar",
"TEACH": "Ensinar",
} as const;

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Substituir os dados desse slot?",
"loading": "Carregando...",
"wave": "Onda",
"lv": "Nv",
"empty": "Vazio",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const zhCnConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const zhCnConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Classic",
"endless": "Endless",
"endlessSpliced": "Endless (Spliced)",
"dailyRun": "Daily Run",
"unknown": "Unknown",
"challenge": "Challenge",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "每周排名",
"noRankings": "无排名",
"loading": "加载中...",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "在线玩家",
"empty": "空",
"yes": "是",
"no": "否",
"disclaimer": "DISCLAIMER",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Overwrite the data in the selected slot?",
"loading": "Loading...",
"wave": "Wave",
"lv": "Lv",
"empty": "空",
} as const;

View File

@ -19,6 +19,7 @@ import {
} from "./dialogue";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { gameMode } from "./game-mode";
import { gameStatsUiHandler } from "./game-stats-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -30,6 +31,7 @@ import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
import { pokemonInfoContainer } from "./pokemon-info-container";
import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler";
import { splashMessages } from "./splash-messages";
import { starterSelectUiHandler } from "./starter-select-ui-handler";
import { titles, trainerClasses, trainerNames } from "./trainers";
@ -58,6 +60,7 @@ export const zhTwConfig = {
PGFdoubleBattleDialogue: PGFdoubleBattleDialogue,
egg: egg,
fightUiHandler: fightUiHandler,
gameMode: gameMode,
gameStatsUiHandler: gameStatsUiHandler,
growth: growth,
menu: menu,
@ -69,6 +72,7 @@ export const zhTwConfig = {
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
titles: titles,

View File

@ -0,0 +1,10 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const gameMode: SimpleTranslationEntries = {
"classic": "Classic",
"endless": "Endless",
"endlessSpliced": "Endless (Spliced)",
"dailyRun": "Daily Run",
"unknown": "Unknown",
"challenge": "Challenge",
} as const;

View File

@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "每週排名",
"noRankings": "無排名",
"loading": "加載中…",
"loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "在線玩家",
"empty":"空",
"yes":"是",
"no":"否",
"disclaimer": "DISCLAIMER",

View File

@ -0,0 +1,9 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Overwrite the data in the selected slot?",
"loading": "Loading...",
"wave": "Wave",
"lv": "Lv",
"empty": "空",
} as const;

View File

@ -196,36 +196,15 @@ declare module "i18next" {
interface CustomTypeOptions {
defaultNS: "menu"; // Even if we don't use it, i18next requires a valid default namespace
resources: {
menu: SimpleTranslationEntries;
menuUiHandler: SimpleTranslationEntries;
move: MoveTranslationEntries;
battle: SimpleTranslationEntries;
abilityTriggers: SimpleTranslationEntries;
ability: AbilityTranslationEntries;
pokeball: SimpleTranslationEntries;
pokemon: SimpleTranslationEntries;
pokemonInfo: PokemonInfoTranslationEntries;
commandUiHandler: SimpleTranslationEntries;
fightUiHandler: SimpleTranslationEntries;
titles: SimpleTranslationEntries;
trainerClasses: SimpleTranslationEntries;
trainerNames: SimpleTranslationEntries;
tutorial: SimpleTranslationEntries;
starterSelectUiHandler: SimpleTranslationEntries;
splashMessages: SimpleTranslationEntries;
nature: SimpleTranslationEntries;
growth: SimpleTranslationEntries;
egg: SimpleTranslationEntries;
weather: SimpleTranslationEntries;
modifierType: ModifierTypeTranslationEntries;
abilityTriggers: SimpleTranslationEntries;
achv: AchievementTranslationEntries;
battle: SimpleTranslationEntries;
battleMessageUiHandler: SimpleTranslationEntries;
berry: BerryTranslationEntries;
achv: AchievementTranslationEntries;
gameStatsUiHandler: SimpleTranslationEntries;
challenges: SimpleTranslationEntries;
voucher: SimpleTranslationEntries;
biome: SimpleTranslationEntries;
pokemonInfoContainer: SimpleTranslationEntries;
challenges: SimpleTranslationEntries;
commandUiHandler: SimpleTranslationEntries;
PGMdialogue: DialogueTranslationEntries;
PGMbattleSpecDialogue: SimpleTranslationEntries;
PGMmiscDialogue: SimpleTranslationEntries;
@ -234,7 +213,30 @@ declare module "i18next" {
PGFbattleSpecDialogue: SimpleTranslationEntries;
PGFmiscDialogue: SimpleTranslationEntries;
PGFdoubleBattleDialogue: DialogueTranslationEntries;
egg: SimpleTranslationEntries;
fightUiHandler: SimpleTranslationEntries;
gameMode: SimpleTranslationEntries;
gameStatsUiHandler: SimpleTranslationEntries;
growth: SimpleTranslationEntries;
menu: SimpleTranslationEntries;
menuUiHandler: SimpleTranslationEntries;
modifierType: ModifierTypeTranslationEntries;
move: MoveTranslationEntries;
nature: SimpleTranslationEntries;
partyUiHandler: SimpleTranslationEntries;
pokeball: SimpleTranslationEntries;
pokemon: SimpleTranslationEntries;
pokemonInfo: PokemonInfoTranslationEntries;
pokemonInfoContainer: SimpleTranslationEntries;
saveSlotSelectUiHandler: SimpleTranslationEntries;
splashMessages: SimpleTranslationEntries;
starterSelectUiHandler: SimpleTranslationEntries;
titles: SimpleTranslationEntries;
trainerClasses: SimpleTranslationEntries;
trainerNames: SimpleTranslationEntries;
tutorial: SimpleTranslationEntries;
voucher: SimpleTranslationEntries;
weather: SimpleTranslationEntries;
};
}
}

View File

@ -64,6 +64,7 @@ export const SettingKeys = {
Sprite_Set: "SPRITE_SET",
Fusion_Palette_Swaps: "FUSION_PALETTE_SWAPS",
Player_Gender: "PLAYER_GENDER",
Type_Hints: "TYPE_HINTS",
Master_Volume: "MASTER_VOLUME",
BGM_Volume: "BGM_VOLUME",
SE_Volume: "SE_VOLUME",
@ -268,6 +269,13 @@ export const Setting: Array<Setting> = [
default: 0,
type: SettingType.DISPLAY
},
{
key: SettingKeys.Type_Hints,
label: "Type hints",
options: OFF_ON,
default: 0,
type: SettingType.DISPLAY
},
{
key: SettingKeys.Master_Volume,
label: "Master Volume",
@ -447,6 +455,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
case SettingKeys.Vibration:
scene.enableVibration = Setting[index].options[value] !== "Disabled" && hasTouchscreen();
break;
case SettingKeys.Type_Hints:
scene.typeHints = Setting[index].options[value] === "On";
break;
case SettingKeys.Language:
if (value) {
if (scene.ui) {

View File

@ -44,8 +44,8 @@ describe("Abilities - Intrepid Sword", () => {
expect(game.scene.getParty()[0].summonData).not.toBeUndefined();
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(0);
await game.phaseInterceptor.mustRun(ShowAbilityPhase).catch((error) => expect(error).toBe(ShowAbilityPhase));
await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase));
await game.phaseInterceptor.run(ShowAbilityPhase);
await game.phaseInterceptor.run(StatChangePhase);
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(1);
}, 20000);
@ -57,8 +57,8 @@ describe("Abilities - Intrepid Sword", () => {
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(0);
await game.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase);
await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase));
await game.phaseInterceptor.whenAboutToRun(MessagePhase);
await game.phaseInterceptor.run(StatChangePhase);
await game.phaseInterceptor.run(MessagePhase);
battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(1);
}, 20000);

View File

@ -5,7 +5,7 @@ import * as overrides from "#app/overrides";
import {Abilities} from "#app/data/enums/abilities";
import {Species} from "#app/data/enums/species";
import {
CommandPhase, EnemyCommandPhase,
CommandPhase, EnemyCommandPhase, SelectTargetPhase,
TurnStartPhase
} from "#app/phases";
import {Mode} from "#app/ui/ui";
@ -55,7 +55,6 @@ describe("Battle order", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
const order = phase.getOrder();
expect(order[0]).toBe(2);
@ -77,7 +76,6 @@ describe("Battle order", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
const order = phase.getOrder();
expect(order[0]).toBe(0);
@ -118,9 +116,7 @@ describe("Battle order", () => {
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
const order = phase.getOrder();
expect(order.indexOf(0)).toBeGreaterThan(order.indexOf(2));
@ -163,9 +159,7 @@ describe("Battle order", () => {
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
const order = phase.getOrder();
expect(order.indexOf(3)).toBeLessThan(order.indexOf(0));
@ -207,9 +201,7 @@ describe("Battle order", () => {
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
const order = phase.getOrder();
expect(order.indexOf(1)).toBeLessThan(order.indexOf(0));

View File

@ -1,34 +1,21 @@
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
import {generateStarter, getMovePosition, waitUntil,} from "#app/test/utils/gameManagerUtils";
import {generateStarter, getMovePosition,} from "#app/test/utils/gameManagerUtils";
import {Mode} from "#app/ui/ui";
import {GameModes} from "#app/game-mode";
import {Species} from "#app/data/enums/species";
import * as overrides from "../../overrides";
import {Command} from "#app/ui/command-ui-handler";
import {
BattleEndPhase,
BerryPhase,
CommandPhase,
DamagePhase,
EggLapsePhase,
EncounterPhase,
EnemyCommandPhase,
FaintPhase,
LoginPhase,
MessagePhase,
MoveEffectPhase,
MoveEndPhase,
MovePhase,
PostSummonPhase,
SelectGenderPhase,
SelectModifierPhase,
SelectStarterPhase,
StatChangePhase,
SummonPhase,
TitlePhase,
TurnEndPhase,
TurnInitPhase,
TurnStartPhase,
VictoryPhase,
} from "#app/phases";
import {Moves} from "#app/data/enums/moves";
import GameManager from "#app/test/utils/gameManager";
@ -36,6 +23,7 @@ import Phaser from "phaser";
import {allSpecies} from "#app/data/pokemon-species";
import {PlayerGender} from "#app/data/enums/player-gender";
import { getGameMode } from "#app/game-mode.js";
import {Abilities} from "#app/data/enums/abilities";
describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game;
@ -55,22 +43,6 @@ describe("Test Battle Phase", () => {
game = new GameManager(phaserGame);
});
it("test phase interceptor with remove", async() => {
await game.phaseInterceptor.run(LoginPhase);
await game.phaseInterceptor.run(LoginPhase, () => {
return game.phaseInterceptor.log.includes("LoginPhase");
});
game.scene.gameData.gender = PlayerGender.MALE;
await game.phaseInterceptor.remove(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase));
await game.phaseInterceptor.run(TitlePhase);
await waitUntil(() => game.scene.ui?.getMode() === Mode.TITLE);
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
}, 100000);
it("test phase interceptor with prompt", async() => {
await game.phaseInterceptor.run(LoginPhase);
@ -87,7 +59,7 @@ describe("Test Battle Phase", () => {
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
expect(game.scene.gameData.gender).toBe(PlayerGender.MALE);
}, 100000);
}, 20000);
it("test phase interceptor with prompt with preparation for a future prompt", async() => {
await game.phaseInterceptor.run(LoginPhase);
@ -109,13 +81,13 @@ describe("Test Battle Phase", () => {
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
expect(game.scene.gameData.gender).toBe(PlayerGender.MALE);
}, 100000);
}, 20000);
it("newGame one-liner", async() => {
await game.startBattle();
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 100000);
}, 20000);
it("do attack wave 3 - single battle - regular - OHKO", async() => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
@ -123,6 +95,8 @@ describe("Test Battle Phase", () => {
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
await game.startBattle();
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
@ -132,28 +106,10 @@ describe("Test Battle Phase", () => {
const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.run(TurnStartPhase);
await game.phaseInterceptor.run(MovePhase);
await game.phaseInterceptor.run(MessagePhase);
await game.phaseInterceptor.run(MoveEffectPhase);
await game.phaseInterceptor.run(DamagePhase);
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(FaintPhase));
await game.phaseInterceptor.run(FaintPhase);
await game.phaseInterceptor.run(MessagePhase);
await game.phaseInterceptor.run(VictoryPhase);
await game.phaseInterceptor.run(MoveEndPhase);
await game.phaseInterceptor.run(MovePhase);
await game.phaseInterceptor.run(BerryPhase);
await game.phaseInterceptor.run(TurnEndPhase);
await game.phaseInterceptor.run(BattleEndPhase);
await game.phaseInterceptor.run(EggLapsePhase);
await game.phaseInterceptor.run(SelectModifierPhase);
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase);
expect(game.scene.ui?.getMode()).toBe(Mode.MODIFIER_SELECT);
expect(game.scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
}, 100000);
}, 20000);
it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async() => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
@ -161,7 +117,8 @@ describe("Test Battle Phase", () => {
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(5);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP]);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
await game.startBattle();
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
@ -171,35 +128,8 @@ describe("Test Battle Phase", () => {
const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.run(EnemyCommandPhase);
await game.phaseInterceptor.run(TurnStartPhase);
await game.phaseInterceptor.run(MovePhase);
await game.phaseInterceptor.run(MessagePhase);
await game.phaseInterceptor.run(MoveEffectPhase);
await game.phaseInterceptor.run(DamagePhase);
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase));
await game.phaseInterceptor.run(MoveEndPhase);
await game.phaseInterceptor.run(MovePhase);
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEffectPhase));
await game.phaseInterceptor.run(MoveEffectPhase);
game.scene.moveAnimations = null; // Mandatory to avoid the crash
await game.phaseInterceptor.run(StatChangePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase) || game.isCurrentPhase(DamagePhase));
await game.phaseInterceptor.run(DamagePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase));
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase));
await game.phaseInterceptor.run(MoveEndPhase);
await game.phaseInterceptor.run(BerryPhase);
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(TurnEndPhase));
await game.phaseInterceptor.run(TurnEndPhase);
await game.phaseInterceptor.run(TurnInitPhase);
await game.phaseInterceptor.run(CommandPhase);
await waitUntil(() => game.scene.ui?.getMode() === Mode.COMMAND);
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 100000);
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase);
}, 20000);
it("load 100% data file", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
@ -208,7 +138,7 @@ describe("Test Battle Phase", () => {
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
}, 50000);
}, 20000);
it("start battle with selected team", async() => {
await game.startBattle([
@ -219,26 +149,7 @@ describe("Test Battle Phase", () => {
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CHARIZARD);
expect(game.scene.getParty()[1].species.speciesId).toBe(Species.CHANSEY);
expect(game.scene.getParty()[2].species.speciesId).toBe(Species.MEW);
}, 50000);
it("assert next phase", async() => {
await game.phaseInterceptor.run(LoginPhase);
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
game.scene.gameData.gender = PlayerGender.MALE;
game.endPhase();
}, () => game.isCurrentPhase(TitlePhase));
await game.phaseInterceptor.mustRun(SelectGenderPhase).catch((error) => expect(error).toBe(SelectGenderPhase));
await game.phaseInterceptor.mustRun(TitlePhase).catch((error) => expect(error).toBe(TitlePhase));
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
game.scene.gameMode = getGameMode(GameModes.CLASSIC);
const starters = generateStarter(game.scene);
const selectStarterPhase = new SelectStarterPhase(game.scene);
game.scene.pushPhase(new EncounterPhase(game.scene, false));
selectStarterPhase.initBattle(starters);
});
await game.phaseInterceptor.mustRun(EncounterPhase).catch((error) => expect(error).toBe(EncounterPhase));
await game.phaseInterceptor.mustRun(PostSummonPhase).catch((error) => expect(error).toBe(PostSummonPhase));
}, 50000);
}, 20000);
it("test remove random battle seed int", async() => {
for (let i=0; i<10; i++) {
@ -246,5 +157,107 @@ describe("Test Battle Phase", () => {
expect(rand).toBe(14);
}
});
it("wrong phase", async() => {
await game.phaseInterceptor.run(LoginPhase);
await game.phaseInterceptor.run(LoginPhase).catch((e) => {
expect(e).toBe("Wrong phase: this is SelectGenderPhase and not LoginPhase");
});
}, 20000);
it("wrong phase but skip", async() => {
await game.phaseInterceptor.run(LoginPhase);
await game.phaseInterceptor.run(LoginPhase, () => game.isCurrentPhase(SelectGenderPhase));
}, 20000);
it("good run", async() => {
await game.phaseInterceptor.run(LoginPhase);
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
game.scene.gameData.gender = PlayerGender.MALE;
game.endPhase();
}, () => game.isCurrentPhase(TitlePhase));
await game.phaseInterceptor.run(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase));
await game.phaseInterceptor.run(TitlePhase);
}, 20000);
it("good run from select gender to title", async() => {
await game.phaseInterceptor.run(LoginPhase);
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
game.scene.gameData.gender = PlayerGender.MALE;
game.endPhase();
}, () => game.isCurrentPhase(TitlePhase));
await game.phaseInterceptor.runFrom(SelectGenderPhase).to(TitlePhase);
}, 20000);
it("good run to SummonPhase phase", async() => {
await game.phaseInterceptor.run(LoginPhase);
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
game.scene.gameData.gender = PlayerGender.MALE;
game.endPhase();
}, () => game.isCurrentPhase(TitlePhase));
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
game.scene.gameMode = getGameMode(GameModes.CLASSIC);
const starters = generateStarter(game.scene);
const selectStarterPhase = new SelectStarterPhase(game.scene);
game.scene.pushPhase(new EncounterPhase(game.scene, false));
selectStarterPhase.initBattle(starters);
});
await game.phaseInterceptor.runFrom(SelectGenderPhase).to(SummonPhase);
}, 20000);
it("2vs1", async() => {
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
await game.startBattle([
Species.BLASTOISE,
Species.CHARIZARD,
]);
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 20000);
it("1vs1", async() => {
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
await game.startBattle([
Species.BLASTOISE,
]);
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 20000);
it("2vs2", async() => {
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
await game.startBattle([
Species.BLASTOISE,
Species.CHARIZARD,
]);
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 20000);
it("4vs2", async() => {
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
await game.startBattle([
Species.BLASTOISE,
Species.CHARIZARD,
Species.DARKRAI,
Species.GABITE,
]);
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
}, 20000);
});

View File

@ -0,0 +1,39 @@
import {afterEach, beforeAll, beforeEach, describe, it, vi} from "vitest";
import GameManager from "#app/test/utils/gameManager";
import Phaser from "phaser";
import * as overrides from "#app/overrides";
import {Species} from "#app/data/enums/species";
import {Moves} from "#app/data/enums/moves";
import {Abilities} from "#app/data/enums/abilities";
describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
});
it("should start phase", async() => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
await game.startBattle();
}, 100000);
});

View File

@ -28,7 +28,8 @@ describe("Phases", () => {
describe("LoginPhase", () => {
it("should start the login phase", async () => {
const loginPhase = new LoginPhase(scene);
loginPhase.start();
scene.pushPhase(loginPhase);
await game.phaseInterceptor.run(LoginPhase);
expect(scene.ui.getMode()).to.equal(Mode.MESSAGE);
});
});
@ -36,16 +37,18 @@ describe("Phases", () => {
describe("TitlePhase", () => {
it("should start the title phase", async () => {
const titlePhase = new TitlePhase(scene);
titlePhase.start();
expect(scene.ui.getMode()).to.equal(Mode.MESSAGE);
scene.pushPhase(titlePhase);
await game.phaseInterceptor.run(TitlePhase);
expect(scene.ui.getMode()).to.equal(Mode.TITLE);
});
});
describe("UnavailablePhase", () => {
it("should start the unavailable phase", async () => {
const unavailablePhase = new UnavailablePhase(scene);
unavailablePhase.start();
scene.pushPhase(unavailablePhase);
await game.phaseInterceptor.run(UnavailablePhase);
expect(scene.ui.getMode()).to.equal(Mode.UNAVAILABLE);
});
}, 20000);
});
});

View File

@ -15,9 +15,9 @@ import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler";
import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler";
import {OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
import {Gender} from "#app/data/gender";
import {allSpecies} from "#app/data/pokemon-species";
import {Nature} from "#app/data/nature";
import {Abilities} from "#app/data/enums/abilities";
import {allSpecies} from "#app/data/pokemon-species";
describe("UI - Starter select", () => {
@ -51,12 +51,13 @@ describe("UI - Starter select", () => {
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -73,21 +74,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -99,19 +99,25 @@ describe("UI - Starter select", () => {
it("Bulbasaur - shiny - variant 2 female hardy overgrow", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.CYCLE_GENDER);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -128,21 +134,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -153,15 +158,19 @@ describe("UI - Starter select", () => {
expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.OVERGROW);
}, 20000);
it("Bulbasaur - shiny - variant 2 female lonely cholorophyl", async() => {
it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
@ -169,7 +178,9 @@ describe("UI - Starter select", () => {
handler.processInput(Button.CYCLE_NATURE);
handler.processInput(Button.CYCLE_ABILITY);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -186,21 +197,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -211,21 +221,27 @@ describe("UI - Starter select", () => {
expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.CHLOROPHYLL);
}, 20000);
it("Bulbasaur - shiny - variant 2 female", async() => {
it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.CYCLE_GENDER);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -242,21 +258,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -268,19 +283,25 @@ describe("UI - Starter select", () => {
it("Bulbasaur - not shiny", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.CYCLE_SHINY);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -297,21 +318,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -320,76 +340,28 @@ describe("UI - Starter select", () => {
expect(game.scene.getParty()[0].variant).toBe(0);
}, 20000);
it("Bulbasaur - shiny - variant 0", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.V);
handler.processInput(Button.ACTION);
});
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => {
optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler;
options = optionSelectUiHandler.getOptionsWithScroll();
resolve();
});
});
expect(options.some(option => option.label === "Add to Party")).toBe(true);
expect(options.some(option => option.label === "Toggle IVs")).toBe(true);
expect(options.some(option => option.label === "Manage Moves")).toBe(true);
expect(options.some(option => option.label === "Use Candies")).toBe(true);
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.BULBASAUR);
expect(game.scene.getParty()[0].shiny).toBe(true);
expect(game.scene.getParty()[0].variant).toBe(0);
}, 20000);
it("Bulbasaur - shiny - variant 1", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
handler.processInput(Button.V);
handler.processInput(Button.V);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -406,21 +378,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -429,15 +400,19 @@ describe("UI - Starter select", () => {
expect(game.scene.getParty()[0].variant).toBe(1);
}, 20000);
it("Bulbasaur - shiny - variant 1", async() => {
it("Bulbasaur - shiny - variant 2", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
@ -445,7 +420,9 @@ describe("UI - Starter select", () => {
handler.processInput(Button.V);
handler.processInput(Button.V);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -462,21 +439,20 @@ describe("UI - Starter select", () => {
expect(options.some(option => option.label === "Cancel")).toBe(true);
optionSelectUiHandler.processInput(Button.ACTION);
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
await new Promise<void>((resolve) => {
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.SUBMIT);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
resolve();
});
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
@ -485,15 +461,19 @@ describe("UI - Starter select", () => {
expect(game.scene.getParty()[0].variant).toBe(2);
}, 20000);
it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column ", async() => {
it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
@ -501,7 +481,9 @@ describe("UI - Starter select", () => {
handler.processInput(Button.RIGHT);
handler.processInput(Button.RIGHT);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -526,6 +508,7 @@ describe("UI - Starter select", () => {
resolve();
});
});
expect(starterSelectUiHandler.starterGens[0]).toBe(0);
expect(starterSelectUiHandler.starterCursors[0]).toBe(3);
expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18);
@ -539,23 +522,23 @@ describe("UI - Starter select", () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CATERPIE);
}, 20000);
it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1) ", async() => {
it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1)", async() => {
await game.importData("src/test/utils/saves/everything.prsv");
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
const species = game.scene.gameData.dexData[key];
return species.caughtAttr !== 0n;
}).length;
expect(caughtCount).toBe(Object.keys(allSpecies).length);
await game.runToTitle();
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
currentPhase.gameMode = GameModes.CLASSIC;
currentPhase.end();
});
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.RIGHT);
@ -564,7 +547,9 @@ describe("UI - Starter select", () => {
handler.processInput(Button.RIGHT);
handler.processInput(Button.DOWN);
handler.processInput(Button.ACTION);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.run(SelectStarterPhase);
let options: OptionSelectItem[];
let optionSelectUiHandler: OptionSelectUiHandler;
await new Promise<void>((resolve) => {
@ -589,6 +574,7 @@ describe("UI - Starter select", () => {
resolve();
});
});
expect(starterSelectUiHandler.starterGens[0]).toBe(0);
expect(starterSelectUiHandler.starterCursors[0]).toBe(12);
expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18);
@ -602,10 +588,6 @@ describe("UI - Starter select", () => {
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
saveSlotSelectUiHandler.processInput(Button.ACTION);
});
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.NIDORAN_M);
}, 20000);

View File

@ -0,0 +1,50 @@
export default class ErrorInterceptor {
private static instance: ErrorInterceptor;
public running;
constructor() {
this.running = [];
}
public static getInstance(): ErrorInterceptor {
if (!ErrorInterceptor.instance) {
ErrorInterceptor.instance = new ErrorInterceptor();
}
return ErrorInterceptor.instance;
}
clear() {
this.running = [];
}
add(obj) {
this.running.push(obj);
}
remove(obj) {
const index = this.running.indexOf(obj);
if (index !== -1) {
this.running.splice(index, 1);
}
}
}
process.on("uncaughtException", (error) => {
console.log(error);
const toStop = ErrorInterceptor.getInstance().running;
for (const elm of toStop) {
elm.rejectAll(error);
}
global.testFailed = true;
});
// Global error handler for unhandled promise rejections
process.on("unhandledRejection", (reason, promise) => {
console.log(reason);
const toStop = ErrorInterceptor.getInstance().running;
for (const elm of toStop) {
elm.rejectAll(reason);
}
global.testFailed = true;
});

View File

@ -2,21 +2,17 @@ import GameWrapper from "#app/test/utils/gameWrapper";
import {Mode} from "#app/ui/ui";
import {generateStarter, waitUntil} from "#app/test/utils/gameManagerUtils";
import {
CheckSwitchPhase,
CommandPhase,
EncounterPhase,
LoginPhase,
PostSummonPhase,
SelectGenderPhase,
SelectStarterPhase,
SummonPhase,
TitlePhase,
ToggleDoublePositionPhase,
} from "#app/phases";
import BattleScene from "#app/battle-scene.js";
import PhaseInterceptor from "#app/test/utils/phaseInterceptor";
import TextInterceptor from "#app/test/utils/TextInterceptor";
import {expect} from "vitest";
import {GameModes, getGameMode} from "#app/game-mode";
import fs from "fs";
import { AES, enc } from "crypto-js";
@ -26,6 +22,7 @@ import {PlayerGender} from "#app/data/enums/player-gender";
import {GameDataType} from "#app/data/enums/game-data-type";
import InputsHandler from "#app/test/utils/inputsHandler";
import {ExpNotification} from "#app/enums/exp-notification";
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
/**
* Class to manage the game state and transitions between phases.
@ -43,6 +40,8 @@ export default class GameManager {
* @param bypassLogin - Whether to bypass the login phase.
*/
constructor(phaserGame: Phaser.Game, bypassLogin: boolean = true) {
localStorage.clear();
ErrorInterceptor.getInstance().clear();
BattleScene.prototype.randBattleSeedInt = (arg) => arg-1;
this.gameWrapper = new GameWrapper(phaserGame, bypassLogin);
this.scene = new BattleScene();
@ -94,14 +93,14 @@ export default class GameManager {
* @returns A promise that resolves when the title phase is reached.
*/
runToTitle(): Promise<void> {
return new Promise(async(resolve) => {
await this.phaseInterceptor.run(LoginPhase);
return new Promise(async(resolve, reject) => {
await this.phaseInterceptor.run(LoginPhase).catch((e) => reject(e));
this.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
this.scene.gameData.gender = PlayerGender.MALE;
this.endPhase();
}, () => this.isCurrentPhase(TitlePhase));
await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase));
await this.phaseInterceptor.run(TitlePhase);
await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase)).catch((e) => reject(e));
await this.phaseInterceptor.run(TitlePhase).catch((e) => reject(e));
this.scene.gameSpeed = 5;
this.scene.moveAnimations = false;
this.scene.showLevelUpStats = false;
@ -118,8 +117,8 @@ export default class GameManager {
* @returns A promise that resolves when the summon phase is reached.
*/
runToSummon(species?: Species[]): Promise<void> {
return new Promise(async(resolve) => {
await this.runToTitle();
return new Promise(async(resolve, reject) => {
await this.runToTitle().catch((e) => reject(e));
this.onNextPrompt("TitlePhase", Mode.TITLE, () => {
this.scene.gameMode = getGameMode(GameModes.CLASSIC);
const starters = generateStarter(this.scene, species);
@ -127,7 +126,7 @@ export default class GameManager {
this.scene.pushPhase(new EncounterPhase(this.scene, false));
selectStarterPhase.initBattle(starters);
});
await this.phaseInterceptor.run(EncounterPhase);
await this.phaseInterceptor.run(EncounterPhase).catch((e) => reject(e));
resolve();
});
}
@ -138,25 +137,18 @@ export default class GameManager {
* @returns A promise that resolves when the battle is started.
*/
startBattle(species?: Species[]): Promise<void> {
return new Promise(async(resolve) => {
await this.runToSummon(species);
await this.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase);
await this.phaseInterceptor.run(SummonPhase, () => this.isCurrentPhase(CheckSwitchPhase) || this.isCurrentPhase(PostSummonPhase));
return new Promise(async(resolve, reject) => {
await this.runToSummon(species).catch((e) => reject(e));
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
this.setMode(Mode.MESSAGE);
this.endPhase();
}, () => this.isCurrentPhase(PostSummonPhase));
}, () => this.isCurrentPhase(CommandPhase));
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
this.setMode(Mode.MESSAGE);
this.endPhase();
}, () => this.isCurrentPhase(PostSummonPhase));
await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase));
await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase));
await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase);
await waitUntil(() => this.scene.ui?.getMode() === Mode.COMMAND);
}, () => this.isCurrentPhase(CommandPhase));
await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase).catch((e) => reject(e));
console.log("==================[New Turn]==================");
expect(this.scene.ui?.getMode()).toBe(Mode.COMMAND);
expect(this.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
return resolve();
});
}

View File

@ -86,7 +86,6 @@ export default class GameWrapper {
frames: {},
});
Pokemon.prototype.enableMask = () => null;
localStorage.clear();
}
setScene(scene: BattleScene) {

View File

@ -7,9 +7,11 @@ export default class MockText {
private scene;
private textureManager;
public list = [];
public style;
constructor(textureManager, x, y, content, styleOptions) {
this.scene = textureManager.scene;
this.textureManager = textureManager;
this.style = {};
// Phaser.GameObjects.TextStyle.prototype.setStyle = () => null;
// Phaser.GameObjects.Text.prototype.updateText = () => null;
// Phaser.Textures.TextureManager.prototype.addCanvas = () => {};

View File

@ -6,10 +6,12 @@ import {
LoginPhase, MessagePhase, MoveEffectPhase, MoveEndPhase, MovePhase, NewBattlePhase, NextEncounterPhase,
PostSummonPhase,
SelectGenderPhase, SelectModifierPhase,
SelectStarterPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase,
TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, VictoryPhase
SelectStarterPhase, SelectTargetPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase,
TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, UnavailablePhase, VictoryPhase
} from "#app/phases";
import {Mode} from "#app/ui/ui";
import UI, {Mode} from "#app/ui/ui";
import {Phase} from "#app/phase";
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
export default class PhaseInterceptor {
public scene;
@ -21,6 +23,9 @@ export default class PhaseInterceptor {
private intervalRun;
private prompts;
private phaseFrom;
private inProgress;
private originalSetMode;
private originalSuperEnd;
/**
* List of phases with their corresponding start methods.
@ -56,6 +61,12 @@ export default class PhaseInterceptor {
[MoveEndPhase, this.startPhase],
[StatChangePhase, this.startPhase],
[ShinySparklePhase, this.startPhase],
[SelectTargetPhase, this.startPhase],
[UnavailablePhase, this.startPhase],
];
private endBySetMode = [
TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase
];
/**
@ -71,6 +82,15 @@ export default class PhaseInterceptor {
this.startPromptHander();
}
rejectAll(error) {
if (this.inProgress) {
clearInterval(this.promptInterval);
clearInterval(this.interval);
clearInterval(this.intervalRun);
this.inProgress.onError(error);
}
}
/**
* Method to set the starting phase.
* @param phaseFrom - The phase to start from.
@ -86,20 +106,31 @@ export default class PhaseInterceptor {
* @param phaseTo - The phase to transition to.
* @returns A promise that resolves when the transition is complete.
*/
async to(phaseTo): Promise<void> {
return new Promise(async (resolve) => {
await this.run(this.phaseFrom);
async to(phaseTo, runTarget: boolean = true): Promise<void> {
return new Promise(async (resolve, reject) => {
ErrorInterceptor.getInstance().add(this);
await this.run(this.phaseFrom).catch((e) => reject(e));
this.phaseFrom = null;
const targetName = typeof phaseTo === "string" ? phaseTo : phaseTo.name;
this.intervalRun = setInterval(async () => {
this.intervalRun = setInterval(async() => {
const currentPhase = this.onHold?.length && this.onHold[0];
if (currentPhase && currentPhase.name !== targetName) {
await this.run(currentPhase.name);
} else if (currentPhase.name === targetName) {
await this.run(currentPhase.name);
if (currentPhase && currentPhase.name === targetName) {
clearInterval(this.intervalRun);
if (!runTarget) {
return resolve();
}
await this.run(currentPhase).catch((e) => {
clearInterval(this.intervalRun);
return reject(e);
});
return resolve();
}
if (currentPhase && currentPhase.name !== targetName) {
await this.run(currentPhase).catch((e) => {
clearInterval(this.intervalRun);
return reject(e);
});
}
});
});
}
@ -111,92 +142,53 @@ export default class PhaseInterceptor {
* @returns A promise that resolves when the phase is run.
*/
run(phaseTarget, skipFn?): Promise<void> {
this.scene.moveAnimations = null; // Mandatory to avoid crash
return new Promise(async (resolve) => {
this.waitUntil(phaseTarget, skipFn).then(() => {
const currentPhase = this.onHold.shift();
currentPhase.call();
resolve();
}).catch(() => {
resolve();
});
});
}
/**
* Method to ensure a phase is run, to throw error on test if not.
* @param phaseTarget - The phase to run.
* @returns A promise that resolves when the phase is run.
*/
mustRun(phaseTarget): Promise<void> {
const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name;
this.scene.moveAnimations = null; // Mandatory to avoid crash
return new Promise(async (resolve, reject) => {
ErrorInterceptor.getInstance().add(this);
const interval = setInterval(async () => {
const currentPhase = this.onHold?.length && this.onHold[0];
if (currentPhase && currentPhase.name !== targetName) {
reject(currentPhase);
} else if (currentPhase && currentPhase.name === targetName) {
const currentPhase = this.onHold.shift();
if (currentPhase) {
if (currentPhase.name !== targetName) {
clearInterval(interval);
const skip = skipFn && skipFn(currentPhase.name);
if (skip) {
this.onHold.unshift(currentPhase);
ErrorInterceptor.getInstance().remove(this);
return resolve();
}
clearInterval(interval);
return reject(`Wrong phase: this is ${currentPhase.name} and not ${targetName}`);
}
clearInterval(interval);
await this.run(phaseTarget);
resolve();
this.inProgress = {
name: currentPhase.name,
callback: () => {
ErrorInterceptor.getInstance().remove(this);
resolve();
},
onError: (error) => reject(error),
};
currentPhase.call();
}
});
});
}
/**
* Method to execute actions when about to run a phase. Does not run the phase, stop right before.
* @param phaseTarget - The phase to run.
* @param skipFn - Optional skip function.
* @returns A promise that resolves when the phase is about to run.
*/
whenAboutToRun(phaseTarget, skipFn?): Promise<void> {
return new Promise(async (resolve) => {
this.waitUntil(phaseTarget, skipFn).then(() => {
resolve();
}).catch(() => {
resolve();
});
});
}
/**
* Method to remove a phase from the list.
* @param phaseTarget - The phase to remove.
* @param skipFn - Optional skip function.
* @returns A promise that resolves when the phase is removed.
*/
remove(phaseTarget, skipFn?): Promise<void> {
return new Promise(async (resolve) => {
this.waitUntil(phaseTarget, skipFn).then(() => {
this.onHold.shift();
this.scene.getCurrentPhase().end();
resolve();
}).catch(() => {
resolve();
});
});
}
/**
* Method to wait until a specific phase is reached.
* @param phaseTarget - The phase to wait for.
* @param skipFn - Optional skip function.
* @returns A promise that resolves when the phase is reached.
*/
waitUntil(phaseTarget, skipFn?): Promise<void> {
const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name;
return new Promise((resolve, reject) => {
this.interval = setInterval(() => {
const currentPhase = this.onHold?.length && this.onHold[0] && this.onHold[0].name;
// if the currentPhase here is not filled, it means it's a phase we haven't added to the list
if (currentPhase === targetName) {
clearInterval(this.interval);
return resolve();
} else if (skipFn && skipFn()) {
clearInterval(this.interval);
return reject("Skipped phase");
this.scene.moveAnimations = null; // Mandatory to avoid crash
return new Promise(async (resolve, reject) => {
ErrorInterceptor.getInstance().add(this);
const interval = setInterval(async () => {
const currentPhase = this.onHold.shift();
if (currentPhase) {
if (currentPhase.name !== targetName) {
this.onHold.unshift(currentPhase);
} else {
clearInterval(interval);
resolve();
}
}
});
});
@ -206,10 +198,17 @@ export default class PhaseInterceptor {
* Method to initialize phases and their corresponding methods.
*/
initPhases() {
for (const [phase, method] of this.PHASES) {
this.originalSetMode = UI.prototype.setMode;
this.originalSuperEnd = Phase.prototype.end;
UI.prototype.setMode = (mode, ...args) => this.setMode.call(this, mode, ...args);
Phase.prototype.end = () => this.superEndPhase.call(this);
for (const [phase, methodStart] of this.PHASES) {
const originalStart = phase.prototype.start;
this.phases[phase.name] = originalStart;
phase.prototype.start = () => method.call(this, phase);
this.phases[phase.name] = {
start: originalStart,
endBySetMode: this.endBySetMode.some((elm) => elm.name === phase.name),
};
phase.prototype.start = () => methodStart.call(this, phase);
}
}
@ -223,11 +222,44 @@ export default class PhaseInterceptor {
this.onHold.push({
name: phase.name,
call: () => {
this.phases[phase.name].apply(instance);
this.phases[phase.name].start.apply(instance);
}
});
}
unlock() {
this.inProgress?.callback();
this.inProgress = undefined;
}
/**
* Method to end a phase and log it.
* @param phase - The phase to start.
*/
superEndPhase() {
const instance = this.scene.getCurrentPhase();
console.log(`%c INTERCEPTED Super End Phase ${instance.constructor.name}`, "color:red;");
this.originalSuperEnd.apply(instance);
this.inProgress?.callback();
this.inProgress = undefined;
}
/**
* m2m to set mode.
* @param phase - The phase to start.
*/
setMode(mode: Mode, ...args: any[]): Promise<void> {
const currentPhase = this.scene.getCurrentPhase();
const instance = this.scene.ui;
console.log("setMode", mode, args);
const ret = this.originalSetMode.apply(instance, [mode, ...args]);
if (this.phases[currentPhase.constructor.name].endBySetMode) {
this.inProgress?.callback();
this.inProgress = undefined;
}
return ret;
}
/**
* Method to start the prompt handler.
*/
@ -271,9 +303,12 @@ export default class PhaseInterceptor {
*/
restoreOg() {
for (const [phase] of this.PHASES) {
phase.prototype.start = this.phases[phase.name];
phase.prototype.start = this.phases[phase.name].start;
}
UI.prototype.setMode = this.originalSetMode;
Phase.prototype.end = this.originalSuperEnd;
clearInterval(this.promptInterval);
clearInterval(this.interval);
clearInterval(this.intervalRun);
}
}

View File

@ -21,3 +21,5 @@ initPokemonForms();
initSpecies();
initMoves();
initAbilities();
global.testFailed = false;

View File

@ -55,6 +55,9 @@ export default class BattleFlyout extends Phaser.GameObjects.Container {
/** The array of {@linkcode MoveInfo} used to track moves for the {@linkcode Pokemon} linked to the flyout */
private moveInfo: MoveInfo[] = new Array();
/** Current state of the flyout's visibility */
public flyoutVisible: boolean = false;
// Stores callbacks in a variable so they can be unsubscribed from when destroyed
private readonly onMoveUsedEvent = (event: Event) => this.onMoveUsed(event);
private readonly onBerryUsedEvent = (event: Event) => this.onBerryUsed(event);
@ -170,6 +173,8 @@ export default class BattleFlyout extends Phaser.GameObjects.Container {
/** Animates the flyout to either show or hide it by applying a fade and translation */
toggleFlyout(visible: boolean): void {
this.flyoutVisible = visible;
this.scene.tweens.add({
targets: this.flyoutParent,
x: visible ? this.anchorX : this.anchorX - this.translationX,

View File

@ -9,6 +9,7 @@ import { Type, getTypeRgb } from "../data/type";
import { getVariantTint } from "#app/data/variant";
import { BattleStat } from "#app/data/battle-stat";
import BattleFlyout from "./battle-flyout";
import { WindowVariant, addWindow } from "./ui-theme";
const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ];
@ -52,6 +53,13 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
private type3Icon: Phaser.GameObjects.Sprite;
private expBar: Phaser.GameObjects.Image;
// #region Type effectiveness hint objects
private effectivenessContainer: Phaser.GameObjects.Container;
private effectivenessWindow: Phaser.GameObjects.NineSlice;
private effectivenessText: Phaser.GameObjects.Text;
private currentEffectiveness?: string;
// #endregion
public expMaskRect: Phaser.GameObjects.Graphics;
private statsContainer: Phaser.GameObjects.Container;
@ -59,7 +67,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
private statValuesContainer: Phaser.GameObjects.Container;
private statNumbers: Phaser.GameObjects.Sprite[];
public flyoutMenu: BattleFlyout;
public flyoutMenu?: BattleFlyout;
constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) {
super(scene, x, y);
@ -250,6 +258,19 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.type3Icon.setName("icon_type_3");
this.type3Icon.setOrigin(0, 0);
this.add(this.type3Icon);
if (!this.player) {
this.effectivenessContainer = this.scene.add.container(0, 0);
this.effectivenessContainer.setPositionRelative(this.type1Icon, 22, 4);
this.effectivenessContainer.setVisible(false);
this.add(this.effectivenessContainer);
this.effectivenessText = addTextObject(this.scene, 5, 4.5, "", TextStyle.BATTLE_INFO);
this.effectivenessWindow = addWindow((this.scene as BattleScene), 0, 0, 0, 20, false, false, null, null, WindowVariant.XTHIN);
this.effectivenessContainer.add(this.effectivenessWindow);
this.effectivenessContainer.add(this.effectivenessText);
}
}
initInfo(pokemon: Pokemon) {
@ -711,6 +732,39 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
});
}
/**
* Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary
*/
toggleFlyout(visible: boolean): void {
this.flyoutMenu?.toggleFlyout(visible);
if (visible) {
this.effectivenessContainer?.setVisible(false);
} else {
this.updateEffectiveness(this.currentEffectiveness);
}
}
/**
* Show or hide the type effectiveness multiplier window
* Passing undefined will hide the window
*/
updateEffectiveness(effectiveness?: string) {
if (this.player) {
return;
}
this.currentEffectiveness = effectiveness;
if (!(this.scene as BattleScene).typeHints || effectiveness === undefined || this.flyoutMenu.flyoutVisible) {
this.effectivenessContainer.setVisible(false);
return;
}
this.effectivenessText.setText(effectiveness);
this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth;
this.effectivenessContainer.setVisible(true);
}
getBaseY(): number {
return this.baseY;
}

View File

@ -1,6 +1,6 @@
import BattleScene from "../battle-scene";
import { addTextObject, TextStyle } from "./text";
import { Type } from "../data/type";
import { getTypeDamageMultiplierColor, Type } from "../data/type";
import { Command } from "./command-ui-handler";
import { Mode } from "./ui";
import UiHandler from "./ui-handler";
@ -9,6 +9,7 @@ import { CommandPhase } from "../phases";
import { MoveCategory } from "#app/data/move.js";
import i18next from "../plugins/i18n";
import {Button} from "../enums/buttons";
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
export default class FightUiHandler extends UiHandler {
private movesContainer: Phaser.GameObjects.Container;
@ -162,7 +163,8 @@ export default class FightUiHandler extends UiHandler {
ui.add(this.cursorObj);
}
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset();
const pokemon = (this.scene.getCurrentPhase() as CommandPhase).getPokemon();
const moveset = pokemon.getMoveset();
const hasMove = cursor < moveset.length;
@ -179,6 +181,10 @@ export default class FightUiHandler extends UiHandler {
this.ppText.setText(`${Utils.padInt(pp, 2, " ")}/${Utils.padInt(maxPP, 2, " ")}`);
this.powerText.setText(`${power >= 0 ? power : "---"}`);
this.accuracyText.setText(`${accuracy >= 0 ? accuracy : "---"}`);
pokemon.getOpponents().forEach((opponent) => {
opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove));
});
}
this.typeIcon.setVisible(hasMove);
@ -195,17 +201,60 @@ export default class FightUiHandler extends UiHandler {
return changed;
}
/**
* Gets multiplier text for a pokemon's move against a specific opponent
* Returns undefined if it's a status move
*/
private getEffectivenessText(pokemon: Pokemon, opponent: Pokemon, pokemonMove: PokemonMove): string | undefined {
const effectiveness = opponent.getMoveEffectiveness(pokemon, pokemonMove);
if (effectiveness === undefined) {
return undefined;
}
return `${effectiveness}x`;
}
displayMoves() {
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset();
for (let m = 0; m < 4; m++) {
const moveText = addTextObject(this.scene, m % 2 === 0 ? 0 : 100, m < 2 ? 0 : 16, "-", TextStyle.WINDOW);
if (m < moveset.length) {
moveText.setText(moveset[m].getName());
const pokemon = (this.scene.getCurrentPhase() as CommandPhase).getPokemon();
const moveset = pokemon.getMoveset();
for (let moveIndex = 0; moveIndex < 4; moveIndex++) {
const moveText = addTextObject(this.scene, moveIndex % 2 === 0 ? 0 : 100, moveIndex < 2 ? 0 : 16, "-", TextStyle.WINDOW);
if (moveIndex < moveset.length) {
const pokemonMove = moveset[moveIndex];
moveText.setText(pokemonMove.getName());
moveText.setColor(this.getMoveColor(pokemon, pokemonMove) ?? moveText.style.color);
}
this.movesContainer.add(moveText);
}
}
/**
* Returns a specific move's color based on its type effectiveness against opponents
* If there are multiple opponents, the highest effectiveness' color is returned
* @returns A color or undefined if the default color should be used
*/
private getMoveColor(pokemon: Pokemon, pokemonMove: PokemonMove): string | undefined {
if (!this.scene.typeHints) {
return undefined;
}
const opponents = pokemon.getOpponents();
if (opponents.length <= 0) {
return undefined;
}
const moveColors = opponents.map((opponent) => {
return opponent.getMoveEffectiveness(pokemon, pokemonMove);
}).sort((a, b) => b - a).map((effectiveness) => {
return getTypeDamageMultiplierColor(effectiveness, "offense");
});
return moveColors[0];
}
clear() {
super.clear();
this.clearMoves();
@ -222,6 +271,11 @@ export default class FightUiHandler extends UiHandler {
clearMoves() {
this.movesContainer.removeAll(true);
const opponents = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getOpponents();
opponents.forEach((opponent) => {
opponent.updateEffectiveness(undefined);
});
}
eraseCursor() {

View File

@ -1,15 +1,15 @@
import i18next from "i18next";
import BattleScene from "../battle-scene";
import { Button } from "../enums/buttons";
import { GameMode } from "../game-mode";
import { PokemonHeldItemModifier } from "../modifier/modifier";
import { SessionSaveData } from "../system/game-data";
import PokemonData from "../system/pokemon-data";
import * as Utils from "../utils";
import MessageUiHandler from "./message-ui-handler";
import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
import * as Utils from "../utils";
import PokemonData from "../system/pokemon-data";
import { PokemonHeldItemModifier } from "../modifier/modifier";
import MessageUiHandler from "./message-ui-handler";
import i18next from "i18next";
import {Button} from "../enums/buttons";
const sessionSlotCount = 5;
@ -118,7 +118,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler {
originalCallback(cursor);
};
if (this.sessionSlots[cursor].hasData) {
ui.showText("Overwrite the data in the selected slot?", null, () => {
ui.showText(i18next.t("saveSlotSelectUiHandler:overwriteData"), null, () => {
ui.setOverlayMode(Mode.CONFIRM, () => saveAndCallback(), () => {
ui.revertMode();
ui.showText(null, 0);
@ -258,7 +258,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
const slotWindow = addWindow(this.scene, 0, 0, 304, 52);
this.add(slotWindow);
this.loadingLabel = addTextObject(this.scene, 152, 26, "Loading…", TextStyle.WINDOW);
this.loadingLabel = addTextObject(this.scene, 152, 26, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW);
this.loadingLabel.setOrigin(0.5, 0.5);
this.add(this.loadingLabel);
}
@ -266,7 +266,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
async setupWithData(data: SessionSaveData) {
this.remove(this.loadingLabel, true);
const gameModeLabel = addTextObject(this.scene, 8, 5, `${GameMode.getModeName(data.gameMode) || "Unknown"} - Wave ${data.waveIndex}`, TextStyle.WINDOW);
const gameModeLabel = addTextObject(this.scene, 8, 5, `${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unkown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`, TextStyle.WINDOW);
this.add(gameModeLabel);
const timestampLabel = addTextObject(this.scene, 8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW);
@ -283,7 +283,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
const pokemon = p.toPokemon(this.scene);
const icon = this.scene.addPokemonIcon(pokemon, 0, 0, 0, 0);
const text = addTextObject(this.scene, 32, 20, `Lv${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" });
const text = addTextObject(this.scene, 32, 20, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" });
text.setShadow(0, 0, null);
text.setStroke("#424242", 14);
text.setOrigin(1, 0);
@ -324,7 +324,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
this.scene.gameData.getSession(this.slotId).then(async sessionData => {
if (!sessionData) {
this.hasData = false;
this.loadingLabel.setText(i18next.t("menu:empty"));
this.loadingLabel.setText(i18next.t("saveSlotSelectUiHandler:empty"));
resolve(false);
return;
}

View File

@ -2,7 +2,7 @@ import BattleScene from "../../battle-scene";
import { Mode } from "../ui";
"#app/inputs-controller.js";
import AbstractSettingsUiHandler from "./abstract-settings-ui-handler";
import { Setting, SettingType } from "#app/system/settings/settings";
import { Setting, SettingKeys, SettingType } from "#app/system/settings/settings";
export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler {
/**
@ -15,6 +15,48 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler
super(scene, mode);
this.title = "Display";
this.settings = Setting.filter(s => s.type === SettingType.DISPLAY);
/**
* Update to current language from default value.
* - default value is 'English'
*/
const languageIndex = this.settings.findIndex(s => s.key === SettingKeys.Language);
if (languageIndex >= 0) {
const currentLocale = localStorage.getItem("prLang");
switch (currentLocale) {
case "en":
this.settings[languageIndex].options[0] = "English";
break;
case "es":
this.settings[languageIndex].options[0] = "Español";
break;
case "it":
this.settings[languageIndex].options[0] = "Italiano";
break;
case "fr":
this.settings[languageIndex].options[0] = "Français";
break;
case "de":
this.settings[languageIndex].options[0] = "Deutsch";
break;
case "pt-BR":
this.settings[languageIndex].options[0] = "Português (BR)";
break;
case "zh-CN":
this.settings[languageIndex].options[0] = "简体中文";
break;
case "zh-TW":
this.settings[languageIndex].options[0] = "繁體中文";
break;
case "ko":
this.settings[languageIndex].options[0] = "한국어";
break;
default:
this.settings[languageIndex].options[0] = "English";
break;
}
}
this.localStorageKey = "settings";
}
}