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: