diff --git a/index.html b/index.html
index a86f7832fc7..3722bdd3422 100644
--- a/index.html
+++ b/index.html
@@ -31,11 +31,6 @@
font-family: 'emerald';
src: url('./fonts/pokemon-emerald-pro.ttf') format('truetype');
}
- @font-face {
- font-family: 'unifont';
- src: url('./fonts/unifont-15.1.05.otf') format('opentype');
- size-adjust: 70%;
- }
@font-face {
font-family: 'pkmnems';
diff --git a/package-lock.json b/package-lock.json
index 45ce400ca2e..638a173d7e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8365,9 +8365,9 @@
"dev": true
},
"node_modules/ws": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
- "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"engines": {
"node": ">=10.0.0"
diff --git a/public/images/pokemon/variant/exp/9-mega_2.json b/public/images/pokemon/variant/exp/9-mega_2.json
new file mode 100644
index 00000000000..ab160a44451
--- /dev/null
+++ b/public/images/pokemon/variant/exp/9-mega_2.json
@@ -0,0 +1,41 @@
+{
+ "textures": [
+ {
+ "image": "9-mega_2.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 88,
+ "h": 88
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "0001.png",
+ "rotated": false,
+ "trimmed": false,
+ "sourceSize": {
+ "w": 88,
+ "h": 87
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 88,
+ "h": 87
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 88,
+ "h": 87
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:9b1bebbbe735399ba2678aa35a42b156:2dc7c20135acd855e9e97cb010985396:00f61506d33ec61875296e0fb5a82ee9$"
+ }
+}
\ No newline at end of file
diff --git a/public/images/pokemon/variant/exp/9-mega_2.png b/public/images/pokemon/variant/exp/9-mega_2.png
new file mode 100644
index 00000000000..c3c06c1eca7
Binary files /dev/null and b/public/images/pokemon/variant/exp/9-mega_2.png differ
diff --git a/public/images/pokemon/variant/exp/9-mega_3.json b/public/images/pokemon/variant/exp/9-mega_3.json
new file mode 100644
index 00000000000..24363c06a12
--- /dev/null
+++ b/public/images/pokemon/variant/exp/9-mega_3.json
@@ -0,0 +1,41 @@
+{
+ "textures": [
+ {
+ "image": "9-mega_3.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 88,
+ "h": 88
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "0001.png",
+ "rotated": false,
+ "trimmed": false,
+ "sourceSize": {
+ "w": 88,
+ "h": 87
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 88,
+ "h": 87
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 88,
+ "h": 87
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:9b1bebbbe735399ba2678aa35a42b156:2dc7c20135acd855e9e97cb010985396:00f61506d33ec61875296e0fb5a82ee9$"
+ }
+}
\ No newline at end of file
diff --git a/public/images/pokemon/variant/exp/9-mega_3.png b/public/images/pokemon/variant/exp/9-mega_3.png
new file mode 100644
index 00000000000..d7a4b6f9140
Binary files /dev/null and b/public/images/pokemon/variant/exp/9-mega_3.png differ
diff --git a/public/images/pokemon/variant/exp/back/9-mega_2.json b/public/images/pokemon/variant/exp/back/9-mega_2.json
new file mode 100644
index 00000000000..42d17ca7d0a
--- /dev/null
+++ b/public/images/pokemon/variant/exp/back/9-mega_2.json
@@ -0,0 +1,41 @@
+{
+ "textures": [
+ {
+ "image": "9-mega_2.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 77,
+ "h": 77
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "0001.png",
+ "rotated": false,
+ "trimmed": false,
+ "sourceSize": {
+ "w": 77,
+ "h": 77
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 77,
+ "h": 77
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 77,
+ "h": 77
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:5d9f38fc4da0e99e00a40be3452a927c:2c58504a78e2752d4c536f8a79dab703:00f61506d33ec61875296e0fb5a82ee9$"
+ }
+}
\ No newline at end of file
diff --git a/public/images/pokemon/variant/exp/back/9-mega_2.png b/public/images/pokemon/variant/exp/back/9-mega_2.png
new file mode 100644
index 00000000000..e961ace2e5c
Binary files /dev/null and b/public/images/pokemon/variant/exp/back/9-mega_2.png differ
diff --git a/public/images/pokemon/variant/exp/back/9-mega_3.json b/public/images/pokemon/variant/exp/back/9-mega_3.json
new file mode 100644
index 00000000000..f108154d97a
--- /dev/null
+++ b/public/images/pokemon/variant/exp/back/9-mega_3.json
@@ -0,0 +1,41 @@
+{
+ "textures": [
+ {
+ "image": "9-mega_3.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 77,
+ "h": 77
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "0001.png",
+ "rotated": false,
+ "trimmed": false,
+ "sourceSize": {
+ "w": 77,
+ "h": 77
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 77,
+ "h": 77
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 77,
+ "h": 77
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:5d9f38fc4da0e99e00a40be3452a927c:2c58504a78e2752d4c536f8a79dab703:00f61506d33ec61875296e0fb5a82ee9$"
+ }
+}
\ No newline at end of file
diff --git a/public/images/pokemon/variant/exp/back/9-mega_3.png b/public/images/pokemon/variant/exp/back/9-mega_3.png
new file mode 100644
index 00000000000..95a7babe58b
Binary files /dev/null and b/public/images/pokemon/variant/exp/back/9-mega_3.png differ
diff --git a/public/images/types/bug.png b/public/images/types/bug.png
deleted file mode 100644
index 72681086ec6..00000000000
Binary files a/public/images/types/bug.png and /dev/null differ
diff --git a/public/images/types/dark.png b/public/images/types/dark.png
deleted file mode 100644
index 6605a95bb4c..00000000000
Binary files a/public/images/types/dark.png and /dev/null differ
diff --git a/public/images/types/dragon.png b/public/images/types/dragon.png
deleted file mode 100644
index 3554bc8bd68..00000000000
Binary files a/public/images/types/dragon.png and /dev/null differ
diff --git a/public/images/types/electric.png b/public/images/types/electric.png
deleted file mode 100644
index ea5008652c5..00000000000
Binary files a/public/images/types/electric.png and /dev/null differ
diff --git a/public/images/types/fairy.png b/public/images/types/fairy.png
deleted file mode 100644
index f8ca169d3aa..00000000000
Binary files a/public/images/types/fairy.png and /dev/null differ
diff --git a/public/images/types/fighting.png b/public/images/types/fighting.png
deleted file mode 100644
index 0fd87f3dbd9..00000000000
Binary files a/public/images/types/fighting.png and /dev/null differ
diff --git a/public/images/types/fire.png b/public/images/types/fire.png
deleted file mode 100644
index 08a550fcaff..00000000000
Binary files a/public/images/types/fire.png and /dev/null differ
diff --git a/public/images/types/flying.png b/public/images/types/flying.png
deleted file mode 100644
index 3a13e051222..00000000000
Binary files a/public/images/types/flying.png and /dev/null differ
diff --git a/public/images/types/ghost.png b/public/images/types/ghost.png
deleted file mode 100644
index f32896bed02..00000000000
Binary files a/public/images/types/ghost.png and /dev/null differ
diff --git a/public/images/types/grass.png b/public/images/types/grass.png
deleted file mode 100644
index 35dfecfc2d2..00000000000
Binary files a/public/images/types/grass.png and /dev/null differ
diff --git a/public/images/types/ground.png b/public/images/types/ground.png
deleted file mode 100644
index 0df975559b6..00000000000
Binary files a/public/images/types/ground.png and /dev/null differ
diff --git a/public/images/types/ice.png b/public/images/types/ice.png
deleted file mode 100644
index 57ea33f9b16..00000000000
Binary files a/public/images/types/ice.png and /dev/null differ
diff --git a/public/images/types/normal.png b/public/images/types/normal.png
deleted file mode 100644
index 92524168f5c..00000000000
Binary files a/public/images/types/normal.png and /dev/null differ
diff --git a/public/images/types/poison.png b/public/images/types/poison.png
deleted file mode 100644
index c898b4d14a9..00000000000
Binary files a/public/images/types/poison.png and /dev/null differ
diff --git a/public/images/types/psychic.png b/public/images/types/psychic.png
deleted file mode 100644
index ff55bc54a60..00000000000
Binary files a/public/images/types/psychic.png and /dev/null differ
diff --git a/public/images/types/rock.png b/public/images/types/rock.png
deleted file mode 100644
index 0a90b780a24..00000000000
Binary files a/public/images/types/rock.png and /dev/null differ
diff --git a/public/images/types/steel.png b/public/images/types/steel.png
deleted file mode 100644
index 34e2ad73db8..00000000000
Binary files a/public/images/types/steel.png and /dev/null differ
diff --git a/public/images/types/stellar.png b/public/images/types/stellar.png
deleted file mode 100644
index 6ca5e5bdbc4..00000000000
Binary files a/public/images/types/stellar.png and /dev/null differ
diff --git a/public/images/types/unknown.png b/public/images/types/unknown.png
deleted file mode 100644
index 607111adefb..00000000000
Binary files a/public/images/types/unknown.png and /dev/null differ
diff --git a/public/images/types/water.png b/public/images/types/water.png
deleted file mode 100644
index eb618008d00..00000000000
Binary files a/public/images/types/water.png and /dev/null differ
diff --git a/public/images/types_pt_BR.json b/public/images/types_pt-BR.json
similarity index 99%
rename from public/images/types_pt_BR.json
rename to public/images/types_pt-BR.json
index 932d316fd30..e89bdcba87f 100644
--- a/public/images/types_pt_BR.json
+++ b/public/images/types_pt-BR.json
@@ -1,7 +1,7 @@
{
"textures": [
{
- "image": "types_pt_BR.png",
+ "image": "types_pt-BR.png",
"format": "RGBA8888",
"size": {
"w": 32,
diff --git a/public/images/types_pt_BR.png b/public/images/types_pt-BR.png
similarity index 100%
rename from public/images/types_pt_BR.png
rename to public/images/types_pt-BR.png
diff --git a/public/images/types_zh_CN.json b/public/images/types_zh-CN.json
similarity index 99%
rename from public/images/types_zh_CN.json
rename to public/images/types_zh-CN.json
index 4cd0135a677..e82d3c56468 100644
--- a/public/images/types_zh_CN.json
+++ b/public/images/types_zh-CN.json
@@ -1,7 +1,7 @@
{
"textures": [
{
- "image": "types_zh_CN.png",
+ "image": "types_zh-CN.png",
"format": "RGBA8888",
"size": {
"w": 32,
diff --git a/public/images/types_zh_CN.png b/public/images/types_zh-CN.png
similarity index 100%
rename from public/images/types_zh_CN.png
rename to public/images/types_zh-CN.png
diff --git a/public/images/types_zh_TW.json b/public/images/types_zh-TW.json
similarity index 99%
rename from public/images/types_zh_TW.json
rename to public/images/types_zh-TW.json
index e3923b00f02..18c51ab61f4 100644
--- a/public/images/types_zh_TW.json
+++ b/public/images/types_zh-TW.json
@@ -1,7 +1,7 @@
{
"textures": [
{
- "image": "types_zh_TW.png",
+ "image": "types_zh-TW.png",
"format": "RGBA8888",
"size": {
"w": 32,
diff --git a/public/images/types_zh_TW.png b/public/images/types_zh-TW.png
similarity index 100%
rename from public/images/types_zh_TW.png
rename to public/images/types_zh-TW.png
diff --git a/public/images/ui/legacy/summary_moves_effect_pt_BR.png b/public/images/ui/legacy/summary_moves_effect_pt-BR.png
similarity index 100%
rename from public/images/ui/legacy/summary_moves_effect_pt_BR.png
rename to public/images/ui/legacy/summary_moves_effect_pt-BR.png
diff --git a/public/images/ui/legacy/summary_moves_effect_zh_CN.png b/public/images/ui/legacy/summary_moves_effect_zh-CN.png
similarity index 100%
rename from public/images/ui/legacy/summary_moves_effect_zh_CN.png
rename to public/images/ui/legacy/summary_moves_effect_zh-CN.png
diff --git a/src/@types/i18next.d.ts b/src/@types/i18next.d.ts
index 0c76c169b51..c4a867b9d73 100644
--- a/src/@types/i18next.d.ts
+++ b/src/@types/i18next.d.ts
@@ -1,4 +1,4 @@
-import { AbilityTranslationEntries, SimpleTranslationEntries, AchievementTranslationEntries, BerryTranslationEntries, DialogueTranslationEntries, ModifierTypeTranslationEntries, MoveTranslationEntries, PokemonInfoTranslationEntries } from "#app/interfaces/locales";
+import { AbilityTranslationEntries, SimpleTranslationEntries, AchievementTranslationEntries, BerryTranslationEntries, DialogueTranslationEntries, ModifierTypeTranslationEntries, MoveTranslationEntries, PokemonInfoTranslationEntries, TranslationEntries } from "#app/interfaces/locales";
// Module declared to make referencing keys in the localization files type-safe.
declare module "i18next" {
@@ -14,6 +14,7 @@ declare module "i18next" {
biome: SimpleTranslationEntries;
challenges: SimpleTranslationEntries;
commandUiHandler: SimpleTranslationEntries;
+ common: TranslationEntries;
PGMachv: AchievementTranslationEntries;
PGFachv: AchievementTranslationEntries;
PGMdialogue: DialogueTranslationEntries;
diff --git a/src/battle-scene.ts b/src/battle-scene.ts
index 163ca41a406..43224ab074b 100644
--- a/src/battle-scene.ts
+++ b/src/battle-scene.ts
@@ -3,6 +3,7 @@ import UI from "./ui/ui";
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
+import { Constructor } from "#app/utils";
import * as Utils from "./utils";
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball";
@@ -2340,8 +2341,14 @@ export default class BattleScene extends SceneBase {
return false;
}
- getModifiers(modifierType: { new(...args: any[]): Modifier }, player: boolean = true): PersistentModifier[] {
- return (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType);
+ /**
+ * Get all of the modifiers that match `modifierType`
+ * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
+ * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
+ * @returns the list of all modifiers that matched `modifierType`.
+ */
+ getModifiers(modifierType: Constructor, player: boolean = true): T[] {
+ return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType);
}
findModifiers(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier[] {
@@ -2352,7 +2359,7 @@ export default class BattleScene extends SceneBase {
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m));
}
- applyShuffledModifiers(scene: BattleScene, modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier[] {
+ applyShuffledModifiers(scene: BattleScene, modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier[] {
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
scene.executeWithSeedOffset(() => {
const shuffleModifiers = mods => {
@@ -2367,7 +2374,7 @@ export default class BattleScene extends SceneBase {
return this.applyModifiersInternal(modifiers, player, args);
}
- applyModifiers(modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier[] {
+ applyModifiers(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier[] {
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
return this.applyModifiersInternal(modifiers, player, args);
}
@@ -2384,7 +2391,7 @@ export default class BattleScene extends SceneBase {
return appliedModifiers;
}
- applyModifier(modifierType: { new(...args: any[]): Modifier }, player: boolean = true, ...args: any[]): PersistentModifier {
+ applyModifier(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier {
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
for (const modifier of modifiers) {
if (modifier.apply(args)) {
@@ -2396,7 +2403,7 @@ export default class BattleScene extends SceneBase {
return null;
}
- triggerPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: { new(...args: any[]): SpeciesFormChangeTrigger }, delayed: boolean = false, modal: boolean = false): boolean {
+ triggerPokemonFormChange(pokemon: Pokemon, formChangeTriggerType: Constructor, delayed: boolean = false, modal: boolean = false): boolean {
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)) {
const matchingFormChange = pokemonFormChanges[pokemon.species.speciesId].find(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
if (matchingFormChange) {
@@ -2420,7 +2427,7 @@ export default class BattleScene extends SceneBase {
return false;
}
- validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void {
+ validateAchvs(achvType: Constructor, ...args: unknown[]): void {
const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType);
for (const achv of filteredAchvs) {
this.validateAchv(achv, args);
diff --git a/src/data/ability.ts b/src/data/ability.ts
index f003bdb48c6..80b569fc72a 100644
--- a/src/data/ability.ts
+++ b/src/data/ability.ts
@@ -1,5 +1,6 @@
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
import { Type } from "./type";
+import { Constructor } from "#app/utils";
import * as Utils from "../utils";
import { BattleStat, getBattleStatName } from "./battle-stat";
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
@@ -61,7 +62,7 @@ export class Ability implements Localizable {
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns Array of attributes that match `attrType`, Empty Array if none match.
*/
- getAttrs(attrType: new(...args: any[]) => T ): T[] {
+ getAttrs(attrType: Constructor ): T[] {
return this.attrs.filter((a): a is T => a instanceof attrType);
}
@@ -70,18 +71,18 @@ export class Ability implements Localizable {
* @param attrType any attribute that extends {@linkcode AbAttr}
* @returns true if the ability has attribute `attrType`
*/
- hasAttr(attrType: new(...args: any[]) => T): boolean {
+ hasAttr(attrType: Constructor): boolean {
return this.attrs.some((attr) => attr instanceof attrType);
}
- attr AbAttr>(AttrType: T, ...args: ConstructorParameters): Ability {
+ attr>(AttrType: T, ...args: ConstructorParameters): Ability {
const attr = new AttrType(...args);
this.attrs.push(attr);
return this;
}
- conditionalAttr AbAttr>(condition: AbAttrCondition, AttrType: T, ...args: ConstructorParameters): Ability {
+ conditionalAttr>(condition: AbAttrCondition, AttrType: T, ...args: ConstructorParameters): Ability {
const attr = new AttrType(...args);
attr.addCondition(condition);
this.attrs.push(attr);
@@ -2342,7 +2343,7 @@ export class BlockNonDirectDamageAbAttr extends AbAttr {
/**
* This attribute will block any status damage that you put in the parameter.
*/
-export class BlockStatusDamageAbAttr extends BlockNonDirectDamageAbAttr {
+export class BlockStatusDamageAbAttr extends AbAttr {
private effects: StatusEffect[];
/**
@@ -2362,7 +2363,7 @@ export class BlockStatusDamageAbAttr extends BlockNonDirectDamageAbAttr {
* @returns Returns true if status damage is blocked
*/
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
- if (this.effects.includes(pokemon.status.effect)) {
+ if (this.effects.includes(pokemon.status?.effect)) {
cancelled.value = true;
return true;
}
@@ -2476,6 +2477,9 @@ function getSheerForceHitDisableAbCondition(): AbAttrCondition {
function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
return (pokemon: Pokemon) => {
+ if (!pokemon.scene?.arena) {
+ return false;
+ }
if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) {
return false;
}
@@ -3720,13 +3724,21 @@ export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAtt
}
/**
- * Applies immunity to physical moves.
+ * Takes no damage from the first hit of a physical move.
* This is used in Ice Face ability.
*/
-export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
+export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
+ private multiplier: number;
+
+ constructor(condition: PokemonDefendCondition, multiplier: number) {
+ super(condition, multiplier);
+
+ this.multiplier = multiplier;
+ }
+
/**
* Applies the Ice Face pre-defense ability to the Pokémon.
- * Removes BattlerTagType.ICE_FACE hit by physical attack and is in Ice Face form.
+ * Removes BattlerTagType.ICE_FACE when hit by physical attack and is in Ice Face form.
*
* @param {Pokemon} pokemon - The Pokémon with the Ice Face ability.
* @param {boolean} passive - Whether the ability is passive.
@@ -3737,16 +3749,13 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
* @returns {boolean} - Whether the immunity was applied.
*/
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
- const isImmune = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args);
-
- if (isImmune) {
- const simulated = args.length > 1 && args[1];
- if (!simulated) {
- pokemon.removeTag(BattlerTagType.ICE_FACE);
- }
+ if (this.condition(pokemon, attacker, move)) {
+ (args[0] as Utils.NumberHolder).value = this.multiplier;
+ pokemon.removeTag(BattlerTagType.ICE_FACE);
+ return true;
}
- return isImmune;
+ return false;
}
/**
@@ -3761,7 +3770,7 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
}
}
-function applyAbAttrsInternal(attrType: { new(...args: any[]): TAttr },
+function applyAbAttrsInternal(attrType: Constructor,
pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise {
return new Promise(resolve => {
if (!pokemon.canApplyAbility(passive)) {
@@ -3776,7 +3785,7 @@ function applyAbAttrsInternal(attrType: { new(...args: any
const attrs = ability.getAttrs(attrType);
const clearSpliceQueueAndResolve = () => {
- pokemon.scene.clearPhaseQueueSplice();
+ pokemon.scene?.clearPhaseQueueSplice();
if (!passive) {
return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
} else {
@@ -3839,32 +3848,32 @@ function applyAbAttrsInternal(attrType: { new(...args: any
});
}
-export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
+export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args);
}
-export function applyPostBattleInitAbAttrs(attrType: { new(...args: any[]): PostBattleInitAbAttr },
+export function applyPostBattleInitAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, args), args);
}
-export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr },
+export function applyPreDefendAbAttrs(attrType: Constructor,
pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
const simulated = args.length > 1 && args[1];
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, false, simulated);
}
-export function applyPostDefendAbAttrs(attrType: { new(...args: any[]): PostDefendAbAttr },
+export function applyPostDefendAbAttrs(attrType: Constructor,
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
}
-export function applyPostMoveUsedAbAttrs(attrType: { new(...args: any[]): PostMoveUsedAbAttr },
+export function applyPostMoveUsedAbAttrs(attrType: Constructor,
pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, args), args);
}
-export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): BattleStatMultiplierAbAttr },
+export function applyBattleStatMultiplierAbAttrs(attrType: Constructor,
pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args);
}
@@ -3879,98 +3888,98 @@ export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[])
* @param hasApplied {@linkcode Utils.BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat
* @param args unused
*/
-export function applyFieldBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): FieldMultiplyBattleStatAbAttr },
+export function applyFieldBattleStatMultiplierAbAttrs(attrType: Constructor,
pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, stat, statValue, checkedPokemon, hasApplied, args), args);
}
-export function applyPreAttackAbAttrs(attrType: { new(...args: any[]): PreAttackAbAttr },
+export function applyPreAttackAbAttrs(attrType: Constructor,
pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
}
-export function applyPostAttackAbAttrs(attrType: { new(...args: any[]): PostAttackAbAttr },
+export function applyPostAttackAbAttrs(attrType: Constructor,
pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args);
}
-export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr },
+export function applyPostKnockOutAbAttrs(attrType: Constructor,
pokemon: Pokemon, knockedOut: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, knockedOut, args), args);
}
-export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr },
+export function applyPostVictoryAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, args), args);
}
-export function applyPostSummonAbAttrs(attrType: { new(...args: any[]): PostSummonAbAttr },
+export function applyPostSummonAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, args), args);
}
-export function applyPreSwitchOutAbAttrs(attrType: { new(...args: any[]): PreSwitchOutAbAttr },
+export function applyPreSwitchOutAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, false, true);
}
-export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreStatChangeAbAttr },
+export function applyPreStatChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
}
-export function applyPostStatChangeAbAttrs(attrType: { new(...args: any[]): PostStatChangeAbAttr },
+export function applyPostStatChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, stats, levels, selfTarget, args), args);
}
-export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
+export function applyPreSetStatusAbAttrs(attrType: Constructor,
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
const simulated = args.length > 1 && args[1];
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, false, !simulated);
}
-export function applyPreApplyBattlerTagAbAttrs(attrType: { new(...args: any[]): PreApplyBattlerTagAbAttr },
+export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor,
pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, tag, cancelled, args), args);
}
-export function applyPreWeatherEffectAbAttrs(attrType: { new(...args: any[]): PreWeatherEffectAbAttr },
+export function applyPreWeatherEffectAbAttrs(attrType: Constructor,
pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, false, true);
}
-export function applyPostTurnAbAttrs(attrType: { new(...args: any[]): PostTurnAbAttr },
+export function applyPostTurnAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, args), args);
}
-export function applyPostWeatherChangeAbAttrs(attrType: { new(...args: any[]): PostWeatherChangeAbAttr },
+export function applyPostWeatherChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, weather: WeatherType, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, weather, args), args);
}
-export function applyPostWeatherLapseAbAttrs(attrType: { new(...args: any[]): PostWeatherLapseAbAttr },
+export function applyPostWeatherLapseAbAttrs(attrType: Constructor,
pokemon: Pokemon, weather: Weather, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args);
}
-export function applyPostTerrainChangeAbAttrs(attrType: { new(...args: any[]): PostTerrainChangeAbAttr },
+export function applyPostTerrainChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, terrain: TerrainType, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, terrain, args), args);
}
-export function applyCheckTrappedAbAttrs(attrType: { new(...args: any[]): CheckTrappedAbAttr },
+export function applyCheckTrappedAbAttrs(attrType: Constructor,
pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, true);
}
-export function applyPostBattleAbAttrs(attrType: { new(...args: any[]): PostBattleAbAttr },
+export function applyPostBattleAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, args), args);
}
-export function applyPostFaintAbAttrs(attrType: { new(...args: any[]): PostFaintAbAttr },
+export function applyPostFaintAbAttrs(attrType: Constructor,
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args);
}
@@ -4807,7 +4816,7 @@ export function initAbilities() {
.conditionalAttr(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW), PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0)
// When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE
.attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW)
- .attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE))
+ .attr(IceFaceBlockPhysicalAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0)
.ignorable(),
new Ability(Abilities.POWER_SPOT, 8)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3),
diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts
index db02803c5ea..4e2a4e06d3c 100644
--- a/src/data/battler-tags.ts
+++ b/src/data/battler-tags.ts
@@ -17,6 +17,7 @@ import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
+import i18next from "#app/plugins/i18n.js";
export enum BattlerTagLapseType {
FAINT,
@@ -105,7 +106,7 @@ export class RechargingTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
super.lapse(pokemon, lapseType);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " must\nrecharge!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsRechargingLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
pokemon.getMoveQueue().shift();
@@ -134,7 +135,10 @@ export class TrappedTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` was freed\nfrom ${this.getMoveName()}!`));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsTrappedOnRemove", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ moveName: this.getMoveName()
+ }));
}
getDescriptor(): string {
@@ -146,7 +150,7 @@ export class TrappedTag extends BattlerTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, " can no\nlonger escape!");
+ return i18next.t("battle:battlerTagsTrappedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
}
}
@@ -169,7 +173,7 @@ export class FlinchedTag extends BattlerTag {
super.lapse(pokemon, lapseType);
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " flinched!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsFlinchedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
return true;
}
@@ -218,26 +222,26 @@ export class ConfusedTag extends BattlerTag {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " became\nconfused!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " snapped\nout of confusion!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready confused!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM && super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nconfused!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
// 1/3 chance of hitting self with a 40 base power move
@@ -245,7 +249,7 @@ export class ConfusedTag extends BattlerTag {
const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
- pokemon.scene.queueMessage("It hurt itself in its\nconfusion!");
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsConfusedLapseHurtItself"));
pokemon.damageAndUpdate(damage);
pokemon.battleData.hitCount++;
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
@@ -292,14 +296,17 @@ export class DestinyBondTag extends BattlerTag {
return false;
}
- const targetMessage = getPokemonMessage(pokemon, "");
-
if (pokemon.isBossImmune()) {
- pokemon.scene.queueMessage(`${targetMessage} is unaffected\nby the effects of Destiny Bond.`);
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsDestinyBondLapseIsBoss", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
return false;
}
- pokemon.scene.queueMessage(`${getPokemonMessage(source, ` took\n${targetMessage} down with it!`)}`);
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsDestinyBondLapse", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(source),
+ pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon)
+ })
+ );
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, false, true);
return false;
}
@@ -317,24 +324,34 @@ export class InfatuatedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` fell in love\nwith ${pokemon.scene.getPokemonById(this.sourceId).name}!`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsInfatuatedOnAdd", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
+ })
+ );
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready in love!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is in love\nwith ${pokemon.scene.getPokemonById(this.sourceId).name}!`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsInfatuatedLapse", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
+ })
+ );
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
if (pokemon.randSeedInt(2)) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nimmobilized by love!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedLapseImmobilize", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
}
}
@@ -345,7 +362,7 @@ export class InfatuatedTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " got over\nits infatuation."));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsInfatuatedOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
isSourceLinked(): boolean {
@@ -380,7 +397,7 @@ export class SeedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was seeded!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSeededOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
}
@@ -400,7 +417,7 @@ export class SeedTag extends BattlerTag {
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1,
- !reverseDrain ? getPokemonMessage(pokemon, "'s health is\nsapped by Leech Seed!") : getPokemonMessage(source, "'s Leech Seed\nsucked up the liquid ooze!"),
+ !reverseDrain ? i18next.t("battle:battlerTagsSeededLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }) : i18next.t("battle:battlerTagsSeededLapseShed", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
false, true));
}
}
@@ -422,20 +439,20 @@ export class NightmareTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " began\nhaving a Nightmare!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nalready locked in a Nightmare!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareOnOverlap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is locked\nin a Nightmare!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsNightmareLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
const cancelled = new Utils.BooleanHolder(false);
@@ -527,7 +544,7 @@ export class EncoreTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " got\nan Encore!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEncoreOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon);
if (movePhase) {
@@ -543,7 +560,7 @@ export class EncoreTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, "'s Encore\nended!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEncoreOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}
@@ -553,7 +570,12 @@ export class HelpingHandTag extends BattlerTag {
}
onAdd(pokemon: Pokemon): void {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` is ready to\nhelp ${pokemon.name}!`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsHelpingHandOnAdd", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
+ pokemonName: pokemon.name
+ })
+ );
}
}
@@ -581,15 +603,22 @@ export class IngrainTag extends TrappedTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), Math.floor(pokemon.getMaxHp() / 16),
- getPokemonMessage(pokemon, " absorbed\nnutrients with its roots!"), true));
+ pokemon.scene.unshiftPhase(
+ new PokemonHealPhase(
+ pokemon.scene,
+ pokemon.getBattlerIndex(),
+ Math.floor(pokemon.getMaxHp() / 16),
+ i18next.t("battle:battlerTagsIngrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
+ true
+ )
+ );
}
return ret;
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, " planted its roots!");
+ return i18next.t("battle:battlerTagsIngrainOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
}
getDescriptor(): string {
@@ -605,15 +634,23 @@ export class AquaRingTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " surrounded\nitself with a veil of water!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsAquaRingOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
- Math.floor(pokemon.getMaxHp() / 16), `${this.getMoveName()} restored\n${pokemon.name}\'s HP!`, true));
+ pokemon.scene.unshiftPhase(
+ new PokemonHealPhase(
+ pokemon.scene,
+ pokemon.getBattlerIndex(),
+ Math.floor(pokemon.getMaxHp() / 16),
+ i18next.t("battle:battlerTagsAquaRingLapse", {
+ moveName: this.getMoveName(),
+ pokemonName: pokemon.name
+ }),
+ true));
}
return ret;
@@ -659,7 +696,7 @@ export class DrowsyTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " grew drowsy!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsDrowsyOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@@ -702,7 +739,12 @@ export abstract class DamagingTrapTag extends TrappedTag {
const ret = super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby ${this.getMoveName()}!`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsDamagingTrapLapse", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ moveName: this.getMoveName()
+ })
+ );
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
const cancelled = new Utils.BooleanHolder(false);
@@ -723,7 +765,11 @@ export class BindTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, ` was squeezed by\n${pokemon.scene.getPokemonById(this.sourceId).name}'s ${this.getMoveName()}!`);
+ return i18next.t("battle:battlerTagsBindOnTrap", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name,
+ moveName: this.getMoveName()
+ });
}
}
@@ -733,7 +779,10 @@ export class WrapTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, ` was Wrapped\nby ${pokemon.scene.getPokemonById(this.sourceId).name}!`);
+ return i18next.t("battle:battlerTagsWrapOnTrap", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonName: pokemon.scene.getPokemonById(this.sourceId).name
+ });
}
}
@@ -743,7 +792,7 @@ export abstract class VortexTrapTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, " was trapped\nin the vortex!");
+ return i18next.t("battle:battlerTagsVortexOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
}
}
@@ -765,7 +814,10 @@ export class ClampTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` Clamped\n${pokemon.name}!`);
+ return i18next.t("battle:battlerTagsClampOnTrap", {
+ sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
+ pokemonName: pokemon.name,
+ });
}
}
@@ -775,7 +827,10 @@ export class SandTombTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, ` became trapped\nby ${this.getMoveName()}!`);
+ return i18next.t("battle:battlerTagsSandTombOnTrap", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ moveName: this.getMoveName()
+ });
}
}
@@ -785,7 +840,7 @@ export class MagmaStormTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, " became trapped\nby swirling magma!");
+ return i18next.t("battle:battlerTagsMagmaStormOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
}
}
@@ -795,7 +850,7 @@ export class SnapTrapTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, " got trapped\nby a snap trap!");
+ return i18next.t("battle:battlerTagsSnapTrapOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
}
}
@@ -805,7 +860,10 @@ export class ThunderCageTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon.scene.getPokemonById(this.sourceId), ` trapped\n${getPokemonNameWithAffix(pokemon)}!`);
+ return i18next.t("battle:battlerTagsThunderCageOnTrap", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
+ });
}
}
@@ -815,7 +873,10 @@ export class InfestationTag extends DamagingTrapTag {
}
getTrapMessage(pokemon: Pokemon): string {
- return getPokemonMessage(pokemon, ` has been afflicted \nwith an infestation by ${getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))}!`);
+ return i18next.t("battle:battlerTagsInfestationOnTrap", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
+ });
}
}
@@ -828,13 +889,13 @@ export class ProtectedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, "\nprotected itself!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsProtectedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play(pokemon.scene);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, "\nprotected itself!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsProtectedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
return true;
}
@@ -959,12 +1020,12 @@ export class EnduringTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " braced\nitself!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEnduringOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " endured\nthe hit!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsEnduringLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
return true;
}
@@ -979,7 +1040,7 @@ export class SturdyTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " endured\nthe hit!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSturdyLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
return true;
}
@@ -1000,7 +1061,12 @@ export class PerishSongTag extends BattlerTag {
const ret = super.lapse(pokemon, lapseType);
if (ret) {
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, `\'s perish count fell to ${this.turnCount}.`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsPerishSongLapse", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ turnCount: this.turnCount
+ })
+ );
} else {
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, true, true);
}
@@ -1071,7 +1137,7 @@ export class TruantTag extends AbilityBattlerTag {
if (lastMove && lastMove.move !== Moves.NONE) {
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive));
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nloafing around!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsTruantLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
return true;
@@ -1086,7 +1152,7 @@ export class SlowStartTag extends AbilityBattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " can't\nget it going!"), null, false, null, true);
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSlowStartOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, false, null, true);
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@@ -1100,7 +1166,7 @@ export class SlowStartTag extends AbilityBattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " finally\ngot its act together!"), null, false, null);
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSlowStartOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, false, null);
}
}
@@ -1146,13 +1212,13 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
break;
}
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, `'s ${getStatName(highestStat)}\nwas heightened!`), null, false, null, true);
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsHighestStatBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), statName: getStatName(highestStat) }), null, false, null, true);
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(`The effects of ${getPokemonMessage(pokemon, `'s\n${allAbilities[this.ability].name} wore off!`)}`);
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsHighestStatBoostOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: allAbilities[this.ability].name }));
}
}
@@ -1286,7 +1352,7 @@ export class CritBoostTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is getting\npumped!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCritBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@@ -1296,7 +1362,7 @@ export class CritBoostTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " relaxed."));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCritBoostOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}
@@ -1331,7 +1397,7 @@ export class SaltCuredTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is being salt cured!"));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSaltCuredOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
}
@@ -1348,7 +1414,12 @@ export class SaltCuredTag extends BattlerTag {
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
+ pokemon.scene.queueMessage(
+ i18next.t("battle:battlerTagsSaltCuredLapse", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
+ moveName: this.getMoveName()
+ })
+ );
}
}
@@ -1374,8 +1445,6 @@ export class CursedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
-
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, " has been cursed!"));
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
}
@@ -1390,7 +1459,7 @@ export class CursedTag extends BattlerTag {
if (!cancelled.value) {
pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1));
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by the ${this.getMoveName()}!`));
+ pokemon.scene.queueMessage(i18next.t("battle:battlerTagsCursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}
diff --git a/src/data/challenge.ts b/src/data/challenge.ts
index 5c689ef7345..75b200b24ee 100644
--- a/src/data/challenge.ts
+++ b/src/data/challenge.ts
@@ -12,6 +12,7 @@ import { pokemonFormChanges } from "./pokemon-forms";
import { Challenges } from "#enums/challenges";
import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type";
+import { TypeColor, TypeShadow } from "#app/enums/color.js";
/**
* An enum for all the challenge types. The parameter entries on these describe the
@@ -160,7 +161,7 @@ export abstract class Challenge {
if (overrideValue === undefined) {
overrideValue = this.value;
}
- return i18next.t(`challenges:${this.geti18nKey()}.desc.${this.value}`);
+ return `${i18next.t("challenges:usePokemon")}${i18next.t(`challenges:${this.geti18nKey()}.desc.${this.value}`)}`;
}
/**
@@ -347,6 +348,37 @@ export class SingleGenerationChallenge extends Challenge {
return this.value > 0 ? 1 : 0;
}
+ /**
+ * Returns the textual representation of a challenge's current value.
+ * @param {value} overrideValue The value to check for. If undefined, gets the current value.
+ * @returns {string} The localised name for the current value.
+ */
+ getValue(overrideValue?: integer): string {
+ if (overrideValue === undefined) {
+ overrideValue = this.value;
+ }
+ if (this.value === 0) {
+ return i18next.t("settings:off");
+ }
+ return i18next.t(`starterSelectUiHandler:gen${this.value}`);
+ }
+
+ /**
+ * Returns the description of a challenge's current value.
+ * @param {value} overrideValue The value to check for. If undefined, gets the current value.
+ * @returns {string} The localised description for the current value.
+ */
+ getDescription(overrideValue?: integer): string {
+ if (overrideValue === undefined) {
+ overrideValue = this.value;
+ }
+ if (this.value === 0) {
+ return i18next.t("challenges:singleGeneration.desc_default");
+ }
+ return i18next.t("challenges:singleGeneration.desc", { gen: i18next.t(`challenges:singleGeneration.gen_${this.value}`) });
+ }
+
+
static loadChallenge(source: SingleGenerationChallenge | any): SingleGenerationChallenge {
const newChallenge = new SingleGenerationChallenge();
newChallenge.value = source.value;
@@ -438,6 +470,34 @@ export class SingleTypeChallenge extends Challenge {
return this.value > 0 ? 1 : 0;
}
+ /**
+ * Returns the textual representation of a challenge's current value.
+ * @param {value} overrideValue The value to check for. If undefined, gets the current value.
+ * @returns {string} The localised name for the current value.
+ */
+ getValue(overrideValue?: integer): string {
+ if (overrideValue === undefined) {
+ overrideValue = this.value;
+ }
+ return Type[this.value - 1].toLowerCase();
+ }
+
+ /**
+ * Returns the description of a challenge's current value.
+ * @param {value} overrideValue The value to check for. If undefined, gets the current value.
+ * @returns {string} The localised description for the current value.
+ */
+ getDescription(overrideValue?: integer): string {
+ if (overrideValue === undefined) {
+ overrideValue = this.value;
+ }
+ const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`);
+ const typeColor = `[color=${TypeColor[Type[this.value-1]]}][shadow=${TypeShadow[Type[this.value-1]]}]${type}[/shadow][/color]`;
+ const defaultDesc = i18next.t("challenges:singleType.desc_default");
+ const typeDesc = i18next.t("challenges:singleType.desc", {type: typeColor});
+ return this.value === 0 ? defaultDesc : typeDesc;
+ }
+
static loadChallenge(source: SingleTypeChallenge | any): SingleTypeChallenge {
const newChallenge = new SingleTypeChallenge();
newChallenge.value = source.value;
diff --git a/src/data/move.ts b/src/data/move.ts
index 7f0d9187847..c8d1b5f9f4d 100644
--- a/src/data/move.ts
+++ b/src/data/move.ts
@@ -2,10 +2,11 @@ import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./
import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
import { BattleStat, getBattleStatName } from "./battle-stat";
import { EncoreTag } from "./battler-tags";
-import { getPokemonMessage } from "../messages";
+import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect";
import { Type } from "./type";
+import { Constructor } from "#app/utils";
import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
@@ -156,7 +157,7 @@ export default class Move implements Localizable {
* @param attrType any attribute that extends {@linkcode MoveAttr}
* @returns Array of attributes that match `attrType`, Empty Array if none match.
*/
- getAttrs(attrType: new(...args: any[]) => T): T[] {
+ getAttrs(attrType: Constructor): T[] {
return this.attrs.filter((a): a is T => a instanceof attrType);
}
@@ -165,7 +166,7 @@ export default class Move implements Localizable {
* @param attrType any attribute that extends {@linkcode MoveAttr}
* @returns true if the move has attribute `attrType`
*/
- hasAttr(attrType: new(...args: any[]) => T): boolean {
+ hasAttr(attrType: Constructor): boolean {
return this.attrs.some((attr) => attr instanceof attrType);
}
@@ -185,7 +186,7 @@ export default class Move implements Localizable {
* @param args the args needed to instantiate a the given class
* @returns the called object {@linkcode Move}
*/
- attr MoveAttr>(AttrType: T, ...args: ConstructorParameters): this {
+ attr>(AttrType: T, ...args: ConstructorParameters): this {
const attr = new AttrType(...args);
this.attrs.push(attr);
let attrCondition = attr.getCondition();
@@ -3963,6 +3964,8 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
return -3;
case BattlerTagType.ENCORE:
return -2;
+ case BattlerTagType.MINIMIZED:
+ return 0;
case BattlerTagType.INGRAIN:
case BattlerTagType.IGNORE_ACCURACY:
case BattlerTagType.AQUA_RING:
@@ -3994,7 +3997,13 @@ export class CurseAttr extends MoveEffectAttr {
}
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
- user.scene.queueMessage(getPokemonMessage(user, ` cut its own HP\nand laid a curse on the ${target.name}!`));
+ user.scene.queueMessage(
+ i18next.t("battle:battlerTagsCursedOnAdd", {
+ pokemonNameWithAffix: getPokemonNameWithAffix(user),
+ pokemonName: target.name
+ })
+ );
+
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
return true;
} else {
@@ -5283,7 +5292,16 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
}
}
+/**
+ * Attribute used for moves that suppress abilities like {@linkcode Moves.GASTRO_ACID}.
+ * A suppressed ability cannot be activated.
+ *
+ * @extends MoveEffectAttr
+ * @see {@linkcode apply}
+ * @see {@linkcode getCondition}
+ */
export class SuppressAbilitiesAttr extends MoveEffectAttr {
+ /** Sets ability suppression for the target pokemon and displays a message. */
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args)) {
return false;
@@ -5296,8 +5314,9 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
return true;
}
+ /** Causes the effect to fail when the target's ability is unsupressable or already suppressed. */
getCondition(): MoveConditionFunc {
- return (user, target, move) => !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr);
+ return (user, target, move) => !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !target.summonData.abilitySuppressed;
}
}
@@ -5312,7 +5331,7 @@ export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr {
* abillity cannot be suppressed. This is a secondary effect and has no bearing on the success or failure of the move.
*
* @returns True if the move occurred, otherwise false. Note that true will be returned even if the target has not
- * yet moved or if the target's abiilty is un-suppressable.
+ * yet moved or if the suppression failed to apply.
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args)) {
@@ -5491,7 +5510,7 @@ function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon, targe
});
}
-export function applyMoveAttrs(attrType: { new(...args: any[]): MoveAttr }, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise {
+export function applyMoveAttrs(attrType: Constructor, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise {
return applyMoveAttrsInternal((attr: MoveAttr) => attr instanceof attrType, user, target, move, args);
}
@@ -7982,6 +8001,7 @@ export function initMoves() {
new AttackMove(Moves.CHLOROBLAST, Type.GRASS, MoveCategory.SPECIAL, 150, 95, 5, -1, 0, 8)
.attr(RecoilAttr, true, 0.5),
new AttackMove(Moves.MOUNTAIN_GALE, Type.ICE, MoveCategory.PHYSICAL, 100, 85, 10, 30, 0, 8)
+ .makesContact(false)
.attr(FlinchAttr),
new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true)
diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts
index cc05af50f6f..ad93bec44e4 100644
--- a/src/data/pokemon-forms.ts
+++ b/src/data/pokemon-forms.ts
@@ -3,6 +3,7 @@ import Pokemon from "../field/pokemon";
import { SpeciesFormKey } from "./pokemon-species";
import { StatusEffect } from "./status-effect";
import { MoveCategory, allMoves } from "./move";
+import { Constructor } from "#app/utils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
@@ -178,7 +179,7 @@ export class SpeciesFormChange {
return true;
}
- findTrigger(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): SpeciesFormChangeTrigger {
+ findTrigger(triggerType: Constructor): SpeciesFormChangeTrigger {
if (!this.trigger.hasTriggerType(triggerType)) {
return null;
}
@@ -208,7 +209,7 @@ export abstract class SpeciesFormChangeTrigger {
return true;
}
- hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
+ hasTriggerType(triggerType: Constructor): boolean {
return this instanceof triggerType;
}
}
@@ -236,7 +237,7 @@ export class SpeciesFormChangeCompoundTrigger {
return true;
}
- hasTriggerType(triggerType: { new(...args: any[]): SpeciesFormChangeTrigger }): boolean {
+ hasTriggerType(triggerType: Constructor): boolean {
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
}
}
diff --git a/src/enums/color.ts b/src/enums/color.ts
new file mode 100644
index 00000000000..99c2d14cb63
--- /dev/null
+++ b/src/enums/color.ts
@@ -0,0 +1,83 @@
+export enum Color {
+ WHITE = "#ffffff",
+ OFF_WHITE = "#f8f8f8",
+ LIGHT_GREY = "#a0a0a0",
+ GREY = "#484848",
+ DARK_GREY = "#404040",
+ PINK = "#f89890",
+ RED = "#e13d3d",
+ RED2 = "#e70808",
+ REDORANGE = "#d64b00",
+ ORANGE = "#f8b050",
+ LIGHT_YELLOW = "#e8e8a8",
+ YELLOW = "#ccbe00",
+ DARK_YELLOW = "#a68e17",
+ GREEN = "#78c850",
+ BLUE = "#40c8f8",
+ COMMON = "#ffffff",
+ GREAT = "#3890f8",
+ ULTRA = "#f8d038",
+ ROGUE = "#d52929",
+ MASTER = "#e020c0",
+ LUXURY = "#e64a18"
+}
+
+export enum TypeColor {
+ NORMAL = "#ADA594",
+ FIGHTING = "#A55239",
+ FLYING = "#9CADF7",
+ POISON = "#9141CB",
+ GROUND = "#AE7A3B",
+ ROCK = "#BDA55A",
+ BUG = "#ADBD21",
+ GHOST = "#6363B5",
+ STEEL = "#81A6BE",
+ FIRE = "#F75231",
+ WATER = "#399CFF",
+ GRASS = "#7BCE52",
+ ELECTRIC = "#FFC631",
+ PSYCHIC = "#EF4179",
+ ICE = "#5ACEE7",
+ DRAGON = "#7B63E7",
+ DARK = "#735A4A",
+ FAIRY = "#EF70EF",
+}
+
+export enum TypeShadow {
+ NORMAL = "#574F4A",
+ FIGHTING = "#4E637C",
+ FLYING = "#4E637C",
+ POISON = "#352166",
+ GROUND = "#572D1E",
+ ROCK = "#5F442D",
+ BUG = "#5F5010",
+ GHOST = "#323D5B",
+ STEEL = "#415C5F",
+ FIRE = "#7C1818",
+ WATER = "#1C4E80",
+ GRASS = "#4F6729",
+ ELECTRIC = "#804618",
+ PSYCHIC = "#782155",
+ ICE = "#2D5C74",
+ DRAGON = "#313874",
+ DARK = "#392725",
+ FAIRY = "#663878",
+}
+
+export enum ShadowColor {
+ GREY = "#636363",
+ PURPLE = "#6b5a73",
+ LIGHT_GREY = "#d0d0c8",
+ BROWN = "#69402a",
+ PINK = "#fca2a2",
+ BRIGHT_RED = "#f83018",
+ RED = "#984038",
+ MAROON = "#632929",
+ GREEN = "#306850",
+ BLUE = "#006090",
+ LIGHT_YELLOW = "#ded6b5",
+ YELLOW = "#ebd773",
+ DARK_YELLOW = "#a0a060",
+ ORANGE = "#c07800",
+ LIGHT_ORANGE = "#ffbd73",
+}
diff --git a/src/events/arena.ts b/src/events/arena.ts
index 657acaeae7e..67b423f3b75 100644
--- a/src/events/arena.ts
+++ b/src/events/arena.ts
@@ -71,11 +71,18 @@ export class TagAddedEvent extends ArenaEvent {
public arenaTagType: ArenaTagType;
/** The {@linkcode ArenaTagSide} the tag is being placed on */
public arenaTagSide: ArenaTagSide;
- constructor(arenaTagType: ArenaTagType, arenaTagSide: ArenaTagSide, duration: number) {
+ /** The current number of layers of the arena trap. */
+ public arenaTagLayers: number;
+ /** The maximum amount of layers of the arena trap. */
+ public arenaTagMaxLayers: number;
+
+ constructor(arenaTagType: ArenaTagType, arenaTagSide: ArenaTagSide, duration: number, arenaTagLayers?: number, arenaTagMaxLayers?: number) {
super(ArenaEventType.TAG_ADDED, duration);
this.arenaTagType = arenaTagType;
this.arenaTagSide = arenaTagSide;
+ this.arenaTagLayers = arenaTagLayers;
+ this.arenaTagMaxLayers = arenaTagMaxLayers;
}
}
/**
diff --git a/src/field/arena.ts b/src/field/arena.ts
index 14280536a5f..a5e62872152 100644
--- a/src/field/arena.ts
+++ b/src/field/arena.ts
@@ -1,5 +1,6 @@
import BattleScene from "../battle-scene";
import { BiomePoolTier, PokemonPools, BiomeTierTrainerPools, biomePokemonPools, biomeTrainerPools } from "../data/biomes";
+import { Constructor } from "#app/utils";
import * as Utils from "../utils";
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
@@ -7,7 +8,7 @@ import { CommonAnimPhase } from "../phases";
import { CommonAnim } from "../data/battle-anims";
import { Type } from "../data/type";
import Move from "../data/move";
-import { ArenaTag, ArenaTagSide, getArenaTag } from "../data/arena-tag";
+import { ArenaTag, ArenaTagSide, ArenaTrapTag, getArenaTag } from "../data/arena-tag";
import { BattlerIndex } from "../battle";
import { Terrain, TerrainType } from "../data/terrain";
import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability";
@@ -535,7 +536,7 @@ export class Arena {
this.ignoreAbilities = ignoreAbilities;
}
- applyTagsForSide(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, side: ArenaTagSide, ...args: any[]): void {
+ applyTagsForSide(tagType: ArenaTagType | Constructor, side: ArenaTagSide, ...args: unknown[]): void {
let tags = typeof tagType === "string"
? this.tags.filter(t => t.tagType === tagType)
: this.tags.filter(t => t instanceof tagType);
@@ -545,7 +546,7 @@ export class Arena {
tags.forEach(t => t.apply(this, args));
}
- applyTags(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, ...args: any[]): void {
+ applyTags(tagType: ArenaTagType | Constructor, ...args: unknown[]): void {
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
}
@@ -553,6 +554,12 @@ export class Arena {
const existingTag = this.getTagOnSide(tagType, side);
if (existingTag) {
existingTag.onOverlap(this);
+
+ if (existingTag instanceof ArenaTrapTag) {
+ const { tagType, side, turnCount, layers, maxLayers } = existingTag as ArenaTrapTag;
+ this.eventTarget.dispatchEvent(new TagAddedEvent(tagType, side, turnCount, layers, maxLayers));
+ }
+
return false;
}
@@ -560,16 +567,18 @@ export class Arena {
this.tags.push(newTag);
newTag.onAdd(this, quiet);
- this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount));
+ const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {};
+
+ this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount, layers, maxLayers));
return true;
}
- getTag(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }): ArenaTag {
+ getTag(tagType: ArenaTagType | Constructor): ArenaTag {
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
}
- getTagOnSide(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, side: ArenaTagSide): ArenaTag {
+ getTagOnSide(tagType: ArenaTagType | Constructor, side: ArenaTagSide): ArenaTag {
return typeof(tagType) === "string"
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts
index 57a472585d5..034c487b467 100644
--- a/src/field/pokemon.ts
+++ b/src/field/pokemon.ts
@@ -5,6 +5,7 @@ import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, VariableMoveTypeAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, MoveFlags } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
+import { Constructor } from "#app/utils";
import * as Utils from "../utils";
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
import { getLevelTotalExp } from "../data/exp";
@@ -1064,7 +1065,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @param {boolean} ignoreOverride If true, it ignores ability changing effects
* @returns {boolean} Whether an ability with that attribute is present and active
*/
- hasAbilityWithAttr(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): boolean {
+ hasAbilityWithAttr(attrType: Constructor, canApply: boolean = true, ignoreOverride?: boolean): boolean {
if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).hasAttr(attrType)) {
return true;
}
@@ -2104,7 +2105,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
}
- getTag(tagType: BattlerTagType | { new(...args: any[]): BattlerTag }): BattlerTag {
+ getTag(tagType: BattlerTagType | Constructor): BattlerTag {
if (!this.summonData) {
return null;
}
@@ -2120,7 +2121,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.summonData.tags.find(t => tagFilter(t));
}
- getTags(tagType: BattlerTagType | { new(...args: any[]): BattlerTag }): BattlerTag[] {
+ getTags(tagType: BattlerTagType | Constructor): BattlerTag[] {
if (!this.summonData) {
return [];
}
@@ -3504,6 +3505,10 @@ export class EnemyPokemon extends Pokemon {
const target = this.scene.getField()[mt];
let targetScore = move.getUserBenefitScore(this, target, move) + move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1);
+ if (Number.isNaN(targetScore)) {
+ console.error(`Move ${move.name} returned score of NaN`);
+ targetScore = 0;
+ }
if ((move.name.endsWith(" (N)") || !move.applyConditions(this, target, move)) && ![Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP].includes(move.id)) {
targetScore = -20;
} else if (move instanceof AttackMove) {
diff --git a/src/form-change-phase.ts b/src/form-change-phase.ts
index f2cf9933b17..7d4e8349775 100644
--- a/src/form-change-phase.ts
+++ b/src/form-change-phase.ts
@@ -278,7 +278,7 @@ export class QuietFormChangePhase extends BattlePhase {
}
end(): void {
- if (this.pokemon.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon instanceof EnemyPokemon) {
+ if (this.pokemon.scene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon instanceof EnemyPokemon) {
this.scene.playBgm();
this.pokemon.summonData.battleStats = [ 0, 0, 0, 0, 0, 0, 0 ];
this.scene.unshiftPhase(new PokemonHealPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true));
diff --git a/src/interfaces/locales.ts b/src/interfaces/locales.ts
index 21fbda7c468..d9b3d71474d 100644
--- a/src/interfaces/locales.ts
+++ b/src/interfaces/locales.ts
@@ -2,6 +2,9 @@ export interface Localizable {
localize(): void;
}
+export interface TranslationEntries {
+ [key: string]: string | { [key: string]: string }
+}
export interface SimpleTranslationEntries {
[key: string]: string
}
diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts
index 09310ca02bc..760f17c0c9a 100644
--- a/src/locales/de/battle.ts
+++ b/src/locales/de/battle.ts
@@ -71,4 +71,61 @@ export const battle: SimpleTranslationEntries = {
"statSeverelyFell": "sinkt drastisch",
"statWontGoAnyLower": "kann nicht weiter sinken",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} kann sich wegen des Rückstoßes durch den Angriff nicht bewegen!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} kann nicht mehr fliehen!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} wurde von {{moveName}} befreit.",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} ist zurückgeschreckt und kann nicht handeln!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} wurde verwirrt!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} ist nicht mehr verwirrt!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} ist bereits verwirrt!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} ist verwirrt!",
+ "battlerTagsConfusedLapseHurtItself": "Es hat sich vor Verwirrung selbst verletzt!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} ist immun gegen den Effekt von Abgangsbund!",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} nimmt {{pokemonNameWithAffix2}} mit sich!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} hat sich in {{sourcePokemonName}} verliebt!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} ist bereits verliebt.",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} ist in {{sourcePokemonName}} verliebt!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} ist starr vor Liebe!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} ist nicht mehr verliebt!",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} wurde bepflanzt!",
+ "battlerTagsSeededLapse": "{{pokemonNameWithAffix}} wurden durch Egelsamen KP geraubt!",
+ "battlerTagsSeededLapseShed": "Egelsamen von {{pokemonNameWithAffix}} saugt Kloakensoße auf!",
+ "battlerTagsNightmareOnAdd": "Nachtmahr sucht {{pokemonNameWithAffix}} heim!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} wird bereits von Nachtmahr heimgesucht!",
+ "battlerTagsNightmareLapse": "Nachtmahr schadet {{pokemonNameWithAffix}}!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} gibt eine Zugabe",
+ "battlerTagsEncoreOnRemove": "Die Zugabe von {{pokemonNameWithAffix}} ist beendet!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} will {{pokemonName}} helfen!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} nimmt über seine Wurzeln Nährstoffe auf!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} pflanzt seine Wurzeln!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} umgibt sich mit einem Wasserring!",
+ "battlerTagsAquaRingLapse": "{{moveName}} füllt KP von {{pokemonName}} wieder auf!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} wurde schläfrig gemacht!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} wurde durch {{moveName}} von {{sourcePokemonName}} gequetscht!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} wurde von {{sourcePokemonName}} umwickelt!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} wird in dem Strudel gefangen!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} wurde von {{pokemonName}} geschnappt!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} wurde von {{moveName}} gefangen!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} wurde in wirbelndem Magma eingeschlossen!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} wurde durch Sandgrab gefangen!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} hat {{pokemonNameWithAffix}} gefangen!",
+ "battlerTagsInfestationOnTrap": "{{sourcePokemonNameWithAffix}} plagt {{pokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}} schützt sich selbst!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}} schützt sich selbst!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} sammelt sich, um die nächste Attacke zu überstehen!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} übersteht die Attacke!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} übersteht die Attacke!",
+ "battlerTagsPerishSongLapse": "Abgesang von {{pokemonNameWithAffix}} steht bei {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} faulenzt!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} kommt nicht in Fahrt!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} kriegt schließlich doch noch die Kurve!",
+ "battlerTagsHighestStatBoostOnAdd": "{{statName}} von {{pokemonNameWithAffix}} wird verstärkt!",
+ "battlerTagsHighestStatBoostOnRemove": "Der Effekt von {{abilityName}} von {{pokemonNameWithAffix}} lässt nach!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} läuft zu Hochtouren auf!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} entspannt.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} wurde eingepökelt!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} nimmt einen Teil seiner KP und legt einen Fluch auf {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} wurde durch den Fluch verletzt!"
} as const;
diff --git a/src/locales/de/challenges.ts b/src/locales/de/challenges.ts
index b3e878f4649..176de9879b6 100644
--- a/src/locales/de/challenges.ts
+++ b/src/locales/de/challenges.ts
@@ -1,67 +1,26 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "Herausforderungsmodifikatoren",
- "confirm_start": "Mit diesen Modifikatoren fortfahren?",
- "singleGeneration.name": "Mono-Generation",
- "singleGeneration.value.0": "Aus",
- "singleGeneration.desc.0": "Du kannst nur Pokémon aus der gewählten Generation verwenden.",
- "singleGeneration.value.1": "Generation 1",
- "singleGeneration.desc.1": "Du kannst nur Pokémon aus der ersten Generation verwenden.",
- "singleGeneration.value.2": "Generation 2",
- "singleGeneration.desc.2": "Du kannst nur Pokémon aus der zweiten Generation verwenden.",
- "singleGeneration.value.3": "Generation 3",
- "singleGeneration.desc.3": "Du kannst nur Pokémon aus der dritten Generation verwenden.",
- "singleGeneration.value.4": "Generation 4",
- "singleGeneration.desc.4": "Du kannst nur Pokémon aus der vierten Generation verwenden.",
- "singleGeneration.value.5": "Generation 5",
- "singleGeneration.desc.5": "Du kannst nur Pokémon aus der fünften Generation verwenden.",
- "singleGeneration.value.6": "Generation 6",
- "singleGeneration.desc.6": "Du kannst nur Pokémon aus der sechsten Generation verwenden.",
- "singleGeneration.value.7": "Generation 7",
- "singleGeneration.desc.7": "Du kannst nur Pokémon aus der siebten Generation verwenden.",
- "singleGeneration.value.8": "Generation 8",
- "singleGeneration.desc.8": "Du kannst nur Pokémon aus der achten Generation verwenden.",
- "singleGeneration.value.9": "Generation 9",
- "singleGeneration.desc.9": "Du kannst nur Pokémon aus der neunten Generation verwenden.",
- "singleType.name": "Mono-Typ",
- "singleType.value.0": "Aus",
- "singleType.desc.0": "Du kannst nur Pokémon des gewählten Typs verwenden.",
- "singleType.value.1": "Normal",
- "singleType.desc.1": "Du kannst nur Pokémon des Typs Normal verwenden.",
- "singleType.value.2": "Kampf",
- "singleType.desc.2": "Du kannst nur Pokémon des Typs Kampf verwenden.",
- "singleType.value.3": "Flug",
- "singleType.desc.3": "Du kannst nur Pokémon des Typs Flug verwenden.",
- "singleType.value.4": "Gift",
- "singleType.desc.4": "Du kannst nur Pokémon des Typs Gift verwenden.",
- "singleType.value.5": "Boden",
- "singleType.desc.5": "Du kannst nur Pokémon des Typs Boden verwenden.",
- "singleType.value.6": "Gestein",
- "singleType.desc.6": "Du kannst nur Pokémon des Typs Gestein verwenden.",
- "singleType.value.7": "Käfer",
- "singleType.desc.7": "Du kannst nur Pokémon des Typs Käfer verwenden.",
- "singleType.value.8": "Geist",
- "singleType.desc.8": "Du kannst nur Pokémon des Typs Geist verwenden.",
- "singleType.value.9": "Stahl",
- "singleType.desc.9": "Du kannst nur Pokémon des Typs Stahl verwenden.",
- "singleType.value.10": "Feuer",
- "singleType.desc.10": "Du kannst nur Pokémon des Typs Feuer verwenden.",
- "singleType.value.11": "Wasser",
- "singleType.desc.11": "Du kannst nur Pokémon des Typs Wasser verwenden.",
- "singleType.value.12": "Pflanze",
- "singleType.desc.12": "Du kannst nur Pokémon des Typs Pflanze verwenden.",
- "singleType.value.13": "Elektro",
- "singleType.desc.13": "Du kannst nur Pokémon des Typs Elektro verwenden.",
- "singleType.value.14": "Psycho",
- "singleType.desc.14": "Du kannst nur Pokémon des Typs Psycho verwenden.",
- "singleType.value.15": "Eis",
- "singleType.desc.15": "Du kannst nur Pokémon des Typs Eis verwenden.",
- "singleType.value.16": "Drache",
- "singleType.desc.16": "Du kannst nur Pokémon des Typs Drache verwenden.",
- "singleType.value.17": "Unlicht",
- "singleType.desc.17": "Du kannst nur Pokémon des Typs Unlicht verwenden.",
- "singleType.value.18": "Fee",
- "singleType.desc.18": "Du kannst nur Pokémon des Typs Fee verwenden."
-
+ "illegalEvolution": "{{pokemon}} hat sich in ein Pokémon verwandelt, dass für diese Herausforderung nicht zulässig ist!",
+ "singleGeneration": {
+ "name": "Mono-Generation",
+ "desc": "Du kannst nur Pokémon aus der {{gen}} Generation verwenden.",
+ "desc_default": "Du kannst nur Pokémon gewählten Generation verwenden.",
+ "gen_1": "ersten",
+ "gen_2": "zweiten",
+ "gen_3": "dritten",
+ "gen_4": "vierten",
+ "gen_5": "fünften",
+ "gen_6": "sechsten",
+ "gen_7": "siebten",
+ "gen_8": "achten",
+ "gen_9": "neunten",
+ },
+ "singleType": {
+ "name": "Mono-Typ",
+ "desc": "Du kannst nur Pokémon des Typs {{type}} verwenden.",
+ "desc_default": "Du kannst nur Pokémon des gewählten Typs verwenden."
+ // types in pokemon-info
+ },
} as const;
diff --git a/src/locales/de/common.ts b/src/locales/de/common.ts
new file mode 100644
index 00000000000..82966b4ffeb
--- /dev/null
+++ b/src/locales/de/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Start",
+} as const;
diff --git a/src/locales/de/config.ts b/src/locales/de/config.ts
index 16c25d6ca78..5f1bd541ad2 100644
--- a/src/locales/de/config.ts
+++ b/src/locales/de/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/de/settings.js";
+import { common } from "#app/locales/de/common.js";
export const deConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const deConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts
index ba040e91810..f7b8a1b0877 100644
--- a/src/locales/de/settings.ts
+++ b/src/locales/de/settings.ts
@@ -9,9 +9,9 @@ export const settings: SimpleTranslationEntries = {
"gamepad": "Controller",
"keyboard": "Tastatur",
"gameSpeed": "Spielgeschwindigkeit",
- "hpBarSpeed": "KP-Balken Geschwindigkeit",
- "expGainsSpeed": "EXP-Balken Geschwindigkeit",
- "expPartyDisplay": "Team-EXP anzeigen",
+ "hpBarSpeed": "KP-Balken Geschw.",
+ "expGainsSpeed": "EP-Balken Geschw.",
+ "expPartyDisplay": "Team-EP anzeigen",
"skipSeenDialogues": "Gesehenen Dialog überspringen",
"battleStyle": "Kampfstil",
"enableRetries": "Erneut versuchen aktivieren",
@@ -22,7 +22,7 @@ export const settings: SimpleTranslationEntries = {
"fast": "Schnell",
"faster": "Schneller",
"skip": "Überspringen",
- "levelUpNotifications": "Auflevelbenachrichtigung",
+ "levelUpNotifications": "Nur Lvl.-Up",
"on": "An",
"off": "Aus",
"switch": "Wechsel",
@@ -58,18 +58,18 @@ export const settings: SimpleTranslationEntries = {
"consistent": "Konistent",
"mixedAnimated": "Gemischt animiert",
"fusionPaletteSwaps": "Fusion-Farbpalettenwechsel",
- "playerGender": "Spieler Geschlecht",
+ "playerGender": "Spielergeschlecht",
"typeHints": "Typhinweise",
"masterVolume": "Gesamtlautstärke",
"bgmVolume": "Hintergrundmusik",
"seVolume": "Spezialeffekte",
"musicPreference": "Musik Präferenz",
- "mixed": "Gemisch",
- "gamepadPleasePlug": "Bitte einen Controller anschließen oder eine Taste drücken",
+ "mixed": "Gemischt",
+ "gamepadPleasePlug": "Bitte einen Controller anschließen oder eine Taste drücken.",
"delete": "Löschen",
- "keyboardPleasePress": "Bitte eine Taste auf der Tastatur drücken",
- "reset": "Zurücksetzen",
- "requireReload": "Neuladen benötigt",
+ "keyboardPleasePress": "Bitte eine Taste auf der Tastatur drücken.",
+ "reset": "Reset",
+ "requireReload": "Neuladen",
"action": "Aktion",
"back": "Zurück",
"pressToBind": "Zum Zuweisen drücken",
@@ -92,7 +92,7 @@ export const settings: SimpleTranslationEntries = {
"buttonSpeedUp": "Beschleunigen",
"buttonSlowDown": "Verlangsamen",
"alt": " (Alt)",
- "mute": "Mute",
+ "mute": "Stumm",
"controller": "Controller",
- "gamepadSupport": "Gamepad Support"
+ "gamepadSupport": "Controllerunterstützung",
} as const;
diff --git a/src/locales/de/starter-select-ui-handler.ts b/src/locales/de/starter-select-ui-handler.ts
index c82f579c341..2f5a98bb051 100644
--- a/src/locales/de/starter-select-ui-handler.ts
+++ b/src/locales/de/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Passiv:",
"nature": "Wesen:",
"eggMoves": "Ei-Attacken",
- "start": "Start",
"addToParty": "Zum Team hinzufügen",
"toggleIVs": "DVs anzeigen/verbergen",
"manageMoves": "Attacken ändern",
diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts
index e5afe934492..304766a228f 100644
--- a/src/locales/en/battle.ts
+++ b/src/locales/en/battle.ts
@@ -71,4 +71,61 @@ export const battle: SimpleTranslationEntries = {
"statSeverelyFell": "severely fell",
"statWontGoAnyLower": "won't go any lower",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} was freed\nfrom {{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} flinched!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} became\nconfused!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} snapped\nout of confusion!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} is\nalready confused!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} is\nconfused!",
+ "battlerTagsConfusedLapseHurtItself": "It hurt itself in its\nconfusion!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} is unaffected\nby the effects of Destiny Bond.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} took\n{{pokemonNameWithAffix2}} down with it!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} fell in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} is\nalready in love!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} is in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} is\nimmobilized by love!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} got over\nits infatuation.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} was seeded!",
+ "battlerTagsSeededLapse": "{{pokemonNameWithAffix}}'s health is\nsapped by Leech Seed!",
+ "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}'s Leech Seed\nsucked up the liquid ooze!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} began\nhaving a Nightmare!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} is\nalready locked in a Nightmare!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} is locked\nin a Nightmare!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} got\nan Encore!",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}'s Encore\nended!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} is ready to\nhelp {{pokemonName}}!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorbed\nnutrients with its roots!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} planted its roots!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} surrounded\nitself with a veil of water!",
+ "battlerTagsAquaRingLapse": "{{moveName}} restored\n{{pokemonName}}'s HP!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} grew drowsy!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} is hurt\nby {{moveName}}!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} was squeezed by\n{{sourcePokemonName}}'s {{moveName}}!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} was Wrapped\nby {{sourcePokemonName}}!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} was trapped\nin the vortex!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} Clamped\n{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} became trapped\nby {{moveName}}!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} became trapped\nby swirling magma!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} got trapped\nby a snap trap!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} trapped\n{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} has been afflicted \nwith an infestation by {{sourcePokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} braced\nitself!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}'s perish count fell to {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} is\nloafing around!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} can't\nget it going!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} finally\ngot its act together!",
+ "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}'s {{statName}}\nwas heightened!",
+ "battlerTagsHighestStatBoostOnRemove": "The effects of {{pokemonNameWithAffix}}'s\n{{abilityName}} wore off!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} is getting\npumped!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} relaxed.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} is being salt cured!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!"
} as const;
diff --git a/src/locales/en/challenges.ts b/src/locales/en/challenges.ts
index 746a7e962d2..a40f05a0843 100644
--- a/src/locales/en/challenges.ts
+++ b/src/locales/en/challenges.ts
@@ -1,67 +1,26 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales.js";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "Challenge Modifiers",
- "start": "Start",
- "illegalEvolution": "{{pokemon}} changed into an ineligble pokemon\nfor this challenge!",
- "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.",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "Mono Gen",
+ "desc": "You can only use Pokémon from Generation {{gen}}.",
+ "desc_default": "You can only use Pokémon from the chosen generation.",
+ "gen_1": "one",
+ "gen_2": "two",
+ "gen_3": "three",
+ "gen_4": "four",
+ "gen_5": "five",
+ "gen_6": "six",
+ "gen_7": "seven",
+ "gen_8": "eight",
+ "gen_9": "nine",
+ },
+ "singleType": {
+ "name": "Mono Type",
+ "desc": "You can only use Pokémon with the {{type}} type.",
+ "desc_default": "You can only use Pokémon of the chosen type."
+ //types in pokemon-info
+ },
} as const;
diff --git a/src/locales/en/common.ts b/src/locales/en/common.ts
new file mode 100644
index 00000000000..82966b4ffeb
--- /dev/null
+++ b/src/locales/en/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Start",
+} as const;
diff --git a/src/locales/en/config.ts b/src/locales/en/config.ts
index 98b36ea61ab..f37b707479a 100644
--- a/src/locales/en/config.ts
+++ b/src/locales/en/config.ts
@@ -1,3 +1,4 @@
+import { common } from "#app/locales/en/common.js";
import { settings } from "#app/locales/en/settings.js";
import { ability } from "./ability";
import { abilityTriggers } from "./ability-trigger";
@@ -50,6 +51,7 @@ export const enConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/en/starter-select-ui-handler.ts b/src/locales/en/starter-select-ui-handler.ts
index 4b7c3194396..ae8443d8a20 100644
--- a/src/locales/en/starter-select-ui-handler.ts
+++ b/src/locales/en/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Passive:",
"nature": "Nature:",
"eggMoves": "Egg Moves",
- "start": "Start",
"addToParty": "Add to Party",
"toggleIVs": "Toggle IVs",
"manageMoves": "Manage Moves",
diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts
index 76b6cd4e35e..7ba401b524d 100644
--- a/src/locales/es/battle.ts
+++ b/src/locales/es/battle.ts
@@ -71,4 +71,61 @@ export const battle: SimpleTranslationEntries = {
"statSeverelyFell": "severely fell",
"statWontGoAnyLower": "won't go any lower",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} was freed\nfrom {{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} flinched!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} became\nconfused!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} snapped\nout of confusion!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} is\nalready confused!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} is\nconfused!",
+ "battlerTagsConfusedLapseHurtItself": "It hurt itself in its\nconfusion!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} is unaffected\nby the effects of Destiny Bond.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} took\n{{pokemonNameWithAffix2}} down with it!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} fell in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} is\nalready in love!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} is in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} is\nimmobilized by love!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} got over\nits infatuation.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} was seeded!",
+ "battlerTagsSeededLapse": "{{pokemonNameWithAffix}}'s health is\nsapped by Leech Seed!",
+ "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}'s Leech Seed\nsucked up the liquid ooze!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} began\nhaving a Nightmare!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} is\nalready locked in a Nightmare!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} is locked\nin a Nightmare!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} got\nan Encore!",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}'s Encore\nended!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} is ready to\nhelp {{pokemonName}}!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorbed\nnutrients with its roots!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} planted its roots!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} surrounded\nitself with a veil of water!",
+ "battlerTagsAquaRingLapse": "{{moveName}} restored\n{{pokemonName}}'s HP!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} grew drowsy!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} is hurt\nby {{moveName}}!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} was squeezed by\n{{sourcePokemonName}}'s {{moveName}}!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} was Wrapped\nby {{sourcePokemonName}}!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} was trapped\nin the vortex!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} Clamped\n{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} became trapped\nby {{moveName}}!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} became trapped\nby swirling magma!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} got trapped\nby a snap trap!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} trapped\n{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} has been afflicted \nwith an infestation by {{sourcePokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} braced\nitself!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}'s perish count fell to {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} is\nloafing around!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} can't\nget it going!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} finally\ngot its act together!",
+ "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}'s {{statName}}\nwas heightened!",
+ "battlerTagsHighestStatBoostOnRemove": "The effects of {{pokemonNameWithAffix}}'s\n{{abilityName}} wore off!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} is getting\npumped!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} relaxed.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} is being salt cured!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!"
} as const;
diff --git a/src/locales/es/challenges.ts b/src/locales/es/challenges.ts
index 9bc5b0923fd..711be39b116 100644
--- a/src/locales/es/challenges.ts
+++ b/src/locales/es/challenges.ts
@@ -1,67 +1,25 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"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": "Solo puedes usar Pokémon de primera generación.",
- "singleGeneration.value.2": "Gen 2",
- "singleGeneration.desc.2": "Solo puedes usar Pokémon de segunda generación.",
- "singleGeneration.value.3": "Gen 3",
- "singleGeneration.desc.3": "Solo puedes usar Pokémon de tercera generación.",
- "singleGeneration.value.4": "Gen 4",
- "singleGeneration.desc.4": "Solo puedes usar Pokémon de cuarta generación.",
- "singleGeneration.value.5": "Gen 5",
- "singleGeneration.desc.5": "Solo puedes usar Pokémon de quinta generación.",
- "singleGeneration.value.6": "Gen 6",
- "singleGeneration.desc.6": "Solo puedes usar Pokémon de sexta generación.",
- "singleGeneration.value.7": "Gen 7",
- "singleGeneration.desc.7": "Solo puedes usar Pokémon de séptima generación.",
- "singleGeneration.value.8": "Gen 8",
- "singleGeneration.desc.8": "Solo puedes usar Pokémon de octava generación.",
- "singleGeneration.value.9": "Gen 9",
- "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": "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.",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "Monogeneración",
+ "desc": "Solo puedes usar Pokémon de {{gen}} generación.",
+ "desc_default": "Solo puedes usar Pokémon de la generación elegida.",
+ "gen_1": "primera",
+ "gen_2": "segunda",
+ "gen_3": "tercera",
+ "gen_4": "cuarta",
+ "gen_5": "quinta",
+ "gen_6": "sexta",
+ "gen_7": "séptima",
+ "gen_8": "octava",
+ "gen_9": "novena",
+ },
+ "singleType": {
+ "name": "Monotipo",
+ "desc": "Solo puedes usar Pokémon with the {{type}} type.",
+ "desc_default": "Solo puedes usar Pokémon del tipo elegido.",
+ },
} as const;
diff --git a/src/locales/es/common.ts b/src/locales/es/common.ts
new file mode 100644
index 00000000000..82966b4ffeb
--- /dev/null
+++ b/src/locales/es/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Start",
+} as const;
diff --git a/src/locales/es/config.ts b/src/locales/es/config.ts
index e85ba976be4..f3747b6c619 100644
--- a/src/locales/es/config.ts
+++ b/src/locales/es/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/es/settings.js";
+import { common } from "#app/locales/es/common.js";
export const esConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const esConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/es/starter-select-ui-handler.ts b/src/locales/es/starter-select-ui-handler.ts
index 642d55ab5d8..a6ff2c921c3 100644
--- a/src/locales/es/starter-select-ui-handler.ts
+++ b/src/locales/es/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Pasiva:",
"nature": "Natur:",
"eggMoves": "Mov. Huevo",
- "start": "Iniciar",
"addToParty": "Añadir a Equipo",
"toggleIVs": "Mostrar IVs",
"manageMoves": "Gestionar Movs.",
diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts
index e270539c781..e86e00029c6 100644
--- a/src/locales/fr/battle.ts
+++ b/src/locales/fr/battle.ts
@@ -62,13 +62,70 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "L’énergie de {{pokemonName}}\nest drainée !",
"regainHealth": "{{pokemonName}} récupère\ndes PV !",
"fainted": "{{pokemonNameWithAffix}}\nest K.O. !",
- "statRose": "rose",
- "statSharplyRose": "sharply rose",
- "statRoseDrastically": "rose drastically",
- "statWontGoAnyHigher": "won't go any higher",
- "statFell": "fell",
- "statHarshlyFell": "harshly fell",
- "statSeverelyFell": "severely fell",
- "statWontGoAnyLower": "won't go any lower",
- "ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "statRose": "augmente",
+ "statSharplyRose": "augmente beaucoup",
+ "statRoseDrastically": "augmente énormément",
+ "statWontGoAnyHigher": "ne peut plus augmenter",
+ "statFell": "baisse",
+ "statHarshlyFell": "baisse beaucoup",
+ "statSeverelyFell": "baisse énormément",
+ "statWontGoAnyLower": "ne peut plus baisser",
+ "ppReduced": "Les PP de la capacité {{moveName}}\nde {{targetName}} sont réduits de {{reduction}} !",
+ "battlerTagsRechargingLapse": "Le contrecoup empêche {{pokemonNameWithAffix}}\n de bouger !",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}\nne peut plus s’échapper !",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} est libéré\nde la capacité {{moveName}} !",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} a la trouille !\nIl ne peut plus attaquer !",
+ "battlerTagsConfusedOnAdd": "Ça rend {{pokemonNameWithAffix}}\nconfus !",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}\nn’est plus confus !",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}\nest déjà confus !",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}\nest confus !",
+ "battlerTagsConfusedLapseHurtItself": "Il se blesse dans sa confusion.",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} n’est pas affecté\nle Lien du Destin !",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} entraine\n{{pokemonNameWithAffix2}} dans sa chute !",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} est amoureux\nde {{sourcePokemonName}} !",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} est\ndéjà amoureux !",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}}] est amoureux\nde {{sourcePokemonName}} !",
+ "battlerTagsInfatuatedLapseImmobilize": "L’amour empêche {{pokemonNameWithAffix}}\nd’agir !",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}\nn’est plus amoureux !",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} est infecté !",
+ "battlerTagsSeededLapse": "Vampigraine draine l’énergie\nde {{pokemonNameWithAffix}} !",
+ "battlerTagsSeededLapseShed": "La Vampigraine de {{pokemonNameWithAffix}}\naspire le suintement !",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} commence à cauchemarder !",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} est\ndéjà prisonnier d’un cauchemar !",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}est\nprisonnier d’un cauchemar !",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} !\nEncore une fois !",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}} n’est\nplus obligé d’utiliser la même capacité !",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} est prêt\nà aider {{pokemonName}} !",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorbe\ndes nutriments avec ses racines !",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}\nplante ses racines !",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} s’entoure\nd’un voile d’eau !",
+ "battlerTagsAquaRingLapse": "{{moveName}} restaure\nles PV de {{pokemonName}} !",
+ "battlerTagsDrowsyOnAdd": "Ça rend {{pokemonNameWithAffix}} somnolent !",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} est blessé\npar la capacité {{moveName}} !",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} est pris dans\nl’étreinte de {{sourcePokemonName}} !",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} est ligoté\npar {{sourcePokemonName}} !",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} est piégé\ndans le tourbillon !",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} est pris dans le Claquoir\nde {{pokemonName}} !",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} est piégé\npar {{moveName}} !",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} est piégé\ndans un tourbillon de magma !",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} est tombé\ndans un Troquenard !",
+ "battlerTagsThunderCageOnTrap": "{{pokemonNameWithAffix}} se fait emprisonner\npar {{sourcePokemonNameWithAffix}} !",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} est harcelé\npar {{sourcePokemonNameWithAffix}} !",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nest prêt à se protéger !",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nse protège !",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} se prépare\nà encaisser les coups !",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}\nencaisse les coups !",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}\nencaisse les coups !",
+ "battlerTagsPerishSongLapse": "Le compte à rebours de Requiem\nde {{pokemonNameWithAffix}} descend à {{turnCount}} !",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} paresse !",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}\nn’arrive pas à se motiver !",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}\narrive enfin à s’y mettre sérieusement !",
+ "battlerTagsHighestStatBoostOnAdd": "{{statName}} de {{pokemonNameWithAffix}}\nest renforcée !",
+ "battlerTagsHighestStatBoostOnRemove": "L’effet du talent {{abilityName}}\nde {{pokemonNameWithAffix}} se dissipe !",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}\nest prêt à tout donner !",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} se détend.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}}\nest couvert de sel !",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} est blessé\npar la capacité {{moveName}} !",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} sacrifie des PV\net lance une malédiction sur {{pokemonName}} !",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} est touché par la malédiction !"
} as const;
diff --git a/src/locales/fr/challenges.ts b/src/locales/fr/challenges.ts
index 6029cdc302a..d88960dbe3b 100644
--- a/src/locales/fr/challenges.ts
+++ b/src/locales/fr/challenges.ts
@@ -1,67 +1,26 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "Paramètres du Challenge",
- "start": "Démarrer",
"illegalEvolution": "{{pokemon}} s’est transformé en Pokémon\ninéligible pour ce challenge !",
- "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": "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": "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": "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.",
+ "singleGeneration": {
+ "name": "Mono-génération",
+ "desc": "Vous ne pouvez choisir que des Pokémon de {{gen}} génération.",
+ "desc_default": "Vous ne pouvez choisir que des Pokémon de la génération sélectionnée.",
+ "gen_1": "1re",
+ "gen_2": "2e",
+ "gen_3": "3e",
+ "gen_4": "4e",
+ "gen_5": "5e",
+ "gen_6": "6e",
+ "gen_7": "7e",
+ "gen_8": "8e",
+ "gen_9": "9e",
+ },
+ "singleType": {
+ "name": "Mono-type",
+ "desc": "Vous ne pouvez choisir que des Pokémon de type {{type}}.",
+ "desc_default": "Vous ne pouvez choisir que des Pokémon du type sélectionné."
+ //type in pokemon-info
+ },
} as const;
diff --git a/src/locales/fr/common.ts b/src/locales/fr/common.ts
new file mode 100644
index 00000000000..e4ccc627f5e
--- /dev/null
+++ b/src/locales/fr/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Lancer",
+} as const;
diff --git a/src/locales/fr/config.ts b/src/locales/fr/config.ts
index b5e7a4e383a..59e8eb9f307 100644
--- a/src/locales/fr/config.ts
+++ b/src/locales/fr/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/fr/settings.js";
+import { common } from "#app/locales/fr/common.js";
export const frConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const frConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/fr/starter-select-ui-handler.ts b/src/locales/fr/starter-select-ui-handler.ts
index 0874c18d84c..87ede732f11 100644
--- a/src/locales/fr/starter-select-ui-handler.ts
+++ b/src/locales/fr/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Passif :",
"nature": "Nature :",
"eggMoves": "Capacités Œuf",
- "start": "Lancer",
"addToParty": "Ajouter à l’équipe",
"toggleIVs": "Voir les IV",
"manageMoves": "Modifier les Capacités",
diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts
index 4f90a361ecb..a4b3c32db07 100644
--- a/src/locales/it/battle.ts
+++ b/src/locales/it/battle.ts
@@ -62,13 +62,70 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "Viene prelevata energia\n da{{pokemonName}}!",
"regainHealth": "{{pokemonName}} ha rigenerato\npunti salute!",
"fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!",
- "statRose": "rose",
- "statSharplyRose": "sharply rose",
- "statRoseDrastically": "rose drastically",
- "statWontGoAnyHigher": "won't go any higher",
- "statFell": "fell",
- "statHarshlyFell": "harshly fell",
- "statSeverelyFell": "severely fell",
- "statWontGoAnyLower": "won't go any lower",
+ "statRose": "è aumentato/a",
+ "statSharplyRose": "è aumentato/a molto",
+ "statRoseDrastically": "è aumentato/a drasticamente",
+ "statWontGoAnyHigher": "non può aumentare più di così",
+ "statFell": "è diminuito/a",
+ "statHarshlyFell": "è diminuito/a molto",
+ "statSeverelyFell": "è diminuito/a drasticamente",
+ "statWontGoAnyLower": "non può diminuire più di così",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} deve\nricaricarsi!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} non può\npiù fuggire!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} è stato liberato\nda {{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} tentenna!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} è\nconfuso!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} non\nè più confuso!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} è\ngià confuso!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} è\nconfuso!",
+ "battlerTagsConfusedLapseHurtItself": "Si colpisce da solo per via della\nconfusione!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} è immune\na Destinobbligato.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} trascina\ncon sé{{pokemonNameWithAffix2}}!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} si è infatuato\ndi {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} è\ngià infatuato!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} è infatuato\ndi {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} è\nimmobilizzato dall'infatuazione!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} non è\npiù infatuato.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} è pieno di semi!",
+ "battlerTagsSeededLapse": "La salute di {{pokemonNameWithAffix}}\nviene prelevata da Parassiseme!",
+ "battlerTagsSeededLapseShed": "Parassiseme di {{pokemonNameWithAffix}}\nha risucchiato la melma!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} sta\navendo un Incubo!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} sta\ngià avendo un Incubo!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} è bloccato\nin un Incubo!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} ha\nsubito Ripeti!",
+ "battlerTagsEncoreOnRemove": "L'effetto di Ripeti su {{pokemonNameWithAffix}}\n è terminato!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} è pronto ad\naiutare {{pokemonName}}!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} assorbe\nnutrienti dalle sue radici!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} ha messo le radici!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} si è circondato\ncon un velo d'acqua!",
+ "battlerTagsAquaRingLapse": "{{moveName}} ha ripristinato\ni PS di {{pokemonName}}!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} sta per addormentarsi!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} subisce danni\nper via di {{moveName}}!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} viene schiacciato da\n{{moveName}} di {{sourcePokemonName}}!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} è stato avvinghiato\nda {{sourcePokemonName}}!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} è intrappolato\nnel vortice!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} sta intenagliando\n{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} è intrappolato\nda {{moveName}}!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} è intrappolato\nnel magma vorticoso!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} è intrappolato\nin una tagliola!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} ha intrappolato\n{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} ha subito un\ninfestazione da parte di {{sourcePokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nsi è protetto!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nsi è protetto!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} si prepara a\nsubire il colpo!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} resiste\nal colpo!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} ha resistito\ngrazie a Vigore!",
+ "battlerTagsPerishSongLapse": "Il conto alla rovescia di Ultimocanto per {{pokemonNameWithAffix}} scende a {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} sta\nciondolando!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} non\ningrana!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} ritrova\nlo slancio!",
+ "battlerTagsHighestStatBoostOnAdd": "{{statName}} di {{pokemonNameWithAffix}}\nviene aumentato/a!",
+ "battlerTagsHighestStatBoostOnRemove": "Gli effetti di {{abilityName}}\ndi {{pokemonNameWithAffix}} sono cessati!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} si prepara\nalla lotta!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} si è rilassato.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} è stato messo sotto sale!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} viene colpito da {{moveName}}!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} ha sacrificato metà dei suoi PS per\nlanciare una maledizione su {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} subisce la maledizione!"
} as const;
diff --git a/src/locales/it/challenges.ts b/src/locales/it/challenges.ts
index 0a15b22f83e..2643b16d0f7 100644
--- a/src/locales/it/challenges.ts
+++ b/src/locales/it/challenges.ts
@@ -1,67 +1,25 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "Modificatori delle sfide",
- "points": "Pessime idee",
- "confirm_start": "Procedere con le sfide selezionate?",
- "singleGeneration.name": "Mono gen",
- "singleGeneration.value.0": "Off",
- "singleGeneration.desc.0": "Puoi usare solo Pokémon della generazione selezionata.",
- "singleGeneration.value.1": "1ª gen",
- "singleGeneration.desc.1": "Puoi usare solo Pokémon di 1ª generazione.",
- "singleGeneration.value.2": "2ª gen",
- "singleGeneration.desc.2": "Puoi usare solo Pokémon di 2ª generazione.",
- "singleGeneration.value.3": "3ª gen",
- "singleGeneration.desc.3": "Puoi usare solo Pokémon di 3ª generazione.",
- "singleGeneration.value.4": "4ª gen",
- "singleGeneration.desc.4": "Puoi usare solo Pokémon di 4ª generazione.",
- "singleGeneration.value.5": "5ª gen",
- "singleGeneration.desc.5": "Puoi usare solo Pokémon di 5ª generazione.",
- "singleGeneration.value.6": "6ª gen",
- "singleGeneration.desc.6": "Puoi usare solo Pokémon di 6ª generazione.",
- "singleGeneration.value.7": "7ª gen",
- "singleGeneration.desc.7": "Puoi usare solo Pokémon di 7ª generazione.",
- "singleGeneration.value.8": "8ª gen",
- "singleGeneration.desc.8": "Puoi usare solo Pokémon di 8ª generazione.",
- "singleGeneration.value.9": "9ª gen",
- "singleGeneration.desc.9": "Puoi usare solo Pokémon di 9ª generazione.",
- "singleType.name": "Mono tipo",
- "singleType.value.0": "Off",
- "singleType.desc.0": "Puoi usare solo Pokémon del tipo selezionato.",
- "singleType.value.1": "Normale",
- "singleType.desc.1": "Puoi usare solo Pokémon di tipo normale.",
- "singleType.value.2": "Lotta",
- "singleType.desc.2": "Puoi usare solo Pokémon di tipo lotta.",
- "singleType.value.3": "Volante",
- "singleType.desc.3": "Puoi usare solo Pokémon di tipo volante.",
- "singleType.value.4": "Veleno",
- "singleType.desc.4": "Puoi usare solo Pokémon di tipo veleno.",
- "singleType.value.5": "Terra",
- "singleType.desc.5": "Puoi usare solo Pokémon di tipo terra.",
- "singleType.value.6": "Roccia",
- "singleType.desc.6": "Puoi usare solo Pokémon di tipo roccia.",
- "singleType.value.7": "Coleottero",
- "singleType.desc.7": "Puoi usare solo Pokémon di tipo coleottero.",
- "singleType.value.8": "Spettro",
- "singleType.desc.8": "Puoi usare solo Pokémon di tipo spettro.",
- "singleType.value.9": "Acciaio",
- "singleType.desc.9": "Puoi usare solo Pokémon di tipo acciaio.",
- "singleType.value.10": "Fuoco",
- "singleType.desc.10": "Puoi usare solo Pokémon di tipo fuoco.",
- "singleType.value.11": "Acqua",
- "singleType.desc.11": "Puoi usare solo Pokémon di tipo acqua.",
- "singleType.value.12": "Erba",
- "singleType.desc.12": "Puoi usare solo Pokémon di tipo erba.",
- "singleType.value.13": "Elettro",
- "singleType.desc.13": "Puoi usare solo Pokémon di tipo elettro.",
- "singleType.value.14": "Psico",
- "singleType.desc.14": "Puoi usare solo Pokémon di tipo psico.",
- "singleType.value.15": "Ghiaccio",
- "singleType.desc.15": "Puoi usare solo Pokémon di tipo ghiaccio.",
- "singleType.value.16": "Drago",
- "singleType.desc.16": "Puoi usare solo Pokémon di tipo drago.",
- "singleType.value.17": "Buio",
- "singleType.desc.17": "Puoi usare solo Pokémon di tipo buio.",
- "singleType.value.18": "Folletto",
- "singleType.desc.18": "Puoi usare solo Pokémon di tipo folletto.",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "Mono gen",
+ "desc": "Puoi usare solo Pokémon di {{gen}} generazione.",
+ "desc_default": "Puoi usare solo Pokémon della generazione selezionata.",
+ "gen_1": "1ª",
+ "gen_2": "2ª",
+ "gen_3": "3ª",
+ "gen_4": "4ª",
+ "gen_5": "5ª",
+ "gen_6": "6ª",
+ "gen_7": "7ª",
+ "gen_8": "8ª",
+ "gen_9": "9ª",
+ },
+ "singleType": {
+ "name": "Mono tipo",
+ "desc": "Puoi usare solo Pokémon di tipo {{type}}.",
+ "desc_default": "Puoi usare solo Pokémon del tipo selezionato."
+ },
} as const;
diff --git a/src/locales/it/common.ts b/src/locales/it/common.ts
new file mode 100644
index 00000000000..f42fa311472
--- /dev/null
+++ b/src/locales/it/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Inizia",
+} as const;
diff --git a/src/locales/it/config.ts b/src/locales/it/config.ts
index 6f14aabda50..7cc063a6b23 100644
--- a/src/locales/it/config.ts
+++ b/src/locales/it/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/it/settings.js";
+import { common } from "#app/locales/it/common.js";
export const itConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const itConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/it/starter-select-ui-handler.ts b/src/locales/it/starter-select-ui-handler.ts
index 8f68e5ff10d..5f9960561ca 100644
--- a/src/locales/it/starter-select-ui-handler.ts
+++ b/src/locales/it/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Passiva:",
"nature": "Natura:",
"eggMoves": "Mosse da uova",
- "start": "Inizia",
"addToParty": "Aggiungi al gruppo",
"toggleIVs": "Vedi/Nascondi IV",
"manageMoves": "Gestisci mosse",
diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts
index 48f7339e9ce..70464c8487a 100644
--- a/src/locales/ko/battle.ts
+++ b/src/locales/ko/battle.ts
@@ -70,5 +70,62 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "[[가]] 크게 떨어졌다!",
"statSeverelyFell": "[[가]] 매우 크게 떨어졌다!",
"statWontGoAnyLower": "[[는]] 더 떨어지지 않는다!",
- "ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "ppReduced": "{{targetName}}의\n{{moveName}}[[를]] {{reduction}} 깎았다!",
+ "battlerTagsRechargingLapse": "공격의 반동으로\n{{pokemonNameWithAffix}}[[는]] 움직일 수 없다!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n이제 도망칠 수 없다!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}[[는]]\n{{moveName}}로부터 풀려났다!",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}[[는]] 풀이 죽어\n움직일 수 없었다!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n혼란에 빠졌다!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}의\n혼란이 풀렸다!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}[[는]]\n이미 혼란에 빠져 있다",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}[[는]]\n혼란에 빠져 있다!",
+ "battlerTagsConfusedLapseHurtItself": "영문도 모른채\n자신을 공격했다!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}}[[는]]\n길동무의 영향을 받지 않는다.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}}[[는]] {{pokemonNameWithAffix2}}[[를]]\n길동무로 삼았다!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n헤롱헤롱해졌다!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}}[[는]]\n이미 헤롱헤롱해있다!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}}[[는]]\n{{sourcePokemonName}}에게 헤롱헤롱해 있다!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}}[[는]] 헤롱헤롱해서\n기술을 쓸 수 없었다!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}[[는]]\n헤롱헤롱 상태에서 벗어났다.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}}에게\n씨앗을 심었다!",
+ "battlerTagsSeededLapse": "씨뿌리기가 {{pokemonNameWithAffix}}의\n체력을 빼앗는다!",
+ "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}[[는]]\n씨앗을 날려버렸다!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}[[는]]\n악몽을 꾸기 시작했다!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}[[는]]\n이미 악몽을 꾸고 있다!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}[[는]]\n악몽에 시달리고 있다!",
+ "battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}}[[는]]\n앙코르를 받았다!",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}의\n앙코르 상태가 풀렸다!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}[[는]] {{pokemonName}}에게\n도우미가 되어주려 한다!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}[[는]] 뿌리로부터\n양분을 흡수했다!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}[[는]] 뿌리를 뻗었다!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}[[는]]\n물의 베일을 둘러썼다!",
+ "battlerTagsAquaRingLapse": "{{moveName}} 효과로 \n{{pokemonName}}[[는]] HP를 회복했다!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}}의\n졸음을 유도했다!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}[[는]] {{moveName}}의\n데미지를 입고 있다!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}[[는]] {{sourcePokemonName}}에게\n{{moveName}}[[를]] 당했다!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}[[는]] {{sourcePokemonName}}에게\n휘감겼다!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}[[는]]\n소용돌이 속에 갇혔다!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}}[[는]] {{pokemonName}}의\n껍질에 꼈다!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}[[는]]\n{{moveName}}에 붙잡혔다!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}[[는]]\n마그마의 소용돌이에 갇혔다!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}[[는]]\n집게덫에 붙잡혔다!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}[[는]]\n{{pokemonNameWithAffix}}를 가두었다!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}}[[는]]\n{{sourcePokemonNameWithAffix}}에게 엉겨 붙었다!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n방어 태세에 들어갔다!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}[[는]]\n공격으로부터 몸을 지켰다!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}[[는]]\n버티기 태세에 들어갔다!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}[[는]]\n공격을 버텼다!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}[[는]]\n공격을 버텼다!",
+ "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}의 멸망의\n카운트가 {{turnCount}}[[가]] 되었다!",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}}[[는]] 게으름을 피우고 있다!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}[[는]] 컨디션이\n좋아지지 않는다!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} 는 마침내\n컨디션을 회복했다!",
+ "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}의\n{{statName}}[[가]] 올라갔다!",
+ "battlerTagsHighestStatBoostOnRemove": "The effects of {{pokemonNameWithAffix}}'s\n{{abilityName}} wore off!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}[[는]]\n의욕이 넘치고 있다!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}[[는]] 평소로 돌아왔다.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}}[[는]]\n소금에 절여졌다!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}}[[는]] 소금절이의\n데미지를 입고 있다.",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n자신의 체력을 깎아서\n{{pokemonName}}에게 저주를 걸었다!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}}[[는]]\n저주받고 있다!"
} as const;
diff --git a/src/locales/ko/challenges.ts b/src/locales/ko/challenges.ts
index 64fa316b3bb..1f10c4f215a 100644
--- a/src/locales/ko/challenges.ts
+++ b/src/locales/ko/challenges.ts
@@ -1,67 +1,26 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "챌린지 조건 설정",
- "points": "Bad Ideas",
- "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세대의 포켓몬만 사용할 수 있습니다.",
- "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": "페어리 타입의 포켓몬만 사용할 수 있습니다.",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "단일 세대",
+ "desc": "{{gen}}의 포켓몬만 사용할 수 있습니다.",
+ "desc_default": "선택한 세대의 포켓몬만 사용할 수 있습니다.",
+ "gen_1": "1세대",
+ "gen_2": "2세대",
+ "gen_3": "3세대",
+ "gen_4": "4세대",
+ "gen_5": "5세대",
+ "gen_6": "6세대",
+ "gen_7": "7세대",
+ "gen_8": "8세대",
+ "gen_9": "9세대",
+ },
+ "singleType": {
+ "name": "단일 타입",
+ "desc": "{{type}} 타입의 포켓몬만 사용할 수 있습니다.",
+ "desc_default": "선택한 타입의 포켓몬만 사용할 수 있습니다."
+ //type in pokemon-info
+ },
} as const;
diff --git a/src/locales/ko/common.ts b/src/locales/ko/common.ts
new file mode 100644
index 00000000000..d87be482f99
--- /dev/null
+++ b/src/locales/ko/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "시작",
+} as const;
diff --git a/src/locales/ko/config.ts b/src/locales/ko/config.ts
index 99cf5ddd8ea..3ec162abd34 100644
--- a/src/locales/ko/config.ts
+++ b/src/locales/ko/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/ko/settings.js";
+import { common } from "#app/locales/ko/common.js";
export const koConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const koConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/ko/modifier-type.ts b/src/locales/ko/modifier-type.ts
index 479e1ca02e2..a0bae4ea703 100644
--- a/src/locales/ko/modifier-type.ts
+++ b/src/locales/ko/modifier-type.ts
@@ -250,14 +250,14 @@ export const modifierType: ModifierTypeTranslationEntries = {
},
TempBattleStatBoosterStatName: {
- "ATK": "Attack",
- "DEF": "Defense",
- "SPATK": "Sp. Atk",
- "SPDEF": "Sp. Def",
- "SPD": "Speed",
- "ACC": "Accuracy",
- "CRIT": "Critical Hit Ratio",
- "EVA": "Evasiveness",
+ "ATK": "공격",
+ "DEF": "방어",
+ "SPATK": "특수공격",
+ "SPDEF": "특수방어",
+ "SPD": "스피드",
+ "ACC": "명중률",
+ "CRIT": "급소율",
+ "EVA": "회피율",
"DEFAULT": "???",
},
diff --git a/src/locales/ko/settings.ts b/src/locales/ko/settings.ts
index 08f0c635199..28fe99f265f 100644
--- a/src/locales/ko/settings.ts
+++ b/src/locales/ko/settings.ts
@@ -92,7 +92,7 @@ export const settings: SimpleTranslationEntries = {
"buttonSpeedUp": "속도 올리기",
"buttonSlowDown": "속도 내리기",
"alt": " (대체)",
- "mute": "Mute",
- "controller": "Controller",
- "gamepadSupport": "Gamepad Support"
+ "mute": "음소거",
+ "controller": "컨트롤러",
+ "gamepadSupport": "게임패드 지원"
} as const;
diff --git a/src/locales/ko/starter-select-ui-handler.ts b/src/locales/ko/starter-select-ui-handler.ts
index ab155a4a048..f78e760c4e0 100644
--- a/src/locales/ko/starter-select-ui-handler.ts
+++ b/src/locales/ko/starter-select-ui-handler.ts
@@ -6,7 +6,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
* account interactions, descriptive text, etc.
*/
export const starterSelectUiHandler: SimpleTranslationEntries = {
- "confirmStartTeam":"이 포켓몬들로 시작하시겠습니까?",
+ "confirmStartTeam": "이 포켓몬들로 시작하시겠습니까?",
"gen1": "1세대",
"gen2": "2세대",
"gen3": "3세대",
@@ -21,11 +21,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "패시브:",
"nature": "성격:",
"eggMoves": "알 기술",
- "start": "시작",
"addToParty": "파티에 추가",
"toggleIVs": "개체값 토글",
"manageMoves": "기술 관리",
+ "manageNature": "성격 관리",
"useCandies": "사탕 사용",
+ "selectNature": "교체할 성격을 선택해주세요.",
"selectMoveSwapOut": "교체할 기술을 선택해주세요.",
"selectMoveSwapWith": "교체될 기술을 선택해주세요. 대상:",
"unlockPassive": "패시브 해금",
diff --git a/src/locales/ko/trainers.ts b/src/locales/ko/trainers.ts
index 374b0180364..429ab13b223 100644
--- a/src/locales/ko/trainers.ts
+++ b/src/locales/ko/trainers.ts
@@ -112,7 +112,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"school_kid": "학원끝난 아이",
"school_kid_female": "학원끝난 아이",
"school_kids": "학원끝난 아이",
- "swimmer": "수연팬티 소년",
+ "swimmer": "수영팬티 소년",
"swimmer_female": "비키니 아가씨",
"swimmers": "수영팬티 소년 & 비키니 아가씨", // 확인 필요
"twins": "쌍둥이",
diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts
index 036c761bca7..ae72a615127 100644
--- a/src/locales/pt_BR/battle.ts
+++ b/src/locales/pt_BR/battle.ts
@@ -70,5 +70,62 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "diminuiu duramente",
"statSeverelyFell": "diminuiu severamente",
"statWontGoAnyLower": "não vai mais diminuir",
- "ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "ppReduced": "O PP do movimento {{moveName}} de\n{{targetName}} foi reduzido em {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} precisa\nrecarregar!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} não pode\nmais escapar!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} foi liberto\nde {{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} hesitou!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} ficou\nconfuso!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} saiu\nde sua confusão!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} já\nestá confuso!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} está\nconfuso!",
+ "battlerTagsConfusedLapseHurtItself": "Se machucou em sua\nconfusão!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} não é afetado\npelos efeitos de Destiny Bond.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} levou\n{{pokemonNameWithAffix2}} junto com ele!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} se apaixonou\npor {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} já\nestá apaixonado!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} está apaixonado\npor {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} está\nimobilizado pelo amor!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} superou\nsua paixão.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} foi semeado!",
+ "battlerTagsSeededLapse": "A saúde de {{pokemonNameWithAffix}}\nfoi sugada pelo Leech Seed!",
+ "battlerTagsSeededLapseShed": "O Leech Seed de{{pokemonNameWithAffix}}\nsugou todo o gotejamento!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} começou\na ter um Nightmare!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} já\nestá preso em um Nightmare!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} está preso\nem um Nightmare!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} ganhou\num Encore!",
+ "battlerTagsEncoreOnRemove": "O Encore de {{pokemonNameWithAffix}}\nacabou!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} está pronto para\najudar {{pokemonName}}!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorveu\nnutrientes com suas raízes!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} plantou suas raízes!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} se cercou\ncom um véu de água!",
+ "battlerTagsAquaRingLapse": "{{moveName}} restaurou\nPS de {{pokemonName}}!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} ficou com sono!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} foi ferido\npelo {{moveName}}!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} foi espremido\npelo {{moveName}} de {{sourcePokemonName}}!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} foi enrolado\npor {{sourcePokemonName}}!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} ficou preso\nno vórtice!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} prendeu\n{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} foi preso\npor {{moveName}}!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} foi preso\npor um redemoinho de magma!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} foi preso\npor uma armadilha!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} prendeu\n{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} foi ferido por \numa infestação de {{sourcePokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nse protegeu!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nse protegeu!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} está\npreparado!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} suportou\no golpe!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} suportou\no golpe!",
+ "battlerTagsPerishSongLapse": "O tempo restante de {{pokemonNameWithAffix}} diminuiu para {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} está\nviajando na maionese!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} não\nestá preparado!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} finalmente\nconseguiu se recompor!",
+ "battlerTagsHighestStatBoostOnAdd": "O atributo de {{statName}} de\n{{pokemonNameWithAffix}} aumentou!",
+ "battlerTagsHighestStatBoostOnRemove": "Os efeitos do {{abilityName}} de\n{{pokemonNameWithAffix}} acabaram!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} está ficando\nbombado!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} relaxou.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} está sendo curado com sal!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} foi ferido pelo {{moveName}}!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cortou seus PS pela metade e amaldiçoou {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} foi ferido pelo Curse!"
} as const;
diff --git a/src/locales/pt_BR/challenges.ts b/src/locales/pt_BR/challenges.ts
index 98731fe890b..fd07fb5de3d 100644
--- a/src/locales/pt_BR/challenges.ts
+++ b/src/locales/pt_BR/challenges.ts
@@ -1,67 +1,25 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"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": "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.",
+ "singleGeneration": {
+ "name": "Geração Única",
+ "desc": "Você só pode user Pokémon da {{gen}} geração.",
+ "desc_default": "Você só pode user Pokémon de uma única geração.",
+ "gen_1": "primeira",
+ "gen_2": "segunda",
+ "gen_3": "terceira",
+ "gen_4": "quarta",
+ "gen_5": "quinta",
+ "gen_6": "sexta",
+ "gen_7": "sétima",
+ "gen_8": "oitava",
+ "gen_9": "nona",
+ },
+ "singleType": {
+ "name": "Tipo Único",
+ "desc": "Você só pode user Pokémon do tipo {{type}}.",
+ "desc_default": "Você só pode user Pokémon de um único tipo."
+ },
} as const;
diff --git a/src/locales/pt_BR/common.ts b/src/locales/pt_BR/common.ts
new file mode 100644
index 00000000000..d7cbfd5d052
--- /dev/null
+++ b/src/locales/pt_BR/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "Iniciar",
+} as const;
diff --git a/src/locales/pt_BR/config.ts b/src/locales/pt_BR/config.ts
index 8d34c1539ef..ba658d43938 100644
--- a/src/locales/pt_BR/config.ts
+++ b/src/locales/pt_BR/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/pt_BR/settings.js";
+import { common } from "#app/locales/pt_BR/common.js";
export const ptBrConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const ptBrConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/pt_BR/menu.ts b/src/locales/pt_BR/menu.ts
index 7490ea64ba8..2837ff55e26 100644
--- a/src/locales/pt_BR/menu.ts
+++ b/src/locales/pt_BR/menu.ts
@@ -52,5 +52,5 @@ export const menu: SimpleTranslationEntries = {
"yes": "Sim",
"no": "Não",
"disclaimer": "AVISO",
- "disclaimerDescription": "Este jogo é um produto inacabado; ele pode ter problemas de jogabilidade (incluindo possíveis perdas de dados salvos),\n sofrer alterações sem aviso prévio e pode ou não ser atualizado ou concluído.",
+ "disclaimerDescription": "Este jogo é um produto inacabado; ele pode ter problemas de jogabilidade (incluindo possíveis\n perdas de dados salvos), sofrer alterações sem aviso prévio e pode ou não ser atualizado ou concluído."
} as const;
diff --git a/src/locales/pt_BR/settings.ts b/src/locales/pt_BR/settings.ts
index 873d4ffd4a8..f094e64d495 100644
--- a/src/locales/pt_BR/settings.ts
+++ b/src/locales/pt_BR/settings.ts
@@ -3,96 +3,96 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales.js";
export const settings: SimpleTranslationEntries = {
"boy": "Menino",
"girl": "Menina",
- "general": "General",
- "display": "Display",
- "audio": "Audio",
- "gamepad": "Gamepad",
- "keyboard": "Keyboard",
- "gameSpeed": "Game Speed",
- "hpBarSpeed": "HP Bar Speed",
- "expGainsSpeed": "EXP Gains Speed",
- "expPartyDisplay": "Show EXP Party",
- "skipSeenDialogues": "Skip Seen Dialogues",
- "battleStyle": "Battle Style",
- "enableRetries": "Enable Retries",
- "tutorials": "Tutorials",
- "touchControls": "Touch Controls",
- "vibrations": "Vibrations",
+ "general": "Geral",
+ "display": "Exibição",
+ "audio": "Áudio",
+ "gamepad": "Controle",
+ "keyboard": "Teclado",
+ "gameSpeed": "Velocidade do Jogo",
+ "hpBarSpeed": "Velocidade da Barra de PS",
+ "expGainsSpeed": "Velocidade do Ganho de EXP",
+ "expPartyDisplay": "Exibição de EXP da Equipe",
+ "skipSeenDialogues": "Pular Diálogos Vistos",
+ "battleStyle": "Estilo de Batalha",
+ "enableRetries": "Habilitar Novas Tentativas",
+ "tutorials": "Tutorial",
+ "touchControls": "Controles de Toque",
+ "vibrations": "Vibração",
"normal": "Normal",
- "fast": "Fast",
- "faster": "Faster",
- "skip": "Skip",
- "levelUpNotifications": "Level Up Notifications",
- "on": "On",
- "off": "Off",
- "switch": "Switch",
- "set": "Set",
- "auto": "Auto",
- "disabled": "Disabled",
- "language": "Language",
- "change": "Change",
- "uiTheme": "UI Theme",
- "default": "Default",
- "legacy": "Legacy",
- "windowType": "Window Type",
- "moneyFormat": "Money Format",
- "damageNumbers": "Damage Numbers",
- "simple": "Simple",
- "fancy": "Fancy",
- "abbreviated": "Abbreviated",
- "moveAnimations": "Move Animations",
- "showStatsOnLevelUp": "Show Stats on Level Up",
- "candyUpgradeNotification": "Candy Upgrade Notification",
- "passivesOnly": "Passives Only",
- "candyUpgradeDisplay": "Candy Upgrade Display",
- "icon": "Icon",
- "animation": "Animation",
- "moveInfo": "Move Info",
- "showMovesetFlyout": "Show Moveset Flyout",
- "showArenaFlyout": "Show Arena Flyout",
- "showTimeOfDayWidget": "Show Time of Day Widget",
- "timeOfDayAnimation": "Time of Day Animation",
- "bounce": "Bounce",
- "timeOfDay_back": "Back",
- "spriteSet": "Sprite Set",
- "consistent": "Consistent",
- "mixedAnimated": "Mixed Animated",
- "fusionPaletteSwaps": "Fusion Palette Swaps",
- "playerGender": "Player Gender",
- "typeHints": "Type Hints",
- "masterVolume": "Master Volume",
- "bgmVolume": "BGM Volume",
- "seVolume": "SE Volume",
- "musicPreference": "Music Preference",
- "mixed": "Mixed",
- "gamepadPleasePlug": "Please Plug in a Gamepad or Press a Button",
- "delete": "Delete",
- "keyboardPleasePress": "Please Press a Key on Your Keyboard",
- "reset": "Reset",
- "requireReload": "Reload Required",
- "action": "Action",
- "back": "Back",
- "pressToBind": "Press to Bind",
- "pressButton": "Press a Button...",
- "buttonUp": "Up",
- "buttonDown": "Down",
- "buttonLeft": "Left",
- "buttonRight": "Right",
- "buttonAction": "Action",
+ "fast": "Rápido",
+ "faster": "Mais Rápido",
+ "skip": "Pular",
+ "levelUpNotifications": "Notificação",
+ "on": "Ligado",
+ "off": "Desligado",
+ "switch": "Alternar",
+ "set": "Definido",
+ "auto": "Automático",
+ "disabled": "Desativado",
+ "language": "Idioma",
+ "change": "Mudar",
+ "uiTheme": "Tema da Interface",
+ "default": "Padrão",
+ "legacy": "Legado",
+ "windowType": "Estilo da Janela",
+ "moneyFormat": "Formatação do Dinheiro",
+ "damageNumbers": "Números de Dano",
+ "simple": "Simples",
+ "fancy": "Detalhado",
+ "abbreviated": "Abreviado",
+ "moveAnimations": "Animações de Movimento",
+ "showStatsOnLevelUp": "Mostrar Atributos ao Subir de Nível",
+ "candyUpgradeNotification": "Exibir Melhorias com Doce",
+ "passivesOnly": "Passivas",
+ "candyUpgradeDisplay": "Modo Melhorias com Doce",
+ "icon": "Ícone",
+ "animation": "Animação",
+ "moveInfo": "Informações de Movimento",
+ "showMovesetFlyout": "Mostrar Flutuante de Movimentos",
+ "showArenaFlyout": "Mostrar Flutuante de Bioma",
+ "showTimeOfDayWidget": "Widget da Hora do Dia",
+ "timeOfDayAnimation": "Animação da Hora do Dia",
+ "bounce": "Saltar",
+ "timeOfDay_back": "Voltar",
+ "spriteSet": "Conjunto de Sprites",
+ "consistent": "Consistente",
+ "mixedAnimated": "Animado",
+ "fusionPaletteSwaps": "Cores da Paleta de Fusão",
+ "playerGender": "Gênero do Jogador",
+ "typeHints": "Dicas de Tipo",
+ "masterVolume": "Volume Mestre",
+ "bgmVolume": "Volume de BGM",
+ "seVolume": "Volume de SE",
+ "musicPreference": "Preferência de Música",
+ "mixed": "Misto",
+ "gamepadPleasePlug": "Conecte um controle ou pressione um botão",
+ "delete": "Deletar",
+ "keyboardPleasePress": "Pressione uma tecla",
+ "reset": "Redefinir",
+ "requireReload": "Requer Reinício",
+ "action": "Ação",
+ "back": "Voltar",
+ "pressToBind": "Pressione para Atribuir",
+ "pressButton": "Pressione um Botão...",
+ "buttonUp": "Cima",
+ "buttonDown": "Baixo",
+ "buttonLeft": "Esquerda",
+ "buttonRight": "Direita",
+ "buttonAction": "Ação",
"buttonMenu": "Menu",
- "buttonSubmit": "Submit",
- "buttonCancel": "Cancel",
- "buttonStats": "Stats",
- "buttonCycleForm": "Cycle Form",
- "buttonCycleShiny": "Cycle Shiny",
- "buttonCycleGender": "Cycle Gender",
- "buttonCycleAbility": "Cycle Ability",
- "buttonCycleNature": "Cycle Nature",
- "buttonCycleVariant": "Cycle Variant",
- "buttonSpeedUp": "Speed Up",
- "buttonSlowDown": "Slow Down",
+ "buttonSubmit": "Confirmar",
+ "buttonCancel": "Cancelar",
+ "buttonStats": "Atributos",
+ "buttonCycleForm": "Próxima Forma",
+ "buttonCycleShiny": "Próximo Shiny",
+ "buttonCycleGender": "Próximo Gênero",
+ "buttonCycleAbility": "Próxima Habilidade",
+ "buttonCycleNature": "Próxima Natureza",
+ "buttonCycleVariant": "Próxima Variante",
+ "buttonSpeedUp": "Acelerar",
+ "buttonSlowDown": "Desacelerar",
"alt": " (Alt)",
- "mute": "Mute",
- "controller": "Controller",
- "gamepadSupport": "Gamepad Support"
+ "mute": "Mudo",
+ "controller": "Controle",
+ "gamepadSupport": "Suporte para Controle"
} as const;
diff --git a/src/locales/pt_BR/starter-select-ui-handler.ts b/src/locales/pt_BR/starter-select-ui-handler.ts
index 64a2ceff7c3..0b349468aee 100644
--- a/src/locales/pt_BR/starter-select-ui-handler.ts
+++ b/src/locales/pt_BR/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "Passiva:",
"nature": "Natureza:",
"eggMoves": "Mov. de Ovo",
- "start": "Iniciar",
"addToParty": "Adicionar à equipe",
"toggleIVs": "Mostrar IVs",
"manageMoves": "Mudar Movimentos",
diff --git a/src/locales/zh_CN/battle.ts b/src/locales/zh_CN/battle.ts
index 4b2b881f6b2..9da9e632f69 100644
--- a/src/locales/zh_CN/battle.ts
+++ b/src/locales/zh_CN/battle.ts
@@ -71,4 +71,61 @@ export const battle: SimpleTranslationEntries = {
"statSeverelyFell": "极大幅降低了!",
"statWontGoAnyLower": "已经无法再降低了!",
"ppReduced": "降低了 {{targetName}} 的\n{{moveName}} 的PP{{reduction}}点!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}因攻击的反作用力而无法动弹!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}不能逃跑!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}摆脱了{{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}畏缩了!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}混乱了!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}的混乱解除了!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}已经混乱了。",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}正在混乱中!",
+ "battlerTagsConfusedLapseHurtItself": "不知所以地攻击了自己!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}}不再受到同命的影响",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} 和{{pokemonNameWithAffix2}} 同归于尽了!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}对{{sourcePokemonName}}着迷了!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}}已经着迷了!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}}对{{sourcePokemonName}}着迷中!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} 不会着迷!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} 治愈了着迷状态!",
+ "battlerTagsSeededOnAdd": "将种子种植在了{{pokemonNameWithAffix}}身上!",
+ "battlerTagsSeededLapse": "{{pokemonNameWithAffix}}被寄生种子吸取了体力!",
+ "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}吸到了污泥浆!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}开始做恶梦了!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}已经被恶梦缠身!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}正被恶梦缠身!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}}接受了再来一次!",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}的再来一次状态解除了!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}摆出了帮助{{pokemonName}} 的架势!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}用扎根回复了体力!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}扎根了!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}用水流环包裹了自己!",
+ "battlerTagsAquaRingLapse": "{{moveName}}回复了{{pokemonName}}的体力!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}}产生睡意了!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}受到了{{moveName}}的伤害!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}被{{sourcePokemonName}}的 {{moveName}}紧紧束缚住了!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}被{{sourcePokemonName}}绑紧了!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}被困在了旋涡之中!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}}用贝壳夹住了{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}被{{moveName}}困住了!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}被困在了熔岩风暴之中!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}被捕兽夹困住了!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}困住了{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}}受到了{{sourcePokemonNameWithAffix}}的死缠烂打!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}摆出了防守的架势!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}在攻击中保护了自己!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}摆出了挺住攻击的架势!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}挺住了攻击!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}挺住了攻击!",
+ "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}} 的灭亡计时变成{{turnCount}}了!",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}}正在偷懒!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}无法拿出平时的水平!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}恢复了平时的水平!",
+ "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}的{{statName}}升高了!",
+ "battlerTagsHighestStatBoostOnRemove": "{{pokemonNameWithAffix}}的{{abilityName}}效果解除了!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}现在干劲十足!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}如释重负似地放松了下来。",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} 陷入了盐腌状态!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} 受到了{{moveName}}的伤害!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}削减了自己的体力,并诅咒了{{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}}正受到诅咒!"
} as const;
diff --git a/src/locales/zh_CN/challenges.ts b/src/locales/zh_CN/challenges.ts
index 697a97bda09..d15a725fbb0 100644
--- a/src/locales/zh_CN/challenges.ts
+++ b/src/locales/zh_CN/challenges.ts
@@ -1,67 +1,25 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "适用挑战条件",
- "points": "Bad Ideas",
- "confirm_start": "要执行这些挑战吗?",
- "singleGeneration.name": "单一世代",
- "singleGeneration.value.0": "关闭",
- "singleGeneration.desc.0": "你只能使用所选世代的宝可梦",
- "singleGeneration.value.1": "第一世代",
- "singleGeneration.desc.1": "你只能使用第一世代的宝可梦",
- "singleGeneration.value.2": "第二世代",
- "singleGeneration.desc.2": "你只能使用第二世代的宝可梦",
- "singleGeneration.value.3": "第三世代",
- "singleGeneration.desc.3": "你只能使用第三世代的宝可梦",
- "singleGeneration.value.4": "第四世代",
- "singleGeneration.desc.4": "你只能使用第四世代的宝可梦",
- "singleGeneration.value.5": "第五世代",
- "singleGeneration.desc.5": "你只能使用第五世代的宝可梦",
- "singleGeneration.value.6": "第六世代",
- "singleGeneration.desc.6": "你只能使用第六世代的宝可梦",
- "singleGeneration.value.7": "第七世代",
- "singleGeneration.desc.7": "你只能使用第七世代的宝可梦",
- "singleGeneration.value.8": "第八世代",
- "singleGeneration.desc.8": "你只能使用第八世代的宝可梦",
- "singleGeneration.value.9": "第九世代",
- "singleGeneration.desc.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": "你只能使用妖精属性的宝可梦",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "单一世代",
+ "desc": "你只能使用第{{gen}}世代的宝可梦",
+ "desc_default": "你只能使用所选世代的宝可梦",
+ "gen_1": "一",
+ "gen_2": "二",
+ "gen_3": "三",
+ "gen_4": "四",
+ "gen_5": "五",
+ "gen_6": "六",
+ "gen_7": "七",
+ "gen_8": "八",
+ "gen_9": "九",
+ },
+ "singleType": {
+ "name": "单属性",
+ "desc": "你只能使用{{type}}属性的宝可梦",
+ "desc_default": "你只能使用所选属性的宝可梦"
+ },
} as const;
diff --git a/src/locales/zh_CN/common.ts b/src/locales/zh_CN/common.ts
new file mode 100644
index 00000000000..29f54ff0dc9
--- /dev/null
+++ b/src/locales/zh_CN/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "开始",
+} as const;
diff --git a/src/locales/zh_CN/config.ts b/src/locales/zh_CN/config.ts
index fdc54cb2be0..ecef682581f 100644
--- a/src/locales/zh_CN/config.ts
+++ b/src/locales/zh_CN/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/zh_CN/settings.js";
+import { common } from "#app/locales/zh_CN/common.js";
export const zhCnConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const zhCnConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/locales/zh_CN/modifier-type.ts b/src/locales/zh_CN/modifier-type.ts
index 52971fe08f3..bbea9d45537 100644
--- a/src/locales/zh_CN/modifier-type.ts
+++ b/src/locales/zh_CN/modifier-type.ts
@@ -93,7 +93,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "招式命中率增加{{accuracyAmount}} (最大100)。",
},
"PokemonMultiHitModifierType": {
- description: "攻击造成一次额外伤害,\n每堆叠一件会让攻击伤害\n衰减60/75/82.5%。",
+ description: "攻击以40/25/12.5%的伤害造成2/3/4次伤害",
},
"TmModifierType": {
name: "招式学习器 {{moveId}} - {{moveName}}",
diff --git a/src/locales/zh_CN/settings.ts b/src/locales/zh_CN/settings.ts
index 04df61d7dbe..f37a59613f5 100644
--- a/src/locales/zh_CN/settings.ts
+++ b/src/locales/zh_CN/settings.ts
@@ -52,8 +52,8 @@ export const settings: SimpleTranslationEntries = {
"showArenaFlyout": "显示战场弹窗",
"showTimeOfDayWidget": "显示时间指示器",
"timeOfDayAnimation": "时间指示器动画",
- "bounce": "彈一下",
- "timeOfDay_back": "不彈",
+ "bounce": "弹跳",
+ "timeOfDay_back": "不弹",
"spriteSet": "宝可梦动画",
"consistent": "默认",
"mixedAnimated": "全部动画",
diff --git a/src/locales/zh_CN/starter-select-ui-handler.ts b/src/locales/zh_CN/starter-select-ui-handler.ts
index 669b8a5bb80..05824853e40 100644
--- a/src/locales/zh_CN/starter-select-ui-handler.ts
+++ b/src/locales/zh_CN/starter-select-ui-handler.ts
@@ -21,7 +21,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"passive": "被动:",
"nature": "性格:",
"eggMoves": "蛋招式",
- "start": "开始",
"addToParty": "加入队伍",
"toggleIVs": "切换个体值",
"manageMoves": "管理招式",
diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts
index f8179c50887..b4d0aa9d50e 100644
--- a/src/locales/zh_TW/battle.ts
+++ b/src/locales/zh_TW/battle.ts
@@ -68,4 +68,61 @@ export const battle: SimpleTranslationEntries = {
"statSeverelyFell": "severely fell",
"statWontGoAnyLower": "won't go any lower",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
+ "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!",
+ "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!",
+ "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} was freed\nfrom {{moveName}}",
+ "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} flinched!",
+ "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} became\nconfused!",
+ "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} snapped\nout of confusion!",
+ "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} is\nalready confused!",
+ "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} is\nconfused!",
+ "battlerTagsConfusedLapseHurtItself": "It hurt itself in its\nconfusion!",
+ "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} is unaffected\nby the effects of Destiny Bond.",
+ "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} took\n{{pokemonNameWithAffix2}} down with it!",
+ "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} fell in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} is\nalready in love!",
+ "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} is in love\nwith {{sourcePokemonName}}!",
+ "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} is\nimmobilized by love!",
+ "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} got over\nits infatuation.",
+ "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} was seeded!",
+ "battlerTagsSeededLapse": "{{pokemonNameWithAffix}}'s health is\nsapped by Leech Seed!",
+ "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}'s Leech Seed\nsucked up the liquid ooze!",
+ "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} began\nhaving a Nightmare!",
+ "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} is\nalready locked in a Nightmare!",
+ "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} is locked\nin a Nightmare!",
+ "battlerTagsEncoreOnAdd": "({{pokemonNameWithAffix}} got\nan Encore!",
+ "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}'s Encore\nended!",
+ "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} is ready to\nhelp {{pokemonName}}!",
+ "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorbed\nnutrients with its roots!",
+ "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} planted its roots!",
+ "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} surrounded\nitself with a veil of water!",
+ "battlerTagsAquaRingLapse": "{{moveName}} restored\n{{pokemonName}}'s HP!",
+ "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} grew drowsy!",
+ "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} is hurt\nby {{moveName}}!",
+ "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} was squeezed by\n{{sourcePokemonName}}'s {{moveName}}!",
+ "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} was Wrapped\nby {{sourcePokemonName}}!",
+ "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} was trapped\nin the vortex!",
+ "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} Clamped\n{{pokemonName}}!",
+ "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} became trapped\nby {{moveName}}!",
+ "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} became trapped\nby swirling magma!",
+ "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} got trapped\nby a snap trap!",
+ "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} trapped\n{{pokemonNameWithAffix}}!",
+ "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} has been afflicted \nwith an infestation by {{sourcePokemonNameWithAffix}}!",
+ "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nprotected itself!",
+ "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} braced\nitself!",
+ "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} endured\nthe hit!",
+ "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}'s perish count fell to {{turnCount}}.",
+ "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} is\nloafing around!",
+ "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} can't\nget it going!",
+ "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} finally\ngot its act together!",
+ "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}'s {{statName}}\nwas heightened!",
+ "battlerTagsHighestStatBoostOnRemove": "The effects of {{pokemonNameWithAffix}}'s\n{{abilityName}} wore off!",
+ "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} is getting\npumped!",
+ "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} relaxed.",
+ "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} is being salt cured!",
+ "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
+ "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!"
} as const;
diff --git a/src/locales/zh_TW/challenges.ts b/src/locales/zh_TW/challenges.ts
index 9da058001b1..6b46ac8c7ab 100644
--- a/src/locales/zh_TW/challenges.ts
+++ b/src/locales/zh_TW/challenges.ts
@@ -1,67 +1,25 @@
-import { SimpleTranslationEntries } from "#app/interfaces/locales";
+import { TranslationEntries } from "#app/interfaces/locales";
-export const challenges: SimpleTranslationEntries = {
+export const challenges: TranslationEntries = {
"title": "適用挑戰條件",
- "points": "Bad Ideas",
- "confirm_start": "要執行這些挑戰嗎?",
- "singleGeneration.name": "單一世代",
- "singleGeneration.value.0": "關閉",
- "singleGeneration.desc.0": "你只能使用所選世代的寶可夢",
- "singleGeneration.value.1": "第一世代",
- "singleGeneration.desc.1": "你只能使用第一世代的寶可夢",
- "singleGeneration.value.2": "第二世代",
- "singleGeneration.desc.2": "你只能使用第二世代的寶可夢",
- "singleGeneration.value.3": "第三世代",
- "singleGeneration.desc.3": "你只能使用第三世代的寶可夢",
- "singleGeneration.value.4": "第四世代",
- "singleGeneration.desc.4": "你只能使用第四世代的寶可夢",
- "singleGeneration.value.5": "第五世代",
- "singleGeneration.desc.5": "你只能使用第五世代的寶可夢",
- "singleGeneration.value.6": "第六世代",
- "singleGeneration.desc.6": "你只能使用第六世代的寶可夢",
- "singleGeneration.value.7": "第七世代",
- "singleGeneration.desc.7": "你只能使用第七世代的寶可夢",
- "singleGeneration.value.8": "第八世代",
- "singleGeneration.desc.8": "你只能使用第八世代的寶可夢",
- "singleGeneration.value.9": "第九世代",
- "singleGeneration.desc.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": "你只能使用妖精屬性的寶可夢",
+ "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
+ "singleGeneration": {
+ "name": "單一世代",
+ "desc": "你只能使用第{{gen}}世代的寶可夢",
+ "desc_default": "你只能使用所選世代的寶可夢",
+ "gen_1": "一",
+ "gen_2": "二",
+ "gen_3": "三",
+ "gen_4": "四",
+ "gen_5": "五",
+ "gen_6": "六",
+ "gen_7": "七",
+ "gen_8": "八",
+ "gen_9": "九",
+ },
+ "singleType": {
+ "name": "單屬性",
+ "desc": "你只能使用{{type}}屬性的寶可夢",
+ "desc_default": "你只能使用所選屬性的寶可夢"
+ },
} as const;
diff --git a/src/locales/zh_TW/common.ts b/src/locales/zh_TW/common.ts
new file mode 100644
index 00000000000..c3dc42785ee
--- /dev/null
+++ b/src/locales/zh_TW/common.ts
@@ -0,0 +1,5 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const common: SimpleTranslationEntries = {
+ "start": "開始",
+} as const;
diff --git a/src/locales/zh_TW/config.ts b/src/locales/zh_TW/config.ts
index 5d6a2dd978d..08063f9f154 100644
--- a/src/locales/zh_TW/config.ts
+++ b/src/locales/zh_TW/config.ts
@@ -40,6 +40,7 @@ import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/zh_TW/settings.js";
+import { common } from "#app/locales/zh_TW/common.js";
export const zhTwConfig = {
ability: ability,
@@ -50,6 +51,7 @@ export const zhTwConfig = {
biome: biome,
challenges: challenges,
commandUiHandler: commandUiHandler,
+ common: common,
PGMachv: PGMachv,
PGFachv: PGFachv,
PGMdialogue: PGMdialogue,
diff --git a/src/main.ts b/src/main.ts
index e750335ddd4..41cd68afc1e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -150,7 +150,6 @@ Phaser.GameObjects.Text.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Rectangle.prototype.setPositionRelative = setPositionRelative;
document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems"));
-document.fonts.load("12px unifont");
let game;
diff --git a/src/phases.ts b/src/phases.ts
index 1ae15dc6caf..fe24664d98c 100644
--- a/src/phases.ts
+++ b/src/phases.ts
@@ -26,7 +26,7 @@ import { Gender } from "./data/gender";
import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
-import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr, WonderSkinAbAttr, applyPreDefendAbAttrs, FieldPreventMovesAbAttr, IgnoreMoveEffectsAbAttr } from "./data/ability";
+import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr, WonderSkinAbAttr, applyPreDefendAbAttrs, FieldPreventMovesAbAttr, IgnoreMoveEffectsAbAttr, BlockStatusDamageAbAttr } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@@ -3505,6 +3505,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
pokemon.status.incrementTurn();
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
+ applyAbAttrs(BlockStatusDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectActivationText(pokemon.status.effect)));
diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts
index 14e5c74f12c..3bcac101465 100644
--- a/src/plugins/i18n.ts
+++ b/src/plugins/i18n.ts
@@ -12,12 +12,45 @@ import { ptBrConfig } from "#app/locales/pt_BR/config.js";
import { zhCnConfig } from "#app/locales/zh_CN/config.js";
import { zhTwConfig } from "#app/locales/zh_TW/config.js";
+const unicodeHalfAndFullWidthForms = [
+ "U+FF00-FFEF"
+];
+
+const unicodeCJK = [
+ "U+2E80-2EFF",
+ "U+3000-303F",
+ "U+31C0-31EF",
+ "U+3200-32FF",
+ "U+3400-4DBF",
+ "U+4E00-9FFF",
+ "U+F900-FAFF",
+ "U+FE30-FE4F",
+].join(",");
+
+const unicodeHangul = [
+ "U+1100-11FF",
+ "U+3130-318F",
+ "U+A960-A97F",
+ "U+AC00-D7AF",
+ "U+D7B0-D7FF",
+].join(",");
+
const fonts = [
- new FontFace("emerald", "url(./fonts/PokePT_Wansung.ttf)", { unicodeRange: "U+AC00-D7AC"}),
+ // korean
+ new FontFace("emerald", "url(./fonts/PokePT_Wansung.ttf)", { unicodeRange: unicodeHangul}),
Object.assign(
- new FontFace("pkmnems", "url(./fonts/PokePT_Wansung.ttf)", { unicodeRange: "U+AC00-D7AC"}),
+ new FontFace("pkmnems", "url(./fonts/PokePT_Wansung.ttf)", { unicodeRange: unicodeHangul}),
{ sizeAdjust: "133%" }
),
+ // unicode
+ Object.assign(
+ new FontFace("emerald", "url(./fonts/unifont-15.1.05.otf)", { unicodeRange: [unicodeCJK, unicodeHalfAndFullWidthForms].join(",") }),
+ { sizeAdjust: "70%", format: "opentype" }
+ ),
+ Object.assign(
+ new FontFace("pkmnems", "url(./fonts/unifont-15.1.05.otf)", { unicodeRange: [unicodeCJK, unicodeHalfAndFullWidthForms].join(",") }),
+ { format: "opentype" }
+ ),
];
async function initFonts() {
diff --git a/src/scene-base.ts b/src/scene-base.ts
index 48b7238387c..1d7a2518300 100644
--- a/src/scene-base.ts
+++ b/src/scene-base.ts
@@ -1,6 +1,19 @@
export const legacyCompatibleImages: string[] = [];
export class SceneBase extends Phaser.Scene {
+ /**
+ * Since everything is scaled up by 6 by default using the game.canvas is annoying
+ * Until such point that we use the canvas normally, this will be easier than
+ * having to divide every width and heigh by 6 to position and scale the ui
+ * @readonly
+ * @defaultValue
+ * width: `320`
+ * height: `180`
+ */
+ public readonly scaledCanvas = {
+ width: 1920 / 6,
+ height: 1080 / 6
+ };
constructor(config?: string | Phaser.Types.Scenes.SettingsConfig) {
super(config);
}
diff --git a/src/test/abilities/battery.test.ts b/src/test/abilities/battery.test.ts
index 93bac836f61..4a5cdc47172 100644
--- a/src/test/abilities/battery.test.ts
+++ b/src/test/abilities/battery.test.ts
@@ -3,7 +3,6 @@ import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
-import { TurnEndPhase, } from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import Move, { allMoves, MoveCategory } from "#app/data/move.js";
@@ -44,8 +43,6 @@ describe("Abilities - Battery", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[1]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).not.toBe(basePower);
expect(appliedPower).toBe(basePower * multiplier);
@@ -63,8 +60,6 @@ describe("Abilities - Battery", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[1]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).toBe(basePower);
expect(appliedPower).not.toBe(basePower * multiplier);
@@ -82,8 +77,6 @@ describe("Abilities - Battery", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[0]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).toBe(basePower);
expect(appliedPower).not.toBe(basePower * multiplier);
diff --git a/src/test/abilities/ice_face.test.ts b/src/test/abilities/ice_face.test.ts
index 759b036770a..09fd8733f93 100644
--- a/src/test/abilities/ice_face.test.ts
+++ b/src/test/abilities/ice_face.test.ts
@@ -4,6 +4,7 @@ import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
import {
+ MoveEffectPhase,
MoveEndPhase,
TurnEndPhase,
TurnInitPhase,
@@ -52,6 +53,34 @@ describe("Abilities - Ice Face", () => {
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined);
});
+ it("takes no damage from the first hit of multihit physical move and transforms to Noice", async () => {
+ vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SURGING_STRIKES]);
+ vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(5);
+ await game.startBattle([Species.HITMONLEE]);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES));
+
+ const eiscue = game.scene.getEnemyPokemon();
+ expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
+
+ // First hit
+ await game.phaseInterceptor.to(MoveEffectPhase);
+ expect(eiscue.hp).equals(eiscue.getMaxHp());
+ expect(eiscue.formIndex).toBe(icefaceForm);
+ expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
+
+ // Second hit
+ await game.phaseInterceptor.to(MoveEffectPhase);
+ expect(eiscue.hp).lessThan(eiscue.getMaxHp());
+ expect(eiscue.formIndex).toBe(noiceForm);
+
+ await game.phaseInterceptor.to(MoveEndPhase);
+
+ expect(eiscue.hp).lessThan(eiscue.getMaxHp());
+ expect(eiscue.formIndex).toBe(noiceForm);
+ expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
+ });
+
it("takes damage from special moves", async () => {
await game.startBattle([Species.MAGIKARP]);
diff --git a/src/test/abilities/power_spot.test.ts b/src/test/abilities/power_spot.test.ts
index 5450aee9742..3bf2e7b72d2 100644
--- a/src/test/abilities/power_spot.test.ts
+++ b/src/test/abilities/power_spot.test.ts
@@ -3,7 +3,6 @@ import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
-import { TurnEndPhase, } from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import Move, { allMoves, MoveCategory } from "#app/data/move.js";
@@ -44,8 +43,6 @@ describe("Abilities - Power Spot", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[1]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).not.toBe(basePower);
expect(appliedPower).toBe(basePower * multiplier);
@@ -63,8 +60,6 @@ describe("Abilities - Power Spot", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[1]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).not.toBe(basePower);
expect(appliedPower).toBe(basePower * multiplier);
@@ -82,8 +77,6 @@ describe("Abilities - Power Spot", () => {
const multiplier = getAttrPowerMultiplier(game.scene.getPlayerField()[0]);
const appliedPower = getAppliedMovePower(game.scene.getEnemyField()[0], game.scene.getPlayerField()[0], allMoves[moveToBeUsed]);
- await game.phaseInterceptor.to(TurnEndPhase);
-
expect(appliedPower).not.toBe(undefined);
expect(appliedPower).toBe(basePower);
expect(appliedPower).not.toBe(basePower * multiplier);
diff --git a/src/test/abilities/screen_cleaner.test.ts b/src/test/abilities/screen_cleaner.test.ts
index 1c9943fbfc8..d790469e952 100644
--- a/src/test/abilities/screen_cleaner.test.ts
+++ b/src/test/abilities/screen_cleaner.test.ts
@@ -27,6 +27,7 @@ describe("Abilities - Screen Cleaner", () => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.SCREEN_CLEANER);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SHUCKLE);
});
it("removes Aurora Veil", async () => {
diff --git a/src/test/abilities/unseen_fist.test.ts b/src/test/abilities/unseen_fist.test.ts
index a799e203f03..c53be8c82a4 100644
--- a/src/test/abilities/unseen_fist.test.ts
+++ b/src/test/abilities/unseen_fist.test.ts
@@ -31,6 +31,7 @@ describe("Abilities - Unseen Fist", () => {
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
+ vi.spyOn(Overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
});
test(
@@ -81,7 +82,7 @@ async function testUnseenFistHitResult(game: GameManager, attackMove: Moves, pro
const enemyStartingHp = enemyPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, attackMove));
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
if (shouldSucceed) {
expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
diff --git a/src/test/abilities/wind_power.test.ts b/src/test/abilities/wind_power.test.ts
new file mode 100644
index 00000000000..89957362268
--- /dev/null
+++ b/src/test/abilities/wind_power.test.ts
@@ -0,0 +1,97 @@
+import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import Phaser from "phaser";
+import GameManager from "#app/test/utils/gameManager";
+import * as overrides from "#app/overrides";
+import { Species } from "#enums/species";
+import {
+ TurnEndPhase,
+} from "#app/phases";
+import { Moves } from "#enums/moves";
+import { getMovePosition } from "#app/test/utils/gameManagerUtils";
+import { Abilities } from "#enums/abilities";
+import { BattlerTagType } from "#app/enums/battler-tag-type.js";
+
+describe("Abilities - Wind Power", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SHIFTRY);
+ vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_POWER);
+ vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
+ vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
+ });
+
+ it("it becomes charged when hit by wind moves", async () => {
+ await game.startBattle([Species.MAGIKARP]);
+ const shiftry = game.scene.getEnemyPokemon();
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.PETAL_BLIZZARD));
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeDefined();
+ });
+
+ it("it becomes charged when Tailwind takes effect on its side", async () => {
+ vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_POWER);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeDefined();
+ });
+
+ it("does not become charged when Tailwind takes effect on opposing side", async () => {
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+ vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_POWER);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const magikarp = game.scene.getEnemyPokemon();
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+ expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeDefined();
+ expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+ });
+
+ it("does not interact with Sandstorm", async () => {
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SANDSTORM));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
+ });
+});
diff --git a/src/test/abilities/wind_rider.test.ts b/src/test/abilities/wind_rider.test.ts
new file mode 100644
index 00000000000..2b9361f5839
--- /dev/null
+++ b/src/test/abilities/wind_rider.test.ts
@@ -0,0 +1,120 @@
+import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import Phaser from "phaser";
+import GameManager from "#app/test/utils/gameManager";
+import * as overrides from "#app/overrides";
+import { Species } from "#enums/species";
+import {
+ TurnEndPhase,
+} from "#app/phases";
+import { Moves } from "#enums/moves";
+import { getMovePosition } from "#app/test/utils/gameManagerUtils";
+import { Abilities } from "#enums/abilities";
+import { BattleStat } from "#app/data/battle-stat.js";
+
+describe("Abilities - Wind Rider", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SHIFTRY);
+ vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_RIDER);
+ vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
+ vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
+ });
+
+ it("takes no damage from wind moves and its Attack is increased by one stage when hit by one", async () => {
+ await game.startBattle([Species.MAGIKARP]);
+ const shiftry = game.scene.getEnemyPokemon();
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.PETAL_BLIZZARD));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.hp).equals(shiftry.getMaxHp());
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(1);
+ });
+
+ it("Attack is increased by one stage when Tailwind is present on its side", async () => {
+ vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_RIDER);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(1);
+ });
+
+ it("does not increase Attack when Tailwind is present on opposing side", async () => {
+ vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WIND_RIDER);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const magikarp = game.scene.getEnemyPokemon();
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(1);
+ expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ });
+
+ it("does not increase Attack when Tailwind is present on opposing side", async () => {
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const magikarp = game.scene.getEnemyPokemon();
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(1);
+ expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ });
+
+ it("does not interact with Sandstorm", async () => {
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+
+ await game.startBattle([Species.SHIFTRY]);
+ const shiftry = game.scene.getPlayerPokemon();
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ expect(shiftry.hp).equals(shiftry.getMaxHp());
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SANDSTORM));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0);
+ expect(shiftry.hp).lessThan(shiftry.getMaxHp());
+ });
+});
diff --git a/src/test/moves/follow_me.test.ts b/src/test/moves/follow_me.test.ts
index 54b972e7cc0..f0b80ab90c0 100644
--- a/src/test/moves/follow_me.test.ts
+++ b/src/test/moves/follow_me.test.ts
@@ -36,6 +36,7 @@ describe("Moves - Follow Me", () => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.AMOONGUSS);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
+ vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
});
@@ -53,7 +54,7 @@ describe("Moves - Follow Me", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- playerPokemon.forEach(p => p.hp = 200);
+ const playerStartingHp = playerPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME));
await game.phaseInterceptor.to(CommandPhase);
@@ -62,10 +63,10 @@ describe("Moves - Follow Me", () => {
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
- expect(playerPokemon[0].hp).toBeLessThan(200);
- expect(playerPokemon[1].hp).toBe(200);
+ expect(playerPokemon[0].hp).toBeLessThan(playerStartingHp[0]);
+ expect(playerPokemon[1].hp).toBe(playerStartingHp[1]);
}, TIMEOUT
);
@@ -82,18 +83,18 @@ describe("Moves - Follow Me", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- playerPokemon.forEach(p => p.hp = 200);
+ const playerStartingHp = playerPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME));
await game.phaseInterceptor.to(CommandPhase);
game.doAttack(getMovePosition(game.scene, 1, Moves.FOLLOW_ME));
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
playerPokemon.sort((a, b) => a.getBattleStat(Stat.SPD) - b.getBattleStat(Stat.SPD));
- expect(playerPokemon[1].hp).toBeLessThan(200);
- expect(playerPokemon[0].hp).toBe(200);
+ expect(playerPokemon[1].hp).toBeLessThan(playerStartingHp[1]);
+ expect(playerPokemon[0].hp).toBe(playerStartingHp[0]);
}, TIMEOUT
);
@@ -114,7 +115,7 @@ describe("Moves - Follow Me", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
@@ -124,10 +125,11 @@ describe("Moves - Follow Me", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY_2);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
// If redirection was bypassed, both enemies should be damaged
- enemyPokemon.forEach(p => expect(p.hp).toBeLessThan(200));
+ expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]);
+ expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]);
}, TIMEOUT
);
@@ -147,7 +149,7 @@ describe("Moves - Follow Me", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.SNIPE_SHOT));
await game.phaseInterceptor.to(SelectTargetPhase, false);
@@ -157,10 +159,11 @@ describe("Moves - Follow Me", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.SNIPE_SHOT));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY_2);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
// If redirection was bypassed, both enemies should be damaged
- enemyPokemon.forEach(p => expect(p.hp).toBeLessThan(200));
+ expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]);
+ expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]);
}, TIMEOUT
);
});
diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts
new file mode 100644
index 00000000000..063a17aead9
--- /dev/null
+++ b/src/test/moves/gastro_acid.test.ts
@@ -0,0 +1,93 @@
+import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import GameManager from "../utils/gameManager";
+import {
+ Moves
+} from "#app/enums/moves.js";
+import * as overrides from "#app/overrides";
+import { Abilities } from "#app/enums/abilities.js";
+import { BattlerIndex } from "#app/battle.js";
+import { getMovePosition } from "../utils/gameManagerUtils";
+import { MoveResult } from "#app/field/pokemon.js";
+import { Stat } from "#app/data/pokemon-stat.js";
+import { Species } from "#app/enums/species.js";
+
+const TIMEOUT = 20 * 1000;
+
+describe("Moves - Gastro Acid", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+ vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(1);
+ vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
+ vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.NONE);
+ vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.GASTRO_ACID, Moves.WATER_GUN, Moves.SPLASH, Moves.CORE_ENFORCER]);
+ vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.BIDOOF);
+ vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
+ vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WATER_ABSORB);
+ });
+
+ it("suppresses effect of ability", async () => {
+ /*
+ * Expected flow (enemies have WATER ABSORD, can only use SPLASH)
+ * - player mon 1 uses GASTRO ACID, player mon 2 uses SPLASH
+ * - both player mons use WATER GUN on their respective enemy mon
+ * - player mon 1 should have dealt damage, player mon 2 should have not
+ */
+
+ await game.startBattle();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID));
+ game.doSelectTarget(BattlerIndex.ENEMY);
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ game.doSelectTarget(BattlerIndex.PLAYER_2);
+
+ await game.phaseInterceptor.to("TurnInitPhase");
+
+ const enemyField = game.scene.getEnemyField();
+ expect(enemyField[0].summonData.abilitySuppressed).toBe(true);
+ expect(enemyField[1].summonData.abilitySuppressed).toBe(false);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
+ game.doSelectTarget(BattlerIndex.ENEMY);
+ game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
+ game.doSelectTarget(BattlerIndex.ENEMY_2);
+
+ await game.phaseInterceptor.to("TurnEndPhase");
+
+ expect(enemyField[0].hp).toBeLessThan(enemyField[0].getMaxHp());
+ expect(enemyField[1].hp).toBe(enemyField[1].getMaxHp());
+ }, TIMEOUT);
+
+ it("fails if used on an enemy with an already-suppressed ability", async () => {
+ vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(false);
+
+ await game.startBattle();
+
+ // Force player to be slower to enable Core Enforcer to proc its suppression effect
+ game.scene.getPlayerPokemon().stats[Stat.SPD] = 1;
+ game.scene.getEnemyPokemon().stats[Stat.SPD] = 2;
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER));
+
+ await game.phaseInterceptor.to("TurnInitPhase");
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID));
+
+ await game.phaseInterceptor.to("TurnInitPhase");
+
+ expect(game.scene.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL);
+ }, TIMEOUT);
+});
diff --git a/src/test/moves/rage_powder.test.ts b/src/test/moves/rage_powder.test.ts
index 6a204877150..1116810f743 100644
--- a/src/test/moves/rage_powder.test.ts
+++ b/src/test/moves/rage_powder.test.ts
@@ -35,6 +35,7 @@ describe("Moves - Rage Powder", () => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.AMOONGUSS);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
+ vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
});
@@ -54,7 +55,7 @@ describe("Moves - Rage Powder", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
@@ -64,10 +65,11 @@ describe("Moves - Rage Powder", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY_2);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
// If redirection was bypassed, both enemies should be damaged
- enemyPokemon.forEach(p => expect(p.hp).toBeLessThan(200));
+ expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]);
+ expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]);
}, TIMEOUT
);
@@ -88,7 +90,7 @@ describe("Moves - Rage Powder", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
@@ -98,10 +100,11 @@ describe("Moves - Rage Powder", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY_2);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
// If redirection was bypassed, both enemies should be damaged
- enemyPokemon.forEach(p => expect(p.hp).toBeLessThan(200));
+ expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]);
+ expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]);
}, TIMEOUT
);
});
diff --git a/src/test/moves/spotlight.test.ts b/src/test/moves/spotlight.test.ts
index 188207b713c..ec3f4977007 100644
--- a/src/test/moves/spotlight.test.ts
+++ b/src/test/moves/spotlight.test.ts
@@ -35,6 +35,7 @@ describe("Moves - Spotlight", () => {
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.AMOONGUSS);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
+ vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
});
@@ -52,7 +53,7 @@ describe("Moves - Spotlight", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.doAttack(getMovePosition(game.scene, 0, Moves.SPOTLIGHT));
await game.phaseInterceptor.to(SelectTargetPhase, false);
@@ -62,10 +63,10 @@ describe("Moves - Spotlight", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(BattlerIndex.ENEMY_2);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
- expect(enemyPokemon[0].hp).toBeLessThan(200);
- expect(enemyPokemon[1].hp).toBe(200);
+ expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]);
+ expect(enemyPokemon[1].hp).toBe(enemyStartingHp[1]);
}, TIMEOUT
);
@@ -84,8 +85,6 @@ describe("Moves - Spotlight", () => {
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
- enemyPokemon.forEach(p => p.hp = 200);
-
/**
* Spotlight will target the slower enemy. In this situation without Spotlight being used,
* the faster enemy would normally end up with the Center of Attention tag.
@@ -94,6 +93,8 @@ describe("Moves - Spotlight", () => {
const spotTarget = enemyPokemon[1].getBattlerIndex();
const attackTarget = enemyPokemon[0].getBattlerIndex();
+ const enemyStartingHp = enemyPokemon.map(p => p.hp);
+
game.doAttack(getMovePosition(game.scene, 0, Moves.SPOTLIGHT));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(spotTarget);
@@ -102,10 +103,10 @@ describe("Moves - Spotlight", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(SelectTargetPhase, false);
game.doSelectTarget(attackTarget);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to(TurnEndPhase, false);
- expect(enemyPokemon[1].hp).toBeLessThan(200);
- expect(enemyPokemon[0].hp).toBe(200);
+ expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]);
+ expect(enemyPokemon[0].hp).toBe(enemyStartingHp[0]);
}, TIMEOUT
);
});
diff --git a/src/test/moves/tailwind.test.ts b/src/test/moves/tailwind.test.ts
new file mode 100644
index 00000000000..efba97f8fe1
--- /dev/null
+++ b/src/test/moves/tailwind.test.ts
@@ -0,0 +1,108 @@
+import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import Phaser from "phaser";
+import GameManager from "#app/test/utils/gameManager";
+import * as overrides from "#app/overrides";
+import { Species } from "#enums/species";
+import {
+ TurnEndPhase,
+} from "#app/phases";
+import { Moves } from "#enums/moves";
+import { getMovePosition } from "#app/test/utils/gameManagerUtils";
+import { Stat } from "#app/data/pokemon-stat.js";
+import { ArenaTagType } from "#app/enums/arena-tag-type.js";
+import { ArenaTagSide } from "#app/data/arena-tag.js";
+
+describe("Abilities - Wind Rider", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+ vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
+ vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
+ });
+
+ it("doubles the Speed stat of the Pokemons on its side", async () => {
+ await game.startBattle([Species.MAGIKARP, Species.MEOWTH]);
+ const magikarp = game.scene.getPlayerField()[0];
+ const meowth = game.scene.getPlayerField()[1];
+
+ const magikarpSpd = magikarp.getStat(Stat.SPD);
+ const meowthSpd = meowth.getStat(Stat.SPD);
+
+ expect(magikarp.getBattleStat(Stat.SPD)).equal(magikarpSpd);
+ expect(meowth.getBattleStat(Stat.SPD)).equal(meowthSpd);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+ game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(magikarp.getBattleStat(Stat.SPD)).toBe(magikarpSpd * 2);
+ expect(meowth.getBattleStat(Stat.SPD)).toBe(meowthSpd * 2);
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined();
+ });
+
+ it("lasts for 4 turns", async () => {
+ vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(false);
+ vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+
+ await game.startBattle([Species.MAGIKARP]);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+ await game.toNextTurn();
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ await game.toNextTurn();
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ await game.toNextTurn();
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ await game.toNextTurn();
+
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeUndefined();
+ });
+
+ it("does not affect the opposing side", async () => {
+ vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(false);
+ vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+
+ await game.startBattle([Species.MAGIKARP]);
+
+ const ally = game.scene.getPlayerPokemon();
+ const enemy = game.scene.getEnemyPokemon();
+
+ const allySpd = ally.getStat(Stat.SPD);
+ const enemySpd = enemy.getStat(Stat.SPD);
+
+
+ expect(ally.getBattleStat(Stat.SPD)).equal(allySpd);
+ expect(enemy.getBattleStat(Stat.SPD)).equal(enemySpd);
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeUndefined();
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.ENEMY)).toBeUndefined();
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND));
+
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(ally.getBattleStat(Stat.SPD)).toBe(allySpd * 2);
+ expect(enemy.getBattleStat(Stat.SPD)).equal(enemySpd);
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined();
+ expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.ENEMY)).toBeUndefined();
+ });
+});
diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts
index 18ff40aec50..f81f24af9bb 100644
--- a/src/timed-event-manager.ts
+++ b/src/timed-event-manager.ts
@@ -18,7 +18,7 @@ const timedEvents: TimedEvent[] = [
eventType: EventType.SHINY,
shinyMultiplier: 2,
startDate: new Date(Date.UTC(2024, 5, 14, 0)),
- endDate: new Date(Date.UTC(2024, 5, 21, 0)),
+ endDate: new Date(Date.UTC(2024, 5, 22, 0)),
bannerFilename: "pride-update"
},
];
diff --git a/src/ui/arena-flyout.ts b/src/ui/arena-flyout.ts
index 0568d1524aa..963b1ac4eb1 100644
--- a/src/ui/arena-flyout.ts
+++ b/src/ui/arena-flyout.ts
@@ -1,6 +1,6 @@
import { addTextObject, TextStyle } from "./text";
import BattleScene from "#app/battle-scene.js";
-import { ArenaTagSide } from "#app/data/arena-tag.js";
+import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag.js";
import { WeatherType } from "#app/data/weather.js";
import { TerrainType } from "#app/data/terrain.js";
import { addWindow, WindowVariant } from "./ui-theme";
@@ -23,12 +23,14 @@ interface ArenaEffectInfo {
/** The enum string representation of the effect */
name: string;
/** {@linkcode ArenaEffectType} type of effect */
- type: ArenaEffectType,
+ effecType: ArenaEffectType,
/** The maximum duration set by the effect */
maxDuration: number;
/** The current duration left on the effect */
duration: number;
+ /** The arena tag type being added */
+ tagType?: ArenaTagType;
}
export default class ArenaFlyout extends Phaser.GameObjects.Container {
@@ -213,7 +215,7 @@ export default class ArenaFlyout extends Phaser.GameObjects.Container {
// Creates a proxy object to decide which text object needs to be updated
let textObject: Phaser.GameObjects.Text;
- switch (fieldEffectInfo.type) {
+ switch (fieldEffectInfo.effecType) {
case ArenaEffectType.PLAYER:
textObject = this.flyoutTextPlayer;
break;
@@ -231,7 +233,7 @@ export default class ArenaFlyout extends Phaser.GameObjects.Container {
}
textObject.text += this.formatText(fieldEffectInfo.name);
- if (fieldEffectInfo.type === ArenaEffectType.TERRAIN) {
+ if (fieldEffectInfo.effecType === ArenaEffectType.TERRAIN) {
textObject.text += " Terrain"; // Adds 'Terrain' since the enum does not contain it
}
@@ -257,19 +259,42 @@ export default class ArenaFlyout extends Phaser.GameObjects.Container {
switch (arenaEffectChangedEvent.constructor) {
case TagAddedEvent:
const tagAddedEvent = arenaEffectChangedEvent as TagAddedEvent;
+ const isArenaTrapTag = this.battleScene.arena.getTag(tagAddedEvent.arenaTagType) instanceof ArenaTrapTag;
+ let arenaEffectType: ArenaEffectType;
+
+ if (tagAddedEvent.arenaTagSide === ArenaTagSide.BOTH) {
+ arenaEffectType = ArenaEffectType.FIELD;
+ } else if (tagAddedEvent.arenaTagSide === ArenaTagSide.PLAYER) {
+ arenaEffectType = ArenaEffectType.PLAYER;
+ } else {
+ arenaEffectType = ArenaEffectType.ENEMY;
+ }
+
+ const existingTrapTagIndex = isArenaTrapTag ? this.fieldEffectInfo.findIndex(e => tagAddedEvent.arenaTagType === e.tagType && arenaEffectType === e.effecType) : -1;
+ let name: string = ArenaTagType[tagAddedEvent.arenaTagType];
+
+ if (isArenaTrapTag && tagAddedEvent.arenaTagMaxLayers > 1) {
+ if (existingTrapTagIndex !== -1) {
+ this.fieldEffectInfo[existingTrapTagIndex].name = `${name} (${tagAddedEvent.arenaTagLayers})`;
+ break;
+ } else {
+ name = `${name} (${tagAddedEvent.arenaTagLayers})`;
+ }
+ }
+
+
this.fieldEffectInfo.push({
- name: ArenaTagType[tagAddedEvent.arenaTagType],
- type: tagAddedEvent.arenaTagSide === ArenaTagSide.BOTH
- ? ArenaEffectType.FIELD
- : tagAddedEvent.arenaTagSide === ArenaTagSide.PLAYER
- ? ArenaEffectType.PLAYER
- : ArenaEffectType.ENEMY,
+ name,
+ effecType: arenaEffectType,
maxDuration: tagAddedEvent.duration,
- duration: tagAddedEvent.duration});
+ duration: tagAddedEvent.duration,
+ tagType: tagAddedEvent.arenaTagType
+ });
break;
case TagRemovedEvent:
const tagRemovedEvent = arenaEffectChangedEvent as TagRemovedEvent;
- foundIndex = this.fieldEffectInfo.findIndex(info => info.name === ArenaTagType[tagRemovedEvent.arenaTagType]);
+ foundIndex = this.fieldEffectInfo.findIndex(info => info.tagType === tagRemovedEvent.arenaTagType);
+
if (foundIndex !== -1) { // If the tag was being tracked, remove it
this.fieldEffectInfo.splice(foundIndex, 1);
}
@@ -290,7 +315,7 @@ export default class ArenaFlyout extends Phaser.GameObjects.Container {
fieldEffectChangedEvent instanceof WeatherChangedEvent
? WeatherType[fieldEffectChangedEvent.newWeatherType]
: TerrainType[fieldEffectChangedEvent.newTerrainType],
- type: fieldEffectChangedEvent instanceof WeatherChangedEvent
+ effecType: fieldEffectChangedEvent instanceof WeatherChangedEvent
? ArenaEffectType.WEATHER
: ArenaEffectType.TERRAIN,
maxDuration: fieldEffectChangedEvent.duration,
diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts
index 1104b048f93..67703b63aee 100644
--- a/src/ui/challenges-select-ui-handler.ts
+++ b/src/ui/challenges-select-ui-handler.ts
@@ -6,7 +6,11 @@ import { addWindow } from "./ui-theme";
import {Button} from "#enums/buttons";
import i18next from "i18next";
import { SelectStarterPhase, TitlePhase } from "#app/phases.js";
-import { Challenge } from "#app/data/challenge.js";
+import { Challenge, ChallengeType } from "#app/data/challenge.js";
+import * as Utils from "../utils";
+import { Challenges } from "#app/enums/challenges.js";
+import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
+import { Color, ShadowColor } from "#app/enums/color.js";
/**
* Handles all the UI for choosing optional challenges.
@@ -21,10 +25,9 @@ export default class GameChallengesUiHandler extends UiHandler {
// private difficultyText: Phaser.GameObjects.Text;
- private descriptionText: Phaser.GameObjects.Text;
+ private descriptionText: BBCodeText;
- private challengeLabels: Phaser.GameObjects.Text[];
- private challengeValueLabels: Phaser.GameObjects.Text[];
+ private challengeLabels: Array<{ label: Phaser.GameObjects.Text, value: Phaser.GameObjects.Text | Phaser.GameObjects.Sprite }>;
private cursorObj: Phaser.GameObjects.NineSlice;
@@ -38,14 +41,22 @@ export default class GameChallengesUiHandler extends UiHandler {
const ui = this.getUi();
this.challengesContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
+ this.challengesContainer.setName("container-challenges");
this.challengesContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
+ const bgOverlay = this.scene.add.rectangle(-1, -1, this.scene.scaledCanvas.width, this.scene.scaledCanvas.height, 0x424242, 0.8);
+ bgOverlay.setName("rect-challenge-overlay");
+ bgOverlay.setOrigin(0, 0);
+ this.challengesContainer.add(bgOverlay);
+
// TODO: Change this back to /9 when adding in difficulty
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6), 24);
+ headerBg.setName("window-header-bg");
headerBg.setOrigin(0, 0);
const headerText = addTextObject(this.scene, 0, 0, i18next.t("challenges:title"), TextStyle.SETTINGS_LABEL);
+ headerText.setName("text-header");
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
@@ -62,45 +73,78 @@ export default class GameChallengesUiHandler extends UiHandler {
// difficultyName.setPositionRelative(difficultyBg, difficultyBg.width - difficultyName.displayWidth - 8, 4);
this.optionsBg = addWindow(this.scene, 0, headerBg.height, (this.scene.game.canvas.width / 9), (this.scene.game.canvas.height / 6) - headerBg.height - 2);
+ this.optionsBg.setName("window-options-bg");
this.optionsBg.setOrigin(0, 0);
const descriptionBg = addWindow(this.scene, 0, headerBg.height, (this.scene.game.canvas.width / 18) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 26);
+ descriptionBg.setName("window-desc-bg");
descriptionBg.setOrigin(0, 0);
descriptionBg.setPositionRelative(this.optionsBg, this.optionsBg.width, 0);
- this.descriptionText = addTextObject(this.scene, 0, 0, "", TextStyle.SETTINGS_LABEL);
+ this.descriptionText = new BBCodeText(this.scene, descriptionBg.x + 6, descriptionBg.y + 4, "", {
+ fontFamily: "emerald, unifont",
+ fontSize: 96,
+ color: Color.ORANGE,
+ padding: {
+ bottom: 6
+ },
+ wrap: {
+ mode: "word",
+ width: (descriptionBg.width - 12) * 6,
+ }
+ });
+ this.descriptionText.setName("text-desc");
+ this.scene.add.existing(this.descriptionText);
+ this.descriptionText.setScale(1/6);
+ this.descriptionText.setShadow(4, 5, ShadowColor.ORANGE);
this.descriptionText.setOrigin(0, 0);
- this.descriptionText.setWordWrapWidth(500, true);
- this.descriptionText.setPositionRelative(descriptionBg, 6, 4);
const startBg = addWindow(this.scene, 0, 0, descriptionBg.width, 24);
+ startBg.setName("window-start-bg");
startBg.setOrigin(0, 0);
startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height);
- const startText = addTextObject(this.scene, 0, 0, i18next.t("challenges:start"), TextStyle.SETTINGS_LABEL);
+ const startText = addTextObject(this.scene, 0, 0, i18next.t("common:start"), TextStyle.SETTINGS_LABEL);
+ startText.setName("text-start");
startText.setOrigin(0, 0);
startText.setPositionRelative(startBg, 8, 4);
this.startCursor = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 18) - 10, 16, 1, 1, 1, 1);
+ this.startCursor.setName("9s-start-cursor");
this.startCursor.setOrigin(0, 0);
this.startCursor.setPositionRelative(startBg, 4, 4);
this.startCursor.setVisible(false);
this.valuesContainer = this.scene.add.container(0, 0);
+ this.valuesContainer.setName("container-values");
this.challengeLabels = [];
- this.challengeValueLabels = [];
- for (let i = 0; i < 9; i++) {
- this.challengeLabels[i] = addTextObject(this.scene, 8, 28 + i * 16, "", TextStyle.SETTINGS_LABEL);
- this.challengeLabels[i].setOrigin(0, 0);
+ for (let i = 0; i < Object.keys(ChallengeType).length; i++) {
+ const label = addTextObject(this.scene, 8, 28 + i * 16, "", TextStyle.SETTINGS_LABEL);
+ label.setName(`text-challenge-label-${i}`);
+ label.setOrigin(0, 0);
- this.valuesContainer.add(this.challengeLabels[i]);
+ this.valuesContainer.add(label);
- this.challengeValueLabels[i] = addTextObject(this.scene, 0, 28 + i * 16, "", TextStyle.SETTINGS_LABEL);
- this.challengeValueLabels[i].setPositionRelative(this.challengeLabels[i], 100, 0);
+ let value;
+ if (i === Challenges.SINGLE_TYPE) {
+ const type = `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`;
+ value = this.scene.add.sprite(8, 98, type);
+ value.setName("sprite-single-type");
+ value.setScale(0.86);
+ value.setPositionRelative(label, 113, 8);
+ } else {
+ value = addTextObject(this.scene, 0, 28 + i * 16, "", TextStyle.SETTINGS_LABEL);
+ value.setName(`text-challenge-value-label-${i}`);
+ value.setPositionRelative(label, 100, 0);
+ }
- this.valuesContainer.add(this.challengeValueLabels[i]);
+ this.valuesContainer.add(value);
+ this.challengeLabels[i] = {
+ label: label,
+ value: value
+ };
}
this.challengesContainer.add(headerBg);
@@ -124,31 +168,49 @@ export default class GameChallengesUiHandler extends UiHandler {
this.challengesContainer.setVisible(false);
}
+ /**
+ * Adds the default text color to the description text
+ * @param text text to set to the BBCode description
+ */
+ setDescription(text: string): void {
+ this.descriptionText.setText(`[color=${Color.ORANGE}][shadow=${ShadowColor.ORANGE}]${text}`);
+ }
+ /**
+ * initLabels
+ * init all challenge labels
+ */
+ initLabels(): void {
+ this.setDescription(this.scene.gameMode.challenges[this.cursor].getDescription());
+ this.scene.gameMode.challenges.forEach((challenge, i) => {
+ this.challengeLabels[i].label.setVisible(true);
+ this.challengeLabels[i].value.setVisible(true);
+ this.challengeLabels[i].label.setText(challenge.getName());
+ if (this.challengeLabels[i].value.type.toLowerCase() === "sprite") {
+ (this.challengeLabels[i].value as Phaser.GameObjects.Sprite).setFrame(challenge.getValue());
+ } else {
+ (this.challengeLabels[i].value as Phaser.GameObjects.Text).setText(challenge.getValue());
+ }
+ });
+ }
+
+ /**
+ * update the text the cursor is on
+ */
updateText(): void {
- if (this.scene.gameMode.challenges.length > 0) {
- this.descriptionText.text = this.getActiveChallenge().getDescription();
- this.descriptionText.updateText();
- }
+ const challenge = this.getActiveChallenge();
+ const { id } = challenge;
+ this.setDescription(this.getActiveChallenge().getDescription());
+ if (this.challengeLabels[id].value.type.toLowerCase() === "sprite") {
+ (this.challengeLabels[id].value as Phaser.GameObjects.Sprite).setFrame(challenge.getValue());
+ } else {
+ (this.challengeLabels[id].value as Phaser.GameObjects.Text).setText(challenge.getValue());
+ }
// const totalDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getDifficulty(), 0);
// const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0);
// this.difficultyText.text = `${totalDifficulty}` + (totalMinDifficulty ? `/${totalMinDifficulty}` : "");
// this.difficultyText.updateText();
-
- for (let i = 0; i < this.challengeLabels.length; i++) {
- if (i + this.scrollCursor < this.scene.gameMode.challenges.length) {
- this.challengeLabels[i].setVisible(true);
- this.challengeValueLabels[i].setVisible(true);
- this.challengeLabels[i].text = this.scene.gameMode.challenges[i + this.scrollCursor].getName();
- this.challengeValueLabels[i].text = this.scene.gameMode.challenges[i + this.scrollCursor].getValue();
- this.challengeLabels[i].updateText();
- this.challengeValueLabels[i].updateText();
- } else {
- this.challengeLabels[i].setVisible(false);
- this.challengeValueLabels[i].setVisible(false);
- }
- }
}
show(args: any[]): boolean {
@@ -158,7 +220,7 @@ export default class GameChallengesUiHandler extends UiHandler {
this.challengesContainer.setVisible(true);
this.setCursor(0);
- this.updateText();
+ this.initLabels();
this.getUi().moveTo(this.challengesContainer, this.getUi().length - 1);
diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts
index 5b1b2caf917..c7c06227d48 100644
--- a/src/ui/menu-ui-handler.ts
+++ b/src/ui/menu-ui-handler.ts
@@ -24,7 +24,7 @@ export enum MenuOptions {
LOG_OUT
}
-const wikiUrl = "https://wiki.pokerogue.net/start";
+let wikiUrl = "https://wiki.pokerogue.net/start";
const discordUrl = "https://discord.gg/uWpTfdKG49";
const githubUrl = "https://github.com/pagefaultgames/pokerogue";
const redditUrl = "https://www.reddit.com/r/pokerogue";
@@ -55,6 +55,11 @@ export default class MenuUiHandler extends MessageUiHandler {
setup() {
const ui = this.getUi();
+ // wiki url directs based on languges available on wiki
+ const lang = i18next.resolvedLanguage.substring(0,2);
+ if (["de", "fr", "ko", "zh"].includes(lang)) {
+ wikiUrl = `https://wiki.pokerogue.net/${lang}:start`;
+ }
this.menuContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts
index 2dd77b53ae0..34ee83b0f50 100644
--- a/src/ui/starter-select-ui-handler.ts
+++ b/src/ui/starter-select-ui-handler.ts
@@ -432,7 +432,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.valueLimitLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(this.valueLimitLabel);
- const startLabel = addTextObject(this.scene, 124, 162, i18next.t("starterSelectUiHandler:start"), TextStyle.TOOLTIP_CONTENT);
+ const startLabel = addTextObject(this.scene, 124, 162, i18next.t("common:start"), TextStyle.TOOLTIP_CONTENT);
startLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(startLabel);
@@ -547,11 +547,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
this.starterSelectContainer.add(this.pokemonSprite);
- this.type1Icon = this.scene.add.sprite(8, 98, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`); this.type1Icon.setScale(0.5);
+ this.type1Icon = this.scene.add.sprite(8, 98, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`);
+ this.type1Icon.setScale(0.5);
this.type1Icon.setOrigin(0, 0);
this.starterSelectContainer.add(this.type1Icon);
- this.type2Icon = this.scene.add.sprite(26, 98, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`); this.type2Icon.setScale(0.5);
+ this.type2Icon = this.scene.add.sprite(26, 98, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`);
+ this.type2Icon.setScale(0.5);
this.type2Icon.setOrigin(0, 0);
this.starterSelectContainer.add(this.type2Icon);
diff --git a/src/ui/text.ts b/src/ui/text.ts
index b74742fef74..046abce2d87 100644
--- a/src/ui/text.ts
+++ b/src/ui/text.ts
@@ -89,7 +89,7 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
const defaultFontSize = 96;
let styleOptions: Phaser.Types.GameObjects.Text.TextStyle = {
- fontFamily: "emerald, unifont",
+ fontFamily: "emerald",
fontSize: 96,
color: getTextColor(style, false, uiTheme),
padding: {
diff --git a/src/ui/ui.ts b/src/ui/ui.ts
index 55982d049cf..75ccfc40f59 100644
--- a/src/ui/ui.ts
+++ b/src/ui/ui.ts
@@ -182,7 +182,7 @@ export default class UI extends Phaser.GameObjects.Container {
}
setup(): void {
- this.setName("container-ui");
+ this.setName(`container-ui-${Mode[this.mode]}`);
for (const handler of this.handlers) {
handler.setup();
}
diff --git a/src/utils.ts b/src/utils.ts
index 7c1a24a6d5e..9fe9cc9096f 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -361,6 +361,9 @@ export function apiPost(path: string, data?: any, contentType: string = "applica
}) : new Promise(() => {});
}
+/** Alias for the constructor of a class */
+export type Constructor = new(...args: unknown[]) => T;
+
export class BooleanHolder {
public value: boolean;
@@ -447,9 +450,9 @@ export function verifyLang(lang?: string): boolean {
case "fr":
case "de":
case "it":
- case "zh_CN":
- case "zh_TW":
- case "pt_BR":
+ case "zh-CN":
+ case "zh-TW":
+ case "pt-BR":
case "ko":
return true;
default: