diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000000..c1c32a95cd6 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,31 @@ +name: Tests + +on: + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + branches: + - main # Trigger on push events to the main branch + pull_request: + branches: + - main # Trigger on pull request events targeting the main branch + +jobs: + run-tests: # Define a job named "run-tests" + name: Run tests # Human-readable name for the job + runs-on: ubuntu-latest # Specify the latest Ubuntu runner for the job + + steps: + - name: Check out Git repository # Step to check out the repository + uses: actions/checkout@v4 # Use the checkout action version 4 + + - name: Set up Node.js # Step to set up Node.js environment + uses: actions/setup-node@v4 # Use the setup-node action version 4 + with: + node-version: 20 # Specify Node.js version 20 + + - name: Install Node.js dependencies # Step to install Node.js dependencies + run: npm ci # Use 'npm ci' to install dependencies + + - name: tests # Step to run tests + run: npm run test:silent \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1b1bc0743c3..669f8df003f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ src/data/battle-anim-data.ts src/overrides.ts coverage +/.vs # Local Documentation /typedoc diff --git a/README.md b/README.md index 9e88163f2d7..839bfa3ae45 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,14 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to - Keisuke Ito - Arata Iiyoshi - Atsuhiro Ishizuna + - Pokémon HeartGold/SoulSilver - Pokémon Black/White 2 + - Pokémon X/Y + - Pokémon Omega Ruby/Alpha Sapphire + - Pokémon Sun/Moon + - Pokémon Ultra Sun/Ultra Moon + - Pokémon Sword/Shield + - Pokémon Scarlet/Violet - Firel (Custom Metropolis and Laboratory biome music) - Lmz (Custom Jungle biome music) diff --git a/index.html b/index.html index b2e8bf3ec0f..0e8afed6b03 100644 --- a/index.html +++ b/index.html @@ -19,6 +19,11 @@ 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.json b/package.json index 2e87525aeaf..f100b3865d2 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test": "vitest run", "test:cov": "vitest run --coverage", "test:watch": "vitest watch --coverage", + "test:silent": "vitest run --silent", "eslint": "eslint --fix .", "eslint-ci": "eslint .", "docs": "typedoc" diff --git a/public/audio/bgm/battle_alola_champion.mp3 b/public/audio/bgm/battle_alola_champion.mp3 new file mode 100644 index 00000000000..94173ca69fd Binary files /dev/null and b/public/audio/bgm/battle_alola_champion.mp3 differ diff --git a/public/audio/bgm/battle_alola_elite.mp3 b/public/audio/bgm/battle_alola_elite.mp3 new file mode 100644 index 00000000000..d87a4a89968 Binary files /dev/null and b/public/audio/bgm/battle_alola_elite.mp3 differ diff --git a/public/audio/bgm/battle_bb_elite.mp3 b/public/audio/bgm/battle_bb_elite.mp3 new file mode 100644 index 00000000000..e0ec0dbd518 Binary files /dev/null and b/public/audio/bgm/battle_bb_elite.mp3 differ diff --git a/public/audio/bgm/battle_champion_geeta.mp3 b/public/audio/bgm/battle_champion_geeta.mp3 new file mode 100644 index 00000000000..1b654e33ee2 Binary files /dev/null and b/public/audio/bgm/battle_champion_geeta.mp3 differ diff --git a/public/audio/bgm/battle_champion_kieran.mp3 b/public/audio/bgm/battle_champion_kieran.mp3 new file mode 100644 index 00000000000..e43a1c904cd Binary files /dev/null and b/public/audio/bgm/battle_champion_kieran.mp3 differ diff --git a/public/audio/bgm/battle_champion_nemona.mp3 b/public/audio/bgm/battle_champion_nemona.mp3 new file mode 100644 index 00000000000..9d835030e49 Binary files /dev/null and b/public/audio/bgm/battle_champion_nemona.mp3 differ diff --git a/public/audio/bgm/battle_galar_champion.mp3 b/public/audio/bgm/battle_galar_champion.mp3 new file mode 100644 index 00000000000..9dd43f9bbc8 Binary files /dev/null and b/public/audio/bgm/battle_galar_champion.mp3 differ diff --git a/public/audio/bgm/battle_galar_elite.mp3 b/public/audio/bgm/battle_galar_elite.mp3 new file mode 100644 index 00000000000..34587edcbd1 Binary files /dev/null and b/public/audio/bgm/battle_galar_elite.mp3 differ diff --git a/public/audio/bgm/battle_galar_gym.mp3 b/public/audio/bgm/battle_galar_gym.mp3 new file mode 100644 index 00000000000..a10b284cf4b Binary files /dev/null and b/public/audio/bgm/battle_galar_gym.mp3 differ diff --git a/public/audio/bgm/battle_hoenn_elite.mp3 b/public/audio/bgm/battle_hoenn_elite.mp3 new file mode 100644 index 00000000000..7d352d4332a Binary files /dev/null and b/public/audio/bgm/battle_hoenn_elite.mp3 differ diff --git a/public/audio/bgm/battle_kalos_champion.mp3 b/public/audio/bgm/battle_kalos_champion.mp3 new file mode 100644 index 00000000000..c9dd6b80133 Binary files /dev/null and b/public/audio/bgm/battle_kalos_champion.mp3 differ diff --git a/public/audio/bgm/battle_kalos_elite.mp3 b/public/audio/bgm/battle_kalos_elite.mp3 new file mode 100644 index 00000000000..f4a0181544d Binary files /dev/null and b/public/audio/bgm/battle_kalos_elite.mp3 differ diff --git a/public/audio/bgm/battle_kalos_gym.mp3 b/public/audio/bgm/battle_kalos_gym.mp3 new file mode 100644 index 00000000000..9031274519f Binary files /dev/null and b/public/audio/bgm/battle_kalos_gym.mp3 differ diff --git a/public/audio/bgm/battle_legendary_arceus.mp3 b/public/audio/bgm/battle_legendary_arceus.mp3 new file mode 100644 index 00000000000..03dab3878f2 Binary files /dev/null and b/public/audio/bgm/battle_legendary_arceus.mp3 differ diff --git a/public/audio/bgm/battle_legendary_birds_galar.mp3 b/public/audio/bgm/battle_legendary_birds_galar.mp3 new file mode 100644 index 00000000000..79bedb5c500 Binary files /dev/null and b/public/audio/bgm/battle_legendary_birds_galar.mp3 differ diff --git a/public/audio/bgm/battle_legendary_calyrex.mp3 b/public/audio/bgm/battle_legendary_calyrex.mp3 new file mode 100644 index 00000000000..8d22a5df963 Binary files /dev/null and b/public/audio/bgm/battle_legendary_calyrex.mp3 differ diff --git a/public/audio/bgm/battle_legendary_deoxys.mp3 b/public/audio/bgm/battle_legendary_deoxys.mp3 new file mode 100644 index 00000000000..da91a5f76bc Binary files /dev/null and b/public/audio/bgm/battle_legendary_deoxys.mp3 differ diff --git a/public/audio/bgm/battle_legendary_dia_pal.mp3 b/public/audio/bgm/battle_legendary_dia_pal.mp3 new file mode 100644 index 00000000000..07998098afe Binary files /dev/null and b/public/audio/bgm/battle_legendary_dia_pal.mp3 differ diff --git a/public/audio/bgm/battle_legendary_dusk_dawn.mp3 b/public/audio/bgm/battle_legendary_dusk_dawn.mp3 new file mode 100644 index 00000000000..20b883a4ca7 Binary files /dev/null and b/public/audio/bgm/battle_legendary_dusk_dawn.mp3 differ diff --git a/public/audio/bgm/battle_legendary_entei.mp3 b/public/audio/bgm/battle_legendary_entei.mp3 new file mode 100644 index 00000000000..30d1f87748c Binary files /dev/null and b/public/audio/bgm/battle_legendary_entei.mp3 differ diff --git a/public/audio/bgm/battle_legendary_giratina.mp3 b/public/audio/bgm/battle_legendary_giratina.mp3 new file mode 100644 index 00000000000..87674e003ca Binary files /dev/null and b/public/audio/bgm/battle_legendary_giratina.mp3 differ diff --git a/public/audio/bgm/battle_legendary_glas_spec.mp3 b/public/audio/bgm/battle_legendary_glas_spec.mp3 new file mode 100644 index 00000000000..52988510ea6 Binary files /dev/null and b/public/audio/bgm/battle_legendary_glas_spec.mp3 differ diff --git a/public/audio/bgm/battle_legendary_gro_kyo.mp3 b/public/audio/bgm/battle_legendary_gro_kyo.mp3 new file mode 100644 index 00000000000..b3401da3f6e Binary files /dev/null and b/public/audio/bgm/battle_legendary_gro_kyo.mp3 differ diff --git a/public/audio/bgm/battle_legendary_ho_oh.mp3 b/public/audio/bgm/battle_legendary_ho_oh.mp3 new file mode 100644 index 00000000000..46740297f77 Binary files /dev/null and b/public/audio/bgm/battle_legendary_ho_oh.mp3 differ diff --git a/public/audio/bgm/battle_legendary_kanto.mp3 b/public/audio/bgm/battle_legendary_kanto.mp3 new file mode 100644 index 00000000000..0b9946ec9fe Binary files /dev/null and b/public/audio/bgm/battle_legendary_kanto.mp3 differ diff --git a/public/audio/bgm/battle_legendary_lake_trio.mp3 b/public/audio/bgm/battle_legendary_lake_trio.mp3 new file mode 100644 index 00000000000..dc6bb08d13f Binary files /dev/null and b/public/audio/bgm/battle_legendary_lake_trio.mp3 differ diff --git a/public/audio/bgm/battle_legendary_loyal_three.mp3 b/public/audio/bgm/battle_legendary_loyal_three.mp3 new file mode 100644 index 00000000000..d753e58a0a7 Binary files /dev/null and b/public/audio/bgm/battle_legendary_loyal_three.mp3 differ diff --git a/public/audio/bgm/battle_legendary_lugia.mp3 b/public/audio/bgm/battle_legendary_lugia.mp3 new file mode 100644 index 00000000000..37031c8a642 Binary files /dev/null and b/public/audio/bgm/battle_legendary_lugia.mp3 differ diff --git a/public/audio/bgm/battle_legendary_ogerpon.mp3 b/public/audio/bgm/battle_legendary_ogerpon.mp3 new file mode 100644 index 00000000000..2ac0d9756a8 Binary files /dev/null and b/public/audio/bgm/battle_legendary_ogerpon.mp3 differ diff --git a/public/audio/bgm/battle_legendary_pecharunt.mp3 b/public/audio/bgm/battle_legendary_pecharunt.mp3 new file mode 100644 index 00000000000..48f205d97d1 Binary files /dev/null and b/public/audio/bgm/battle_legendary_pecharunt.mp3 differ diff --git a/public/audio/bgm/battle_legendary_raikou.mp3 b/public/audio/bgm/battle_legendary_raikou.mp3 new file mode 100644 index 00000000000..8daa7083faa Binary files /dev/null and b/public/audio/bgm/battle_legendary_raikou.mp3 differ diff --git a/public/audio/bgm/battle_legendary_rayquaza.mp3 b/public/audio/bgm/battle_legendary_rayquaza.mp3 new file mode 100644 index 00000000000..843596779bd Binary files /dev/null and b/public/audio/bgm/battle_legendary_rayquaza.mp3 differ diff --git a/public/audio/bgm/battle_legendary_regis.mp3 b/public/audio/bgm/battle_legendary_regis_g5.mp3 similarity index 100% rename from public/audio/bgm/battle_legendary_regis.mp3 rename to public/audio/bgm/battle_legendary_regis_g5.mp3 diff --git a/public/audio/bgm/battle_legendary_regis_g6.mp3 b/public/audio/bgm/battle_legendary_regis_g6.mp3 new file mode 100644 index 00000000000..ebe1a44d18a Binary files /dev/null and b/public/audio/bgm/battle_legendary_regis_g6.mp3 differ diff --git a/public/audio/bgm/battle_legendary_ruinous.mp3 b/public/audio/bgm/battle_legendary_ruinous.mp3 new file mode 100644 index 00000000000..dc1aeeaee26 Binary files /dev/null and b/public/audio/bgm/battle_legendary_ruinous.mp3 differ diff --git a/public/audio/bgm/battle_legendary_sinnoh.mp3 b/public/audio/bgm/battle_legendary_sinnoh.mp3 new file mode 100644 index 00000000000..6332a3e1cc2 Binary files /dev/null and b/public/audio/bgm/battle_legendary_sinnoh.mp3 differ diff --git a/public/audio/bgm/battle_legendary_sol_lun.mp3 b/public/audio/bgm/battle_legendary_sol_lun.mp3 new file mode 100644 index 00000000000..4aa9d5111b8 Binary files /dev/null and b/public/audio/bgm/battle_legendary_sol_lun.mp3 differ diff --git a/public/audio/bgm/battle_legendary_suicune.mp3 b/public/audio/bgm/battle_legendary_suicune.mp3 new file mode 100644 index 00000000000..7e7e4901386 Binary files /dev/null and b/public/audio/bgm/battle_legendary_suicune.mp3 differ diff --git a/public/audio/bgm/battle_legendary_tapu.mp3 b/public/audio/bgm/battle_legendary_tapu.mp3 new file mode 100644 index 00000000000..7f251a387a2 Binary files /dev/null and b/public/audio/bgm/battle_legendary_tapu.mp3 differ diff --git a/public/audio/bgm/battle_legendary_terapagos.mp3 b/public/audio/bgm/battle_legendary_terapagos.mp3 new file mode 100644 index 00000000000..b820d7dba6a Binary files /dev/null and b/public/audio/bgm/battle_legendary_terapagos.mp3 differ diff --git a/public/audio/bgm/battle_legendary_ub.mp3 b/public/audio/bgm/battle_legendary_ub.mp3 new file mode 100644 index 00000000000..7a6bdb3a678 Binary files /dev/null and b/public/audio/bgm/battle_legendary_ub.mp3 differ diff --git a/public/audio/bgm/battle_legendary_ultra_nec.mp3 b/public/audio/bgm/battle_legendary_ultra_nec.mp3 new file mode 100644 index 00000000000..63d8b0fa505 Binary files /dev/null and b/public/audio/bgm/battle_legendary_ultra_nec.mp3 differ diff --git a/public/audio/bgm/battle_legendary_xern_yvel.mp3 b/public/audio/bgm/battle_legendary_xern_yvel.mp3 new file mode 100644 index 00000000000..856bebb0f61 Binary files /dev/null and b/public/audio/bgm/battle_legendary_xern_yvel.mp3 differ diff --git a/public/audio/bgm/battle_legendary_zac_zam.mp3 b/public/audio/bgm/battle_legendary_zac_zam.mp3 new file mode 100644 index 00000000000..6725625bedf Binary files /dev/null and b/public/audio/bgm/battle_legendary_zac_zam.mp3 differ diff --git a/public/audio/bgm/battle_paldea_elite.mp3 b/public/audio/bgm/battle_paldea_elite.mp3 new file mode 100644 index 00000000000..9a598dfaf64 Binary files /dev/null and b/public/audio/bgm/battle_paldea_elite.mp3 differ diff --git a/public/audio/bgm/battle_paldea_gym.mp3 b/public/audio/bgm/battle_paldea_gym.mp3 new file mode 100644 index 00000000000..eb9a19bacfe Binary files /dev/null and b/public/audio/bgm/battle_paldea_gym.mp3 differ diff --git a/public/audio/bgm/battle_plasma_grunt.mp3 b/public/audio/bgm/battle_plasma_grunt.mp3 new file mode 100644 index 00000000000..fe371f21f9f Binary files /dev/null and b/public/audio/bgm/battle_plasma_grunt.mp3 differ diff --git a/public/audio/bgm/battle_elite.mp3 b/public/audio/bgm/battle_unova_elite.mp3 similarity index 100% rename from public/audio/bgm/battle_elite.mp3 rename to public/audio/bgm/battle_unova_elite.mp3 diff --git a/public/audio/bgm/encounter_plasma_grunt.mp3 b/public/audio/bgm/encounter_plasma_grunt.mp3 new file mode 100644 index 00000000000..478d3f8edc5 Binary files /dev/null and b/public/audio/bgm/encounter_plasma_grunt.mp3 differ diff --git a/public/fonts/unifont-15.1.05.otf b/public/fonts/unifont-15.1.05.otf new file mode 100644 index 00000000000..3d0dcd3c1a0 Binary files /dev/null and b/public/fonts/unifont-15.1.05.otf differ diff --git a/public/images/items.json b/public/images/items.json index dc05a39354d..6af2029efd9 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -4,13 +4,13 @@ "image": "items.png", "format": "RGBA8888", "size": { - "w": 399, - "h": 399 + "w": 414, + "h": 414 }, "scale": 1, "frames": [ { - "filename": "galarica_cuff", + "filename": "relic_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -18,1507 +18,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 29, - "h": 30 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 30 - } - }, - { - "filename": "galarica_wreath", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 32, - "h": 27 - }, - "frame": { - "x": 29, - "y": 0, - "w": 32, - "h": 27 - } - }, - { - "filename": "max_mushrooms", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 29, - "h": 28 - }, - "frame": { - "x": 0, - "y": 30, - "w": 29, - "h": 28 - } - }, - { - "filename": "bronze_ribbon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 31 - }, - "frame": { - "x": 29, - "y": 27, - "w": 22, - "h": 31 - } - }, - { - "filename": "great_ribbon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 31 - }, - "frame": { - "x": 0, - "y": 58, - "w": 22, - "h": 31 - } - }, - { - "filename": "linking_cord", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 27, - "h": 26 - }, - "frame": { - "x": 61, - "y": 0, - "w": 27, - "h": 26 - } - }, - { - "filename": "master_ribbon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 31 - }, - "frame": { - "x": 0, - "y": 89, - "w": 22, - "h": 31 - } - }, - { - "filename": "rogue_ribbon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 31 - }, - "frame": { - "x": 22, - "y": 58, - "w": 22, - "h": 31 - } - }, - { - "filename": "ultra_ribbon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 31 - }, - "frame": { - "x": 0, - "y": 120, - "w": 22, - "h": 31 - } - }, - { - "filename": "cornerstone_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 3, - "w": 24, - "h": 26 - }, - "frame": { - "x": 88, - "y": 0, - "w": 24, - "h": 26 - } - }, - { - "filename": "ability_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 23, - "h": 26 - }, - "frame": { - "x": 112, - "y": 0, - "w": 23, - "h": 26 - } - }, - { - "filename": "map", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 5, - "w": 27, - "h": 22 - }, - "frame": { - "x": 135, - "y": 0, - "w": 27, - "h": 22 - } - }, - { - "filename": "mint_atk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 162, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_def", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 190, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_neutral", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 218, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spatk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 246, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spd", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 274, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spdef", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 302, - "y": 0, - "w": 28, - "h": 21 - } - }, - { - "filename": "exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 22, - "y": 89, - "w": 17, - "h": 31 - } - }, - { - "filename": "golden_exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 0, - "y": 151, - "w": 17, - "h": 31 - } - }, - { - "filename": "super_exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 22, - "y": 120, - "w": 17, - "h": 31 - } - }, - { - "filename": "black_augurite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 3, - "w": 22, - "h": 25 - }, - "frame": { - "x": 17, - "y": 151, - "w": 22, - "h": 25 - } - }, - { - "filename": "prison_bottle", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 30 - }, - "frame": { - "x": 0, - "y": 182, - "w": 17, - "h": 30 - } - }, - { - "filename": "big_root", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 17, - "y": 176, - "w": 23, - "h": 24 - } - }, - { - "filename": "chipped_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 6, - "w": 26, - "h": 20 - }, - "frame": { - "x": 330, - "y": 0, - "w": 26, - "h": 20 - } - }, - { - "filename": "cracked_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 6, - "w": 26, - "h": 20 - }, - "frame": { - "x": 356, - "y": 0, - "w": 26, - "h": 20 - } - }, - { - "filename": "lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 382, - "y": 0, - "w": 17, - "h": 24 - } - }, - { - "filename": "catching_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 0, - "y": 212, - "w": 21, - "h": 24 - } - }, - { - "filename": "choice_scarf", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 236, - "w": 24, - "h": 24 - } - }, - { - "filename": "focus_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 260, - "w": 24, - "h": 24 - } - }, - { - "filename": "golden_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 284, - "w": 24, - "h": 24 - } - }, - { - "filename": "gracidea", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 308, - "w": 24, - "h": 24 - } - }, - { - "filename": "grip_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 332, - "w": 24, - "h": 24 - } - }, - { - "filename": "lucky_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 0, - "y": 356, - "w": 24, - "h": 24 - } - }, - { - "filename": "coupon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 0, - "y": 380, - "w": 23, - "h": 19 - } - }, - { - "filename": "golden_mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 23, - "y": 380, - "w": 23, - "h": 19 - } - }, - { - "filename": "calcium", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 51, - "y": 27, - "w": 16, - "h": 24 - } - }, - { - "filename": "lucky_punch_great", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 67, - "y": 26, - "w": 24, - "h": 24 - } - }, - { - "filename": "lucky_punch_master", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 91, - "y": 26, - "w": 24, - "h": 24 - } - }, - { - "filename": "kings_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 115, - "y": 26, - "w": 23, - "h": 24 - } - }, - { - "filename": "lucky_punch_ultra", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 138, - "y": 22, - "w": 24, - "h": 24 - } - }, - { - "filename": "lustrous_globe", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 162, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "muscle_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 186, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "salac_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 210, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "scanner", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 234, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "silk_scarf", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 258, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "sun_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 282, - "y": 21, - "w": 24, - "h": 24 - } - }, - { - "filename": "clefairy_doll", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 306, - "y": 21, - "w": 24, - "h": 23 - } - }, - { - "filename": "coin_case", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 330, - "y": 20, - "w": 24, - "h": 23 - } - }, - { - "filename": "expert_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 23 - }, - "frame": { - "x": 354, - "y": 20, - "w": 24, - "h": 23 - } - }, - { - "filename": "oval_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 378, - "y": 24, - "w": 21, - "h": 24 - } - }, - { - "filename": "carbos", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 44, - "y": 58, - "w": 16, - "h": 24 - } - }, - { - "filename": "max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 24 - }, - "frame": { - "x": 21, - "y": 200, - "w": 22, - "h": 24 - } - }, - { - "filename": "red_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 20, - "h": 24 - }, - "frame": { - "x": 24, - "y": 224, - "w": 20, - "h": 24 - } - }, - { - "filename": "reveal_glass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 24, - "y": 248, - "w": 23, - "h": 24 - } - }, - { - "filename": "berry_pouch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 24, - "y": 272, - "w": 23, - "h": 23 - } - }, - { - "filename": "dynamax_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 23 - }, - "frame": { - "x": 24, - "y": 295, - "w": 23, - "h": 23 - } - }, - { - "filename": "griseous_core", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 24, - "y": 318, - "w": 23, - "h": 23 - } - }, - { - "filename": "hearthflame_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 23 - }, - "frame": { - "x": 24, - "y": 341, - "w": 24, - "h": 23 - } - }, - { - "filename": "mega_bracelet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 16 - }, - "frame": { - "x": 24, - "y": 364, - "w": 20, - "h": 16 - } - }, - { - "filename": "elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 39, - "y": 89, - "w": 18, - "h": 24 - } - }, - { - "filename": "ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 39, - "y": 113, - "w": 18, - "h": 24 - } - }, - { - "filename": "full_restore", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 39, - "y": 137, - "w": 18, - "h": 24 - } - }, - { - "filename": "silver_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, + "x": 9, "y": 11, - "w": 24, - "h": 15 + "w": 15, + "h": 11 }, "frame": { - "x": 39, - "y": 161, - "w": 24, - "h": 15 - } - }, - { - "filename": "shiny_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 40, - "y": 176, - "w": 21, - "h": 24 - } - }, - { - "filename": "max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 43, - "y": 200, - "w": 18, - "h": 24 - } - }, - { - "filename": "max_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 44, - "y": 224, - "w": 18, - "h": 24 - } - }, - { - "filename": "hp_up", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 47, - "y": 248, - "w": 16, - "h": 24 - } - }, - { - "filename": "iron", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 47, - "y": 272, - "w": 16, - "h": 24 - } - }, - { - "filename": "max_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 47, - "y": 296, - "w": 17, - "h": 24 - } - }, - { - "filename": "adamant_crystal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 47, - "y": 320, - "w": 23, - "h": 21 - } - }, - { - "filename": "black_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 48, - "y": 341, - "w": 22, - "h": 23 + "x": 0, + "y": 0, + "w": 15, + "h": 11 } }, { @@ -1536,957 +45,12 @@ "h": 14 }, "frame": { - "x": 44, - "y": 364, + "x": 15, + "y": 0, "w": 24, "h": 14 } }, - { - "filename": "amulet_coin", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 46, - "y": 378, - "w": 23, - "h": 21 - } - }, - { - "filename": "choice_specs", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 138, - "y": 46, - "w": 24, - "h": 18 - } - }, - { - "filename": "exp_balance", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 162, - "y": 45, - "w": 24, - "h": 22 - } - }, - { - "filename": "exp_share", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 186, - "y": 45, - "w": 24, - "h": 22 - } - }, - { - "filename": "leppa_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 210, - "y": 45, - "w": 24, - "h": 23 - } - }, - { - "filename": "scope_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 234, - "y": 45, - "w": 24, - "h": 23 - } - }, - { - "filename": "twisted_spoon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 258, - "y": 45, - "w": 24, - "h": 23 - } - }, - { - "filename": "peat_block", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 282, - "y": 45, - "w": 24, - "h": 22 - } - }, - { - "filename": "rare_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 306, - "y": 44, - "w": 23, - "h": 23 - } - }, - { - "filename": "max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 61, - "y": 176, - "w": 18, - "h": 24 - } - }, - { - "filename": "super_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 61, - "y": 200, - "w": 17, - "h": 24 - } - }, - { - "filename": "max_repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 62, - "y": 224, - "w": 16, - "h": 24 - } - }, - { - "filename": "pp_max", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 63, - "y": 248, - "w": 16, - "h": 24 - } - }, - { - "filename": "pp_up", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 63, - "y": 272, - "w": 16, - "h": 24 - } - }, - { - "filename": "protein", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 64, - "y": 296, - "w": 16, - "h": 24 - } - }, - { - "filename": "repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 70, - "y": 320, - "w": 16, - "h": 24 - } - }, - { - "filename": "apicot_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 70, - "y": 344, - "w": 19, - "h": 20 - } - }, - { - "filename": "bug_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 69, - "y": 364, - "w": 22, - "h": 23 - } - }, - { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 69, - "y": 387, - "w": 15, - "h": 11 - } - }, - { - "filename": "dragon_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 330, - "y": 43, - "w": 24, - "h": 18 - } - }, - { - "filename": "icy_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 354, - "y": 43, - "w": 24, - "h": 20 - } - }, - { - "filename": "dragon_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 378, - "y": 48, - "w": 21, - "h": 23 - } - }, - { - "filename": "rusted_shield", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 329, - "y": 61, - "w": 24, - "h": 20 - } - }, - { - "filename": "sacred_ash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 353, - "y": 63, - "w": 24, - "h": 20 - } - }, - { - "filename": "dark_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 377, - "y": 71, - "w": 22, - "h": 23 - } - }, - { - "filename": "shadow_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 67, - "y": 50, - "w": 24, - "h": 20 - } - }, - { - "filename": "soft_sand", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 91, - "y": 50, - "w": 24, - "h": 20 - } - }, - { - "filename": "auspicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 115, - "y": 50, - "w": 23, - "h": 21 - } - }, - { - "filename": "binding_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 23, - "h": 20 - }, - "frame": { - "x": 138, - "y": 64, - "w": 23, - "h": 20 - } - }, - { - "filename": "black_glasses", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 161, - "y": 67, - "w": 23, - "h": 17 - } - }, - { - "filename": "burn_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 184, - "y": 67, - "w": 23, - "h": 17 - } - }, - { - "filename": "chill_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 207, - "y": 68, - "w": 23, - "h": 17 - } - }, - { - "filename": "douse_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 230, - "y": 68, - "w": 23, - "h": 17 - } - }, - { - "filename": "healing_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 253, - "y": 68, - "w": 23, - "h": 22 - } - }, - { - "filename": "berry_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 18, - "h": 22 - }, - "frame": { - "x": 276, - "y": 68, - "w": 18, - "h": 22 - } - }, - { - "filename": "rarer_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 294, - "y": 67, - "w": 23, - "h": 23 - } - }, - { - "filename": "revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 10, - "y": 8, - "w": 12, - "h": 17 - }, - "frame": { - "x": 317, - "y": 67, - "w": 12, - "h": 17 - } - }, - { - "filename": "moon_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 60, - "y": 70, - "w": 23, - "h": 21 - } - }, - { - "filename": "n_lunarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 83, - "y": 70, - "w": 23, - "h": 21 - } - }, - { - "filename": "stick", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 57, - "y": 91, - "w": 23, - "h": 23 - } - }, - { - "filename": "dragon_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 80, - "y": 91, - "w": 22, - "h": 23 - } - }, - { - "filename": "electric_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 57, - "y": 114, - "w": 22, - "h": 23 - } - }, - { - "filename": "super_repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 57, - "y": 137, - "w": 16, - "h": 24 - } - }, - { - "filename": "fairy_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 79, - "y": 114, - "w": 22, - "h": 23 - } - }, - { - "filename": "fighting_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 73, - "y": 137, - "w": 22, - "h": 23 - } - }, { "filename": "candy_overlay", "rotated": false, @@ -2502,516 +66,12 @@ "h": 15 }, "frame": { - "x": 63, - "y": 161, + "x": 39, + "y": 0, "w": 16, "h": 15 } }, - { - "filename": "unknown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 79, - "y": 160, - "w": 16, - "h": 24 - } - }, - { - "filename": "n_solarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 106, - "y": 71, - "w": 23, - "h": 21 - } - }, - { - "filename": "rusted_sword", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 102, - "y": 92, - "w": 23, - "h": 22 - } - }, - { - "filename": "fire_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 101, - "y": 114, - "w": 22, - "h": 23 - } - }, - { - "filename": "fire_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 95, - "y": 137, - "w": 22, - "h": 23 - } - }, - { - "filename": "flying_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 95, - "y": 160, - "w": 22, - "h": 23 - } - }, - { - "filename": "abomasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 79, - "y": 184, - "w": 16, - "h": 16 - } - }, - { - "filename": "focus_sash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 78, - "y": 200, - "w": 22, - "h": 23 - } - }, - { - "filename": "ghost_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 78, - "y": 223, - "w": 22, - "h": 23 - } - }, - { - "filename": "shock_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 95, - "y": 183, - "w": 23, - "h": 17 - } - }, - { - "filename": "grass_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 79, - "y": 246, - "w": 22, - "h": 23 - } - }, - { - "filename": "ground_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 79, - "y": 269, - "w": 22, - "h": 23 - } - }, - { - "filename": "ice_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 100, - "y": 200, - "w": 22, - "h": 23 - } - }, - { - "filename": "never_melt_ice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 100, - "y": 223, - "w": 22, - "h": 23 - } - }, - { - "filename": "lansat_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 101, - "y": 246, - "w": 21, - "h": 23 - } - }, - { - "filename": "leaf_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 101, - "y": 269, - "w": 21, - "h": 23 - } - }, - { - "filename": "normal_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 80, - "y": 292, - "w": 22, - "h": 23 - } - }, - { - "filename": "mystic_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 20, - "h": 23 - }, - "frame": { - "x": 102, - "y": 292, - "w": 20, - "h": 23 - } - }, - { - "filename": "petaya_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 86, - "y": 315, - "w": 22, - "h": 23 - } - }, - { - "filename": "full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 4, - "w": 15, - "h": 23 - }, - "frame": { - "x": 108, - "y": 315, - "w": 15, - "h": 23 - } - }, - { - "filename": "poison_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 89, - "y": 338, - "w": 22, - "h": 23 - } - }, - { - "filename": "psychic_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 91, - "y": 361, - "w": 22, - "h": 23 - } - }, - { - "filename": "hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 111, - "y": 338, - "w": 17, - "h": 23 - } - }, - { - "filename": "potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 113, - "y": 361, - "w": 17, - "h": 23 - } - }, { "filename": "prism_scale", "rotated": false, @@ -3027,56 +87,14 @@ "h": 15 }, "frame": { - "x": 91, - "y": 384, + "x": 55, + "y": 0, "w": 15, "h": 15 } }, { - "filename": "zinc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 117, - "y": 137, - "w": 16, - "h": 24 - } - }, - { - "filename": "charcoal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 117, - "y": 161, - "w": 22, - "h": 22 - } - }, - { - "filename": "wise_glasses", + "filename": "silver_powder", "rotated": false, "trimmed": true, "sourceSize": { @@ -3085,733 +103,19 @@ }, "spriteSourceSize": { "x": 4, - "y": 8, - "w": 23, - "h": 17 + "y": 11, + "w": 24, + "h": 15 }, "frame": { - "x": 118, - "y": 183, - "w": 23, - "h": 17 + "x": 70, + "y": 0, + "w": 24, + "h": 15 } }, { - "filename": "reaper_cloth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 122, - "y": 200, - "w": 22, - "h": 23 - } - }, - { - "filename": "rock_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 122, - "y": 223, - "w": 22, - "h": 23 - } - }, - { - "filename": "steel_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 122, - "y": 246, - "w": 22, - "h": 23 - } - }, - { - "filename": "stellar_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 122, - "y": 269, - "w": 22, - "h": 23 - } - }, - { - "filename": "water_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 122, - "y": 292, - "w": 22, - "h": 23 - } - }, - { - "filename": "sharp_beak", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 123, - "y": 315, - "w": 21, - "h": 23 - } - }, - { - "filename": "sachet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 18, - "h": 23 - }, - "frame": { - "x": 128, - "y": 338, - "w": 18, - "h": 23 - } - }, - { - "filename": "super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 130, - "y": 361, - "w": 17, - "h": 23 - } - }, - { - "filename": "whipped_dream", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 123, - "y": 114, - "w": 21, - "h": 23 - } - }, - { - "filename": "dire_hit", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 125, - "y": 92, - "w": 22, - "h": 22 - } - }, - { - "filename": "wide_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 147, - "y": 84, - "w": 22, - "h": 23 - } - }, - { - "filename": "dna_splicers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 169, - "y": 84, - "w": 22, - "h": 22 - } - }, - { - "filename": "leftovers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 15, - "h": 22 - }, - "frame": { - "x": 191, - "y": 84, - "w": 15, - "h": 22 - } - }, - { - "filename": "wellspring_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 206, - "y": 85, - "w": 23, - "h": 21 - } - }, - { - "filename": "deep_sea_tooth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 229, - "y": 85, - "w": 22, - "h": 21 - } - }, - { - "filename": "mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 251, - "y": 90, - "w": 23, - "h": 19 - } - }, - { - "filename": "pair_of_tickets", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 274, - "y": 90, - "w": 23, - "h": 19 - } - }, - { - "filename": "big_nugget", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 297, - "y": 90, - "w": 20, - "h": 20 - } - }, - { - "filename": "electirizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 317, - "y": 84, - "w": 22, - "h": 22 - } - }, - { - "filename": "enigma_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 133, - "y": 137, - "w": 22, - "h": 22 - } - }, - { - "filename": "ganlon_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 139, - "y": 159, - "w": 22, - "h": 22 - } - }, - { - "filename": "blunder_policy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 19 - }, - "frame": { - "x": 141, - "y": 181, - "w": 22, - "h": 19 - } - }, - { - "filename": "guard_spec", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 200, - "w": 22, - "h": 22 - } - }, - { - "filename": "ice_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 222, - "w": 22, - "h": 22 - } - }, - { - "filename": "magmarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 244, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_bug", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 266, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_dark", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 288, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_dragon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 144, - "y": 310, - "w": 22, - "h": 22 - } - }, - { - "filename": "hard_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 20, - "h": 22 - }, - "frame": { - "x": 146, - "y": 332, - "w": 20, - "h": 22 - } - }, - { - "filename": "lock_capsule", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 147, - "y": 354, - "w": 19, - "h": 22 - } - }, - { - "filename": "deep_sea_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 147, - "y": 107, - "w": 22, - "h": 20 - } - }, - { - "filename": "liechi_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 169, - "y": 106, - "w": 22, - "h": 21 - } - }, - { - "filename": "memory_electric", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 191, - "y": 106, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_fairy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 213, - "y": 106, - "w": 22, - "h": 22 - } - }, - { - "filename": "mystery_egg", + "filename": "abomasite", "rotated": false, "trimmed": true, "sourceSize": { @@ -3822,160 +126,13 @@ "x": 8, "y": 8, "w": 16, - "h": 18 + "h": 16 }, "frame": { - "x": 235, - "y": 106, + "x": 94, + "y": 0, "w": 16, - "h": 18 - } - }, - { - "filename": "relic_crown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 18 - }, - "frame": { - "x": 251, - "y": 109, - "w": 23, - "h": 18 - } - }, - { - "filename": "reviver_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 8, - "w": 23, - "h": 20 - }, - "frame": { - "x": 274, - "y": 109, - "w": 23, - "h": 20 - } - }, - { - "filename": "blue_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 297, - "y": 110, - "w": 20, - "h": 20 - } - }, - { - "filename": "memory_fighting", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 317, - "y": 106, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_fire", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 155, - "y": 127, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_flying", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 339, - "y": 83, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_ghost", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 339, - "y": 105, - "w": 22, - "h": 22 + "h": 16 } }, { @@ -3993,33 +150,12 @@ "h": 16 }, "frame": { - "x": 361, - "y": 83, + "x": 110, + "y": 0, "w": 16, "h": 16 } }, - { - "filename": "memory_grass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 377, - "y": 94, - "w": 22, - "h": 22 - } - }, { "filename": "aerodactylite", "rotated": false, @@ -4035,8 +171,8 @@ "h": 16 }, "frame": { - "x": 361, - "y": 99, + "x": 126, + "y": 0, "w": 16, "h": 16 } @@ -4056,243 +192,12 @@ "h": 16 }, "frame": { - "x": 361, - "y": 115, + "x": 142, + "y": 0, "w": 16, "h": 16 } }, - { - "filename": "memory_ground", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 377, - "y": 116, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_ice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 177, - "y": 128, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_normal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 199, - "y": 128, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_normal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 199, - "y": 128, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_poison", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 221, - "y": 128, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_psychic", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 243, - "y": 127, - "w": 22, - "h": 22 - } - }, - { - "filename": "shell_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 23, - "h": 20 - }, - "frame": { - "x": 265, - "y": 129, - "w": 23, - "h": 20 - } - }, - { - "filename": "dubious_disc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 288, - "y": 130, - "w": 22, - "h": 19 - } - }, - { - "filename": "big_mushroom", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 19 - }, - "frame": { - "x": 147, - "y": 376, - "w": 19, - "h": 19 - } - }, - { - "filename": "fairy_feather", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 20 - }, - "frame": { - "x": 339, - "y": 127, - "w": 22, - "h": 20 - } - }, - { - "filename": "malicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 317, - "y": 128, - "w": 22, - "h": 20 - } - }, { "filename": "alakazite", "rotated": false, @@ -4308,33 +213,12 @@ "h": 16 }, "frame": { - "x": 361, - "y": 131, + "x": 158, + "y": 0, "w": 16, "h": 16 } }, - { - "filename": "memory_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 377, - "y": 138, - "w": 22, - "h": 22 - } - }, { "filename": "altarianite", "rotated": false, @@ -4350,138 +234,12 @@ "h": 16 }, "frame": { - "x": 161, - "y": 149, + "x": 174, + "y": 0, "w": 16, "h": 16 } }, - { - "filename": "memory_steel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 177, - "y": 150, - "w": 22, - "h": 22 - } - }, - { - "filename": "memory_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 199, - "y": 150, - "w": 22, - "h": 22 - } - }, - { - "filename": "mini_black_hole", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 221, - "y": 150, - "w": 22, - "h": 22 - } - }, - { - "filename": "protector", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 243, - "y": 149, - "w": 22, - "h": 22 - } - }, - { - "filename": "scroll_of_darkness", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 265, - "y": 149, - "w": 22, - "h": 22 - } - }, - { - "filename": "scroll_of_waters", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 287, - "y": 149, - "w": 22, - "h": 22 - } - }, { "filename": "ampharosite", "rotated": false, @@ -4497,1986 +255,12 @@ "h": 16 }, "frame": { - "x": 161, - "y": 165, + "x": 190, + "y": 0, "w": 16, "h": 16 } }, - { - "filename": "lum_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 163, - "y": 181, - "w": 20, - "h": 19 - } - }, - { - "filename": "metal_coat", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 166, - "y": 200, - "w": 19, - "h": 22 - } - }, - { - "filename": "shed_shell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 222, - "w": 22, - "h": 22 - } - }, - { - "filename": "starf_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 244, - "w": 22, - "h": 22 - } - }, - { - "filename": "thunder_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 266, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_bug", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 288, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_dark", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 310, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_dragon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 332, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_electric", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 166, - "y": 354, - "w": 22, - "h": 22 - } - }, - { - "filename": "sweet_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 166, - "y": 376, - "w": 22, - "h": 21 - } - }, - { - "filename": "tm_fairy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 183, - "y": 172, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_fighting", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 205, - "y": 172, - "w": 22, - "h": 22 - } - }, - { - "filename": "metronome", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 227, - "y": 172, - "w": 17, - "h": 22 - } - }, - { - "filename": "tm_fire", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 244, - "y": 171, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_flying", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 266, - "y": 171, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ghost", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 288, - "y": 171, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_grass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 185, - "y": 194, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ground", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 207, - "y": 194, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 216, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_poison", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 238, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_psychic", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 260, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 282, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_steel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 304, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 326, - "w": 22, - "h": 22 - } - }, - { - "filename": "water_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 348, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_accuracy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 188, - "y": 370, - "w": 22, - "h": 22 - } - }, - { - "filename": "sitrus_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 20, - "h": 22 - }, - "frame": { - "x": 210, - "y": 216, - "w": 20, - "h": 22 - } - }, - { - "filename": "x_attack", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 238, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_defense", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 260, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_sp_atk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 282, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_sp_def", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 304, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_speed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 210, - "y": 326, - "w": 22, - "h": 22 - } - }, - { - "filename": "syrupy_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 210, - "y": 348, - "w": 22, - "h": 21 - } - }, - { - "filename": "tart_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 210, - "y": 369, - "w": 22, - "h": 21 - } - }, - { - "filename": "soothe_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 229, - "y": 194, - "w": 17, - "h": 22 - } - }, - { - "filename": "dusk_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 246, - "y": 193, - "w": 21, - "h": 21 - } - }, - { - "filename": "poison_barb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 267, - "y": 193, - "w": 21, - "h": 21 - } - }, - { - "filename": "shiny_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 288, - "y": 193, - "w": 21, - "h": 21 - } - }, - { - "filename": "dawn_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 21 - }, - "frame": { - "x": 230, - "y": 216, - "w": 20, - "h": 21 - } - }, - { - "filename": "tera_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 250, - "y": 214, - "w": 22, - "h": 20 - } - }, - { - "filename": "upgrade", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 272, - "y": 214, - "w": 22, - "h": 19 - } - }, - { - "filename": "quick_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 21 - }, - "frame": { - "x": 232, - "y": 237, - "w": 19, - "h": 21 - } - }, - { - "filename": "spell_tag", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 19, - "h": 21 - }, - "frame": { - "x": 232, - "y": 258, - "w": 19, - "h": 21 - } - }, - { - "filename": "zoom_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 232, - "y": 279, - "w": 21, - "h": 21 - } - }, - { - "filename": "gb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 232, - "y": 300, - "w": 20, - "h": 20 - } - }, - { - "filename": "magnet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 232, - "y": 320, - "w": 20, - "h": 20 - } - }, - { - "filename": "mb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 232, - "y": 340, - "w": 20, - "h": 20 - } - }, - { - "filename": "pb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 232, - "y": 360, - "w": 20, - "h": 20 - } - }, - { - "filename": "metal_alloy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 21, - "h": 19 - }, - "frame": { - "x": 232, - "y": 380, - "w": 21, - "h": 19 - } - }, - { - "filename": "pb_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 251, - "y": 234, - "w": 20, - "h": 20 - } - }, - { - "filename": "rb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 251, - "y": 254, - "w": 20, - "h": 20 - } - }, - { - "filename": "candy_jar", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 294, - "y": 214, - "w": 19, - "h": 20 - } - }, - { - "filename": "hard_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 253, - "y": 274, - "w": 19, - "h": 20 - } - }, - { - "filename": "everstone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 17 - }, - "frame": { - "x": 253, - "y": 294, - "w": 20, - "h": 17 - } - }, - { - "filename": "smooth_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 252, - "y": 311, - "w": 20, - "h": 20 - } - }, - { - "filename": "strange_ball", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 252, - "y": 331, - "w": 20, - "h": 20 - } - }, - { - "filename": "ub", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 252, - "y": 351, - "w": 20, - "h": 20 - } - }, - { - "filename": "miracle_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 19, - "h": 19 - }, - "frame": { - "x": 253, - "y": 371, - "w": 19, - "h": 19 - } - }, - { - "filename": "masterpiece_teacup", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 21, - "h": 18 - }, - "frame": { - "x": 339, - "y": 147, - "w": 21, - "h": 18 - } - }, - { - "filename": "golden_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 360, - "y": 147, - "w": 17, - "h": 20 - } - }, - { - "filename": "sharp_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 21, - "h": 18 - }, - "frame": { - "x": 377, - "y": 160, - "w": 21, - "h": 18 - } - }, - { - "filename": "unremarkable_teacup", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 21, - "h": 18 - }, - "frame": { - "x": 272, - "y": 233, - "w": 21, - "h": 18 - } - }, - { - "filename": "razor_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 271, - "y": 251, - "w": 20, - "h": 19 - } - }, - { - "filename": "wl_ability_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 293, - "y": 234, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_antidote", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 291, - "y": 252, - "w": 20, - "h": 18 - } - }, - { - "filename": "razor_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 18, - "h": 20 - }, - "frame": { - "x": 272, - "y": 270, - "w": 18, - "h": 20 - } - }, - { - "filename": "wl_awakening", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 270, - "w": 20, - "h": 18 - } - }, - { - "filename": "lucky_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 273, - "y": 290, - "w": 17, - "h": 20 - } - }, - { - "filename": "wl_burn_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 288, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_custom_spliced", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 306, - "w": 20, - "h": 18 - } - }, - { - "filename": "oval_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 19 - }, - "frame": { - "x": 272, - "y": 311, - "w": 18, - "h": 19 - } - }, - { - "filename": "candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 11, - "w": 18, - "h": 18 - }, - "frame": { - "x": 272, - "y": 330, - "w": 18, - "h": 18 - } - }, - { - "filename": "wl_custom_thief", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 324, - "w": 20, - "h": 18 - } - }, - { - "filename": "dark_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 272, - "y": 348, - "w": 18, - "h": 18 - } - }, - { - "filename": "wl_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 342, - "w": 20, - "h": 18 - } - }, - { - "filename": "light_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 272, - "y": 366, - "w": 18, - "h": 18 - } - }, - { - "filename": "wl_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 360, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 290, - "y": 378, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_full_restore", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 311, - "y": 252, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_guard_spec", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 270, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 288, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_ice_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 306, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_item_drop", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 324, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_item_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 342, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 360, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 378, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 309, - "y": 193, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 313, - "y": 211, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_paralyze_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 313, - "y": 229, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 309, - "y": 149, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_reset_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 310, - "y": 167, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 330, - "y": 165, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 350, - "y": 167, - "w": 20, - "h": 18 - } - }, - { - "filename": "relic_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 9, - "w": 17, - "h": 16 - }, - "frame": { - "x": 333, - "y": 183, - "w": 17, - "h": 16 - } - }, { "filename": "audinite", "rotated": false, @@ -6492,8 +276,8 @@ "h": 16 }, "frame": { - "x": 350, - "y": 185, + "x": 206, + "y": 0, "w": 16, "h": 16 } @@ -6513,8 +297,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 199, + "x": 222, + "y": 0, "w": 16, "h": 16 } @@ -6534,8 +318,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 215, + "x": 238, + "y": 0, "w": 16, "h": 16 } @@ -6555,8 +339,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 231, + "x": 254, + "y": 0, "w": 16, "h": 16 } @@ -6576,8 +360,8 @@ "h": 16 }, "frame": { - "x": 349, - "y": 201, + "x": 270, + "y": 0, "w": 16, "h": 16 } @@ -6597,8 +381,8 @@ "h": 16 }, "frame": { - "x": 349, - "y": 217, + "x": 286, + "y": 0, "w": 16, "h": 16 } @@ -6618,8 +402,8 @@ "h": 16 }, "frame": { - "x": 349, - "y": 233, + "x": 302, + "y": 0, "w": 16, "h": 16 } @@ -6639,8 +423,8 @@ "h": 16 }, "frame": { - "x": 331, - "y": 247, + "x": 318, + "y": 0, "w": 16, "h": 16 } @@ -6660,8 +444,8 @@ "h": 16 }, "frame": { - "x": 347, - "y": 249, + "x": 334, + "y": 0, "w": 16, "h": 16 } @@ -6681,8 +465,8 @@ "h": 16 }, "frame": { - "x": 331, - "y": 263, + "x": 350, + "y": 0, "w": 16, "h": 16 } @@ -6702,8 +486,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 279, + "x": 366, + "y": 0, "w": 16, "h": 16 } @@ -6723,8 +507,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 295, + "x": 382, + "y": 0, "w": 16, "h": 16 } @@ -6744,12 +528,33 @@ "h": 16 }, "frame": { - "x": 330, - "y": 311, + "x": 398, + "y": 0, "w": 16, "h": 16 } }, + { + "filename": "revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 12, + "h": 17 + }, + "frame": { + "x": 0, + "y": 11, + "w": 12, + "h": 17 + } + }, { "filename": "glalitite", "rotated": false, @@ -6765,8 +570,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 327, + "x": 12, + "y": 14, "w": 16, "h": 16 } @@ -6786,8 +591,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 343, + "x": 28, + "y": 15, "w": 16, "h": 16 } @@ -6807,8 +612,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 359, + "x": 44, + "y": 15, "w": 16, "h": 16 } @@ -6828,8 +633,8 @@ "h": 16 }, "frame": { - "x": 330, - "y": 375, + "x": 60, + "y": 15, "w": 16, "h": 16 } @@ -6849,8 +654,8 @@ "h": 16 }, "frame": { - "x": 347, - "y": 265, + "x": 76, + "y": 15, "w": 16, "h": 16 } @@ -6870,8 +675,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 281, + "x": 92, + "y": 16, "w": 16, "h": 16 } @@ -6891,8 +696,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 297, + "x": 108, + "y": 16, "w": 16, "h": 16 } @@ -6912,8 +717,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 313, + "x": 124, + "y": 16, "w": 16, "h": 16 } @@ -6933,8 +738,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 329, + "x": 140, + "y": 16, "w": 16, "h": 16 } @@ -6954,8 +759,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 345, + "x": 156, + "y": 16, "w": 16, "h": 16 } @@ -6975,8 +780,8 @@ "h": 16 }, "frame": { - "x": 346, - "y": 361, + "x": 172, + "y": 16, "w": 16, "h": 16 } @@ -6996,12 +801,33 @@ "h": 16 }, "frame": { - "x": 346, - "y": 377, + "x": 188, + "y": 16, "w": 16, "h": 16 } }, + { + "filename": "mega_bracelet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 16 + }, + "frame": { + "x": 204, + "y": 16, + "w": 20, + "h": 16 + } + }, { "filename": "metagrossite", "rotated": false, @@ -7017,8 +843,8 @@ "h": 16 }, "frame": { - "x": 366, - "y": 185, + "x": 224, + "y": 16, "w": 16, "h": 16 } @@ -7038,8 +864,8 @@ "h": 16 }, "frame": { - "x": 365, - "y": 201, + "x": 240, + "y": 16, "w": 16, "h": 16 } @@ -7059,8 +885,8 @@ "h": 16 }, "frame": { - "x": 365, - "y": 217, + "x": 256, + "y": 16, "w": 16, "h": 16 } @@ -7080,8 +906,8 @@ "h": 16 }, "frame": { - "x": 365, - "y": 233, + "x": 272, + "y": 16, "w": 16, "h": 16 } @@ -7101,8 +927,8 @@ "h": 16 }, "frame": { - "x": 363, - "y": 249, + "x": 288, + "y": 16, "w": 16, "h": 16 } @@ -7122,8 +948,8 @@ "h": 16 }, "frame": { - "x": 363, - "y": 265, + "x": 304, + "y": 16, "w": 16, "h": 16 } @@ -7143,12 +969,33 @@ "h": 16 }, "frame": { - "x": 362, - "y": 281, + "x": 320, + "y": 16, "w": 16, "h": 16 } }, + { + "filename": "relic_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 9, + "w": 17, + "h": 16 + }, + "frame": { + "x": 336, + "y": 16, + "w": 17, + "h": 16 + } + }, { "filename": "sablenite", "rotated": false, @@ -7164,8 +1011,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 297, + "x": 353, + "y": 16, "w": 16, "h": 16 } @@ -7185,8 +1032,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 313, + "x": 369, + "y": 16, "w": 16, "h": 16 } @@ -7206,8 +1053,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 329, + "x": 385, + "y": 16, "w": 16, "h": 16 } @@ -7227,8 +1074,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 345, + "x": 0, + "y": 30, "w": 16, "h": 16 } @@ -7248,8 +1095,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 361, + "x": 16, + "y": 31, "w": 16, "h": 16 } @@ -7269,8 +1116,8 @@ "h": 16 }, "frame": { - "x": 362, - "y": 377, + "x": 32, + "y": 31, "w": 16, "h": 16 } @@ -7290,8 +1137,8 @@ "h": 16 }, "frame": { - "x": 382, - "y": 178, + "x": 48, + "y": 31, "w": 16, "h": 16 } @@ -7311,8 +1158,8 @@ "h": 16 }, "frame": { - "x": 382, - "y": 194, + "x": 64, + "y": 31, "w": 16, "h": 16 } @@ -7332,8 +1179,8 @@ "h": 16 }, "frame": { - "x": 381, - "y": 210, + "x": 80, + "y": 32, "w": 16, "h": 16 } @@ -7353,8 +1200,8 @@ "h": 16 }, "frame": { - "x": 381, - "y": 226, + "x": 96, + "y": 32, "w": 16, "h": 16 } @@ -7374,8 +1221,8 @@ "h": 16 }, "frame": { - "x": 381, - "y": 242, + "x": 112, + "y": 32, "w": 16, "h": 16 } @@ -7395,60 +1242,6612 @@ "h": 16 }, "frame": { - "x": 379, - "y": 258, + "x": 128, + "y": 32, "w": 16, "h": 16 } }, - { - "filename": "toxic_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 379, - "y": 274, - "w": 18, - "h": 18 - } - }, - { - "filename": "flame_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 379, - "y": 292, - "w": 18, - "h": 18 - } - } + { + "filename": "black_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 144, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "burn_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 167, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "chill_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 190, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "douse_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 213, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "everstone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 17 + }, + "frame": { + "x": 236, + "y": 32, + "w": 20, + "h": 17 + } + }, + { + "filename": "shock_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 256, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "wise_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 279, + "y": 32, + "w": 23, + "h": 17 + } + }, + { + "filename": "candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 11, + "w": 18, + "h": 18 + }, + "frame": { + "x": 302, + "y": 32, + "w": 18, + "h": 18 + } + }, + { + "filename": "choice_specs", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 320, + "y": 32, + "w": 24, + "h": 18 + } + }, + { + "filename": "dark_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 344, + "y": 32, + "w": 18, + "h": 18 + } + }, + { + "filename": "dragon_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 362, + "y": 32, + "w": 24, + "h": 18 + } + }, + { + "filename": "flame_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 386, + "y": 32, + "w": 18, + "h": 18 + } + }, + { + "filename": "mystery_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 18 + }, + "frame": { + "x": 0, + "y": 46, + "w": 16, + "h": 18 + } + }, + { + "filename": "light_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 16, + "y": 47, + "w": 18, + "h": 18 + } + }, + { + "filename": "masterpiece_teacup", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 21, + "h": 18 + }, + "frame": { + "x": 34, + "y": 47, + "w": 21, + "h": 18 + } + }, + { + "filename": "relic_crown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 18 + }, + "frame": { + "x": 55, + "y": 47, + "w": 23, + "h": 18 + } + }, + { + "filename": "sharp_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 21, + "h": 18 + }, + "frame": { + "x": 78, + "y": 48, + "w": 21, + "h": 18 + } + }, + { + "filename": "toxic_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 99, + "y": 48, + "w": 18, + "h": 18 + } + }, + { + "filename": "unremarkable_teacup", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 21, + "h": 18 + }, + "frame": { + "x": 117, + "y": 48, + "w": 21, + "h": 18 + } + }, + { + "filename": "wl_ability_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 138, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_antidote", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 158, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_awakening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 178, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_burn_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 198, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_custom_spliced", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 218, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_custom_thief", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 238, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 258, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 278, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 298, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_full_restore", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 318, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_guard_spec", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 338, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 358, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_ice_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 378, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "leftovers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 15, + "h": 22 + }, + "frame": { + "x": 398, + "y": 50, + "w": 15, + "h": 22 + } + }, + { + "filename": "wl_item_drop", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 0, + "y": 65, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_item_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 20, + "y": 65, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 40, + "y": 65, + "w": 20, + "h": 18 + } + }, + { + "filename": "oval_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 19 + }, + "frame": { + "x": 60, + "y": 65, + "w": 18, + "h": 19 + } + }, + { + "filename": "wl_max_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 78, + "y": 66, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 98, + "y": 66, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 118, + "y": 66, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_paralyze_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 138, + "y": 67, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 158, + "y": 67, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_reset_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 178, + "y": 67, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 198, + "y": 67, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 218, + "y": 67, + "w": 20, + "h": 18 + } + }, + { + "filename": "big_mushroom", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 19 + }, + "frame": { + "x": 238, + "y": 67, + "w": 19, + "h": 19 + } + }, + { + "filename": "blunder_policy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 19 + }, + "frame": { + "x": 257, + "y": 67, + "w": 22, + "h": 19 + } + }, + { + "filename": "miracle_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 279, + "y": 67, + "w": 19, + "h": 19 + } + }, + { + "filename": "coupon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 298, + "y": 68, + "w": 23, + "h": 19 + } + }, + { + "filename": "dubious_disc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 321, + "y": 68, + "w": 22, + "h": 19 + } + }, + { + "filename": "golden_mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 343, + "y": 68, + "w": 23, + "h": 19 + } + }, + { + "filename": "lum_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 366, + "y": 68, + "w": 20, + "h": 19 + } + }, + { + "filename": "metal_alloy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 21, + "h": 19 + }, + "frame": { + "x": 386, + "y": 72, + "w": 21, + "h": 19 + } + }, + { + "filename": "mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 0, + "y": 83, + "w": 23, + "h": 19 + } + }, + { + "filename": "pair_of_tickets", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 23, + "y": 83, + "w": 23, + "h": 19 + } + }, + { + "filename": "razor_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 46, + "y": 84, + "w": 20, + "h": 19 + } + }, + { + "filename": "upgrade", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 66, + "y": 84, + "w": 22, + "h": 19 + } + }, + { + "filename": "apicot_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 88, + "y": 84, + "w": 19, + "h": 20 + } + }, + { + "filename": "big_nugget", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 107, + "y": 84, + "w": 20, + "h": 20 + } + }, + { + "filename": "binding_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 23, + "h": 20 + }, + "frame": { + "x": 127, + "y": 85, + "w": 23, + "h": 20 + } + }, + { + "filename": "blue_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 150, + "y": 85, + "w": 20, + "h": 20 + } + }, + { + "filename": "candy_jar", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 170, + "y": 85, + "w": 19, + "h": 20 + } + }, + { + "filename": "chipped_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 26, + "h": 20 + }, + "frame": { + "x": 189, + "y": 85, + "w": 26, + "h": 20 + } + }, + { + "filename": "deep_sea_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 215, + "y": 85, + "w": 22, + "h": 20 + } + }, + { + "filename": "cracked_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 26, + "h": 20 + }, + "frame": { + "x": 237, + "y": 86, + "w": 26, + "h": 20 + } + }, + { + "filename": "fairy_feather", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 20 + }, + "frame": { + "x": 263, + "y": 86, + "w": 22, + "h": 20 + } + }, + { + "filename": "gb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 285, + "y": 87, + "w": 20, + "h": 20 + } + }, + { + "filename": "golden_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 305, + "y": 87, + "w": 17, + "h": 20 + } + }, + { + "filename": "hard_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 322, + "y": 87, + "w": 19, + "h": 20 + } + }, + { + "filename": "icy_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 341, + "y": 87, + "w": 24, + "h": 20 + } + }, + { + "filename": "lucky_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 365, + "y": 87, + "w": 17, + "h": 20 + } + }, + { + "filename": "legend_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 25, + "h": 20 + }, + "frame": { + "x": 382, + "y": 91, + "w": 25, + "h": 20 + } + }, + { + "filename": "magnet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 0, + "y": 102, + "w": 20, + "h": 20 + } + }, + { + "filename": "malicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 20, + "y": 102, + "w": 22, + "h": 20 + } + }, + { + "filename": "mb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 42, + "y": 103, + "w": 20, + "h": 20 + } + }, + { + "filename": "pb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 62, + "y": 103, + "w": 20, + "h": 20 + } + }, + { + "filename": "pb_gold", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 82, + "y": 104, + "w": 20, + "h": 20 + } + }, + { + "filename": "razor_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 18, + "h": 20 + }, + "frame": { + "x": 102, + "y": 104, + "w": 18, + "h": 20 + } + }, + { + "filename": "rb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 120, + "y": 105, + "w": 20, + "h": 20 + } + }, + { + "filename": "reviver_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 8, + "w": 23, + "h": 20 + }, + "frame": { + "x": 140, + "y": 105, + "w": 23, + "h": 20 + } + }, + { + "filename": "rusted_shield", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 163, + "y": 105, + "w": 24, + "h": 20 + } + }, + { + "filename": "sacred_ash", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 187, + "y": 105, + "w": 24, + "h": 20 + } + }, + { + "filename": "shadow_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 211, + "y": 105, + "w": 24, + "h": 20 + } + }, + { + "filename": "shell_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 23, + "h": 20 + }, + "frame": { + "x": 235, + "y": 106, + "w": 23, + "h": 20 + } + }, + { + "filename": "smooth_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 258, + "y": 106, + "w": 20, + "h": 20 + } + }, + { + "filename": "soft_sand", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 278, + "y": 107, + "w": 24, + "h": 20 + } + }, + { + "filename": "strange_ball", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 302, + "y": 107, + "w": 20, + "h": 20 + } + }, + { + "filename": "tera_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 322, + "y": 107, + "w": 22, + "h": 20 + } + }, + { + "filename": "ub", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 344, + "y": 107, + "w": 20, + "h": 20 + } + }, + { + "filename": "berry_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 18, + "h": 22 + }, + "frame": { + "x": 364, + "y": 107, + "w": 18, + "h": 22 + } + }, + { + "filename": "adamant_crystal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 382, + "y": 111, + "w": 23, + "h": 21 + } + }, + { + "filename": "amulet_coin", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 0, + "y": 122, + "w": 23, + "h": 21 + } + }, + { + "filename": "quick_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 21 + }, + "frame": { + "x": 23, + "y": 122, + "w": 19, + "h": 21 + } + }, + { + "filename": "auspicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 42, + "y": 123, + "w": 23, + "h": 21 + } + }, + { + "filename": "dawn_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 21 + }, + "frame": { + "x": 65, + "y": 124, + "w": 20, + "h": 21 + } + }, + { + "filename": "deep_sea_tooth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 85, + "y": 124, + "w": 22, + "h": 21 + } + }, + { + "filename": "dusk_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 107, + "y": 125, + "w": 21, + "h": 21 + } + }, + { + "filename": "liechi_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 128, + "y": 125, + "w": 22, + "h": 21 + } + }, + { + "filename": "mint_atk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 150, + "y": 125, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_def", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 178, + "y": 125, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_neutral", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 206, + "y": 125, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spatk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 234, + "y": 126, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spd", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 262, + "y": 127, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spdef", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 290, + "y": 127, + "w": 28, + "h": 21 + } + }, + { + "filename": "moon_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 318, + "y": 127, + "w": 23, + "h": 21 + } + }, + { + "filename": "n_lunarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 341, + "y": 127, + "w": 23, + "h": 21 + } + }, + { + "filename": "metronome", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 364, + "y": 129, + "w": 17, + "h": 22 + } + }, + { + "filename": "n_solarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 381, + "y": 132, + "w": 23, + "h": 21 + } + }, + { + "filename": "poison_barb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 0, + "y": 143, + "w": 21, + "h": 21 + } + }, + { + "filename": "shiny_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 21, + "y": 143, + "w": 21, + "h": 21 + } + }, + { + "filename": "spell_tag", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 19, + "h": 21 + }, + "frame": { + "x": 42, + "y": 144, + "w": 19, + "h": 21 + } + }, + { + "filename": "sweet_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 61, + "y": 145, + "w": 22, + "h": 21 + } + }, + { + "filename": "syrupy_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 83, + "y": 145, + "w": 22, + "h": 21 + } + }, + { + "filename": "tart_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 105, + "y": 146, + "w": 22, + "h": 21 + } + }, + { + "filename": "wellspring_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 127, + "y": 146, + "w": 23, + "h": 21 + } + }, + { + "filename": "zoom_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 150, + "y": 146, + "w": 21, + "h": 21 + } + }, + { + "filename": "blank_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 171, + "y": 146, + "w": 22, + "h": 22 + } + }, + { + "filename": "bug_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 193, + "y": 146, + "w": 22, + "h": 22 + } + }, + { + "filename": "lock_capsule", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 19, + "h": 22 + }, + "frame": { + "x": 215, + "y": 146, + "w": 19, + "h": 22 + } + }, + { + "filename": "charcoal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 234, + "y": 147, + "w": 22, + "h": 22 + } + }, + { + "filename": "dark_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 256, + "y": 148, + "w": 22, + "h": 22 + } + }, + { + "filename": "dire_hit", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 278, + "y": 148, + "w": 22, + "h": 22 + } + }, + { + "filename": "dna_splicers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 300, + "y": 148, + "w": 22, + "h": 22 + } + }, + { + "filename": "dragon_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 322, + "y": 148, + "w": 22, + "h": 22 + } + }, + { + "filename": "hard_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 344, + "y": 148, + "w": 20, + "h": 22 + } + }, + { + "filename": "soothe_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 364, + "y": 151, + "w": 17, + "h": 22 + } + }, + { + "filename": "electirizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 381, + "y": 153, + "w": 22, + "h": 22 + } + }, + { + "filename": "electric_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 0, + "y": 164, + "w": 22, + "h": 22 + } + }, + { + "filename": "metal_coat", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 19, + "h": 22 + }, + "frame": { + "x": 22, + "y": 164, + "w": 19, + "h": 22 + } + }, + { + "filename": "sitrus_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 41, + "y": 165, + "w": 20, + "h": 22 + } + }, + { + "filename": "enigma_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 61, + "y": 166, + "w": 22, + "h": 22 + } + }, + { + "filename": "fairy_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 83, + "y": 166, + "w": 22, + "h": 22 + } + }, + { + "filename": "exp_balance", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 105, + "y": 167, + "w": 24, + "h": 22 + } + }, + { + "filename": "exp_share", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 129, + "y": 167, + "w": 24, + "h": 22 + } + }, + { + "filename": "fighting_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 153, + "y": 168, + "w": 22, + "h": 22 + } + }, + { + "filename": "fire_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 175, + "y": 168, + "w": 22, + "h": 22 + } + }, + { + "filename": "flying_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 197, + "y": 168, + "w": 22, + "h": 22 + } + }, + { + "filename": "full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 4, + "w": 15, + "h": 23 + }, + "frame": { + "x": 219, + "y": 168, + "w": 15, + "h": 23 + } + }, + { + "filename": "ganlon_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 234, + "y": 169, + "w": 22, + "h": 22 + } + }, + { + "filename": "ghost_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 256, + "y": 170, + "w": 22, + "h": 22 + } + }, + { + "filename": "grass_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 278, + "y": 170, + "w": 22, + "h": 22 + } + }, + { + "filename": "ground_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 300, + "y": 170, + "w": 22, + "h": 22 + } + }, + { + "filename": "guard_spec", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 322, + "y": 170, + "w": 22, + "h": 22 + } + }, + { + "filename": "hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 344, + "y": 170, + "w": 17, + "h": 23 + } + }, + { + "filename": "mystic_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 23 + }, + "frame": { + "x": 361, + "y": 173, + "w": 20, + "h": 23 + } + }, + { + "filename": "healing_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 381, + "y": 175, + "w": 23, + "h": 22 + } + }, + { + "filename": "ice_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 0, + "y": 186, + "w": 22, + "h": 22 + } + }, + { + "filename": "ice_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 22, + "y": 187, + "w": 22, + "h": 22 + } + }, + { + "filename": "magmarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 44, + "y": 188, + "w": 22, + "h": 22 + } + }, + { + "filename": "map", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 5, + "w": 27, + "h": 22 + }, + "frame": { + "x": 66, + "y": 188, + "w": 27, + "h": 22 + } + }, + { + "filename": "mini_black_hole", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 93, + "y": 189, + "w": 22, + "h": 22 + } + }, + { + "filename": "peat_block", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 115, + "y": 189, + "w": 24, + "h": 22 + } + }, + { + "filename": "poison_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 139, + "y": 190, + "w": 22, + "h": 22 + } + }, + { + "filename": "protector", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 161, + "y": 190, + "w": 22, + "h": 22 + } + }, + { + "filename": "psychic_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 183, + "y": 190, + "w": 22, + "h": 22 + } + }, + { + "filename": "rock_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 205, + "y": 191, + "w": 22, + "h": 22 + } + }, + { + "filename": "rusted_sword", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 227, + "y": 191, + "w": 23, + "h": 22 + } + }, + { + "filename": "scroll_of_darkness", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 250, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "scroll_of_waters", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 272, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "shed_shell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 294, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "starf_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 316, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "steel_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 338, + "y": 193, + "w": 22, + "h": 22 + } + }, + { + "filename": "dragon_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 360, + "y": 196, + "w": 21, + "h": 23 + } + }, + { + "filename": "thunder_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 381, + "y": 197, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_bug", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 0, + "y": 208, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_dark", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 22, + "y": 209, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_dragon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 44, + "y": 210, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_electric", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 66, + "y": 210, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fairy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 88, + "y": 211, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fighting", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 110, + "y": 211, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fire", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 132, + "y": 212, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_flying", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 154, + "y": 212, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_ghost", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 176, + "y": 212, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_grass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 198, + "y": 213, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_ground", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 220, + "y": 213, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_ice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 242, + "y": 214, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_normal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 264, + "y": 214, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_poison", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 286, + "y": 214, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_psychic", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 308, + "y": 214, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 330, + "y": 215, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_steel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 352, + "y": 219, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 374, + "y": 219, + "w": 22, + "h": 22 + } + }, + { + "filename": "potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 396, + "y": 219, + "w": 17, + "h": 23 + } + }, + { + "filename": "water_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 0, + "y": 230, + "w": 22, + "h": 22 + } + }, + { + "filename": "water_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 22, + "y": 231, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_accuracy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 44, + "y": 232, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_attack", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 66, + "y": 232, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_defense", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 88, + "y": 233, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_sp_atk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 110, + "y": 233, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_sp_def", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 132, + "y": 234, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_speed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 154, + "y": 234, + "w": 22, + "h": 22 + } + }, + { + "filename": "black_belt", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 176, + "y": 234, + "w": 22, + "h": 23 + } + }, + { + "filename": "berry_pouch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 198, + "y": 235, + "w": 23, + "h": 23 + } + }, + { + "filename": "lansat_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 221, + "y": 235, + "w": 21, + "h": 23 + } + }, + { + "filename": "bug_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 242, + "y": 236, + "w": 22, + "h": 23 + } + }, + { + "filename": "clefairy_doll", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 264, + "y": 236, + "w": 24, + "h": 23 + } + }, + { + "filename": "coin_case", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 288, + "y": 236, + "w": 24, + "h": 23 + } + }, + { + "filename": "sachet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 18, + "h": 23 + }, + "frame": { + "x": 312, + "y": 236, + "w": 18, + "h": 23 + } + }, + { + "filename": "dark_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 330, + "y": 237, + "w": 22, + "h": 23 + } + }, + { + "filename": "dragon_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 352, + "y": 241, + "w": 22, + "h": 23 + } + }, + { + "filename": "electric_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 374, + "y": 241, + "w": 22, + "h": 23 + } + }, + { + "filename": "super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 396, + "y": 242, + "w": 17, + "h": 23 + } + }, + { + "filename": "fairy_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 0, + "y": 252, + "w": 22, + "h": 23 + } + }, + { + "filename": "fighting_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 22, + "y": 253, + "w": 22, + "h": 23 + } + }, + { + "filename": "dynamax_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 23 + }, + "frame": { + "x": 44, + "y": 254, + "w": 23, + "h": 23 + } + }, + { + "filename": "leaf_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 67, + "y": 254, + "w": 21, + "h": 23 + } + }, + { + "filename": "expert_belt", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 23 + }, + "frame": { + "x": 88, + "y": 255, + "w": 24, + "h": 23 + } + }, + { + "filename": "calcium", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 112, + "y": 255, + "w": 16, + "h": 24 + } + }, + { + "filename": "fire_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 128, + "y": 256, + "w": 22, + "h": 23 + } + }, + { + "filename": "fire_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 150, + "y": 256, + "w": 22, + "h": 23 + } + }, + { + "filename": "flying_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 172, + "y": 257, + "w": 22, + "h": 23 + } + }, + { + "filename": "focus_sash", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 194, + "y": 258, + "w": 22, + "h": 23 + } + }, + { + "filename": "ghost_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 216, + "y": 258, + "w": 22, + "h": 23 + } + }, + { + "filename": "grass_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 238, + "y": 259, + "w": 22, + "h": 23 + } + }, + { + "filename": "griseous_core", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 260, + "y": 259, + "w": 23, + "h": 23 + } + }, + { + "filename": "ground_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 283, + "y": 259, + "w": 22, + "h": 23 + } + }, + { + "filename": "hearthflame_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 23 + }, + "frame": { + "x": 305, + "y": 259, + "w": 24, + "h": 23 + } + }, + { + "filename": "ice_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 329, + "y": 260, + "w": 22, + "h": 23 + } + }, + { + "filename": "leppa_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 351, + "y": 264, + "w": 24, + "h": 23 + } + }, + { + "filename": "sharp_beak", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 375, + "y": 264, + "w": 21, + "h": 23 + } + }, + { + "filename": "carbos", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 396, + "y": 265, + "w": 16, + "h": 24 + } + }, + { + "filename": "never_melt_ice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 0, + "y": 275, + "w": 22, + "h": 23 + } + }, + { + "filename": "normal_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 22, + "y": 276, + "w": 22, + "h": 23 + } + }, + { + "filename": "petaya_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 44, + "y": 277, + "w": 22, + "h": 23 + } + }, + { + "filename": "poison_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 66, + "y": 277, + "w": 22, + "h": 23 + } + }, + { + "filename": "psychic_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 88, + "y": 278, + "w": 22, + "h": 23 + } + }, + { + "filename": "rare_candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 110, + "y": 279, + "w": 23, + "h": 23 + } + }, + { + "filename": "rarer_candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 133, + "y": 279, + "w": 23, + "h": 23 + } + }, + { + "filename": "hp_up", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 156, + "y": 279, + "w": 16, + "h": 24 + } + }, + { + "filename": "reaper_cloth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 172, + "y": 280, + "w": 22, + "h": 23 + } + }, + { + "filename": "rock_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 194, + "y": 281, + "w": 22, + "h": 23 + } + }, + { + "filename": "steel_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 216, + "y": 281, + "w": 22, + "h": 23 + } + }, + { + "filename": "scope_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 238, + "y": 282, + "w": 24, + "h": 23 + } + }, + { + "filename": "stellar_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 262, + "y": 282, + "w": 22, + "h": 23 + } + }, + { + "filename": "stick", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 284, + "y": 282, + "w": 23, + "h": 23 + } + }, + { + "filename": "water_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 307, + "y": 282, + "w": 22, + "h": 23 + } + }, + { + "filename": "whipped_dream", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 329, + "y": 283, + "w": 21, + "h": 23 + } + }, + { + "filename": "twisted_spoon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 350, + "y": 287, + "w": 24, + "h": 23 + } + }, + { + "filename": "wide_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 374, + "y": 287, + "w": 22, + "h": 23 + } + }, + { + "filename": "elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 396, + "y": 289, + "w": 18, + "h": 24 + } + }, + { + "filename": "catching_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 0, + "y": 298, + "w": 21, + "h": 24 + } + }, + { + "filename": "big_root", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 21, + "y": 299, + "w": 23, + "h": 24 + } + }, + { + "filename": "blank_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 44, + "y": 300, + "w": 24, + "h": 24 + } + }, + { + "filename": "ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 68, + "y": 300, + "w": 18, + "h": 24 + } + }, + { + "filename": "choice_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 86, + "y": 301, + "w": 24, + "h": 24 + } + }, + { + "filename": "draco_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 110, + "y": 302, + "w": 24, + "h": 24 + } + }, + { + "filename": "full_restore", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 134, + "y": 302, + "w": 18, + "h": 24 + } + }, + { + "filename": "dread_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 152, + "y": 303, + "w": 24, + "h": 24 + } + }, + { + "filename": "iron", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 176, + "y": 303, + "w": 16, + "h": 24 + } + }, + { + "filename": "earth_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 192, + "y": 304, + "w": 24, + "h": 24 + } + }, + { + "filename": "lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 216, + "y": 304, + "w": 17, + "h": 24 + } + }, + { + "filename": "fist_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 233, + "y": 305, + "w": 24, + "h": 24 + } + }, + { + "filename": "flame_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 257, + "y": 305, + "w": 24, + "h": 24 + } + }, + { + "filename": "focus_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 281, + "y": 305, + "w": 24, + "h": 24 + } + }, + { + "filename": "golden_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 305, + "y": 305, + "w": 24, + "h": 24 + } + }, + { + "filename": "max_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 329, + "y": 306, + "w": 18, + "h": 24 + } + }, + { + "filename": "gracidea", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 347, + "y": 310, + "w": 24, + "h": 24 + } + }, + { + "filename": "grip_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 371, + "y": 310, + "w": 24, + "h": 24 + } + }, + { + "filename": "max_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 395, + "y": 313, + "w": 18, + "h": 24 + } + }, + { + "filename": "max_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 0, + "y": 322, + "w": 17, + "h": 24 + } + }, + { + "filename": "icicle_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 17, + "y": 323, + "w": 24, + "h": 24 + } + }, + { + "filename": "insect_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 41, + "y": 324, + "w": 24, + "h": 24 + } + }, + { + "filename": "max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 65, + "y": 324, + "w": 18, + "h": 24 + } + }, + { + "filename": "iron_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 83, + "y": 325, + "w": 24, + "h": 24 + } + }, + { + "filename": "kings_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 107, + "y": 326, + "w": 23, + "h": 24 + } + }, + { + "filename": "max_repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 130, + "y": 326, + "w": 16, + "h": 24 + } + }, + { + "filename": "lucky_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 146, + "y": 327, + "w": 24, + "h": 24 + } + }, + { + "filename": "max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 24 + }, + "frame": { + "x": 170, + "y": 327, + "w": 22, + "h": 24 + } + }, + { + "filename": "lucky_punch_great", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 192, + "y": 328, + "w": 24, + "h": 24 + } + }, + { + "filename": "pp_max", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 216, + "y": 328, + "w": 16, + "h": 24 + } + }, + { + "filename": "lucky_punch_master", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 232, + "y": 329, + "w": 24, + "h": 24 + } + }, + { + "filename": "lucky_punch_ultra", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 256, + "y": 329, + "w": 24, + "h": 24 + } + }, + { + "filename": "lustrous_globe", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 280, + "y": 329, + "w": 24, + "h": 24 + } + }, + { + "filename": "meadow_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 304, + "y": 329, + "w": 24, + "h": 24 + } + }, + { + "filename": "pp_up", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 328, + "y": 330, + "w": 16, + "h": 24 + } + }, + { + "filename": "mind_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 344, + "y": 334, + "w": 24, + "h": 24 + } + }, + { + "filename": "muscle_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 368, + "y": 334, + "w": 24, + "h": 24 + } + }, + { + "filename": "oval_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 392, + "y": 337, + "w": 21, + "h": 24 + } + }, + { + "filename": "protein", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 0, + "y": 346, + "w": 16, + "h": 24 + } + }, + { + "filename": "pixie_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 16, + "y": 347, + "w": 24, + "h": 24 + } + }, + { + "filename": "red_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 20, + "h": 24 + }, + "frame": { + "x": 40, + "y": 348, + "w": 20, + "h": 24 + } + }, + { + "filename": "repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 60, + "y": 348, + "w": 16, + "h": 24 + } + }, + { + "filename": "reveal_glass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 76, + "y": 349, + "w": 23, + "h": 24 + } + }, + { + "filename": "salac_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 99, + "y": 350, + "w": 24, + "h": 24 + } + }, + { + "filename": "shiny_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 123, + "y": 350, + "w": 21, + "h": 24 + } + }, + { + "filename": "scanner", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 144, + "y": 351, + "w": 24, + "h": 24 + } + }, + { + "filename": "silk_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 168, + "y": 351, + "w": 24, + "h": 24 + } + }, + { + "filename": "sky_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 192, + "y": 352, + "w": 24, + "h": 24 + } + }, + { + "filename": "super_repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 216, + "y": 352, + "w": 16, + "h": 24 + } + }, + { + "filename": "splash_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 232, + "y": 353, + "w": 24, + "h": 24 + } + }, + { + "filename": "spooky_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 256, + "y": 353, + "w": 24, + "h": 24 + } + }, + { + "filename": "stone_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 280, + "y": 353, + "w": 24, + "h": 24 + } + }, + { + "filename": "sun_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 304, + "y": 353, + "w": 24, + "h": 24 + } + }, + { + "filename": "unknown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 328, + "y": 354, + "w": 16, + "h": 24 + } + }, + { + "filename": "super_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 344, + "y": 358, + "w": 17, + "h": 24 + } + }, + { + "filename": "toxic_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 361, + "y": 358, + "w": 24, + "h": 24 + } + }, + { + "filename": "zap_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 385, + "y": 361, + "w": 24, + "h": 24 + } + }, + { + "filename": "zinc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 0, + "y": 370, + "w": 16, + "h": 24 + } + }, + { + "filename": "black_augurite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 3, + "w": 22, + "h": 25 + }, + "frame": { + "x": 16, + "y": 371, + "w": 22, + "h": 25 + } + }, + { + "filename": "ability_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 3, + "w": 23, + "h": 26 + }, + "frame": { + "x": 38, + "y": 372, + "w": 23, + "h": 26 + } + }, + { + "filename": "cornerstone_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 3, + "w": 24, + "h": 26 + }, + "frame": { + "x": 61, + "y": 373, + "w": 24, + "h": 26 + } + }, + { + "filename": "linking_cord", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 3, + "w": 27, + "h": 26 + }, + "frame": { + "x": 85, + "y": 374, + "w": 27, + "h": 26 + } + }, + { + "filename": "galarica_wreath", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 32, + "h": 27 + }, + "frame": { + "x": 112, + "y": 374, + "w": 32, + "h": 27 + } + }, + { + "filename": "max_mushrooms", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 1, + "y": 3, + "w": 29, + "h": 28 + }, + "frame": { + "x": 144, + "y": 375, + "w": 29, + "h": 28 + } + }, + { + "filename": "prison_bottle", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 30 + }, + "frame": { + "x": 173, + "y": 375, + "w": 17, + "h": 30 + } + }, + { + "filename": "galarica_cuff", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 29, + "h": 30 + }, + "frame": { + "x": 190, + "y": 376, + "w": 29, + "h": 30 + } + }, + { + "filename": "bronze_ribbon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 31 + }, + "frame": { + "x": 219, + "y": 377, + "w": 22, + "h": 31 + } + }, + { + "filename": "exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 241, + "y": 377, + "w": 17, + "h": 31 + } + }, + { + "filename": "golden_exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 258, + "y": 377, + "w": 17, + "h": 31 + } + }, + { + "filename": "great_ribbon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 31 + }, + "frame": { + "x": 275, + "y": 377, + "w": 22, + "h": 31 + } + }, + { + "filename": "master_ribbon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 31 + }, + "frame": { + "x": 297, + "y": 377, + "w": 22, + "h": 31 + } + }, + { + "filename": "rogue_ribbon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 31 + }, + "frame": { + "x": 319, + "y": 378, + "w": 22, + "h": 31 + } + }, + { + "filename": "super_exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 341, + "y": 382, + "w": 17, + "h": 31 + } + }, + { + "filename": "ultra_ribbon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 31 + }, + "frame": { + "x": 358, + "y": 382, + "w": 22, + "h": 31 + } + } ] } ], "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:5676fc2ef4e2b6e18c96ca3c80e7521d:a6286201546cef975121cad6b35c7005:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:b516eabbda93be0375a8d45471c54e6c:5bf73f118de19726fc5d5a538ddc6f22:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index d19bb003b93..51d692b1c73 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/public/images/items/blank_memory.png b/public/images/items/blank_memory.png new file mode 100644 index 00000000000..ddc22d1d4ab Binary files /dev/null and b/public/images/items/blank_memory.png differ diff --git a/public/images/items/blank_plate.png b/public/images/items/blank_plate.png new file mode 100644 index 00000000000..ec82203340c Binary files /dev/null and b/public/images/items/blank_plate.png differ diff --git a/public/images/items/memory_bug.png b/public/images/items/bug_memory.png similarity index 100% rename from public/images/items/memory_bug.png rename to public/images/items/bug_memory.png diff --git a/public/images/items/memory_dark.png b/public/images/items/dark_memory.png similarity index 100% rename from public/images/items/memory_dark.png rename to public/images/items/dark_memory.png diff --git a/public/images/items/draco_plate.png b/public/images/items/draco_plate.png new file mode 100644 index 00000000000..b25df530171 Binary files /dev/null and b/public/images/items/draco_plate.png differ diff --git a/public/images/items/memory_dragon.png b/public/images/items/dragon_memory.png similarity index 100% rename from public/images/items/memory_dragon.png rename to public/images/items/dragon_memory.png diff --git a/public/images/items/dread_plate.png b/public/images/items/dread_plate.png new file mode 100644 index 00000000000..4cdbb76f180 Binary files /dev/null and b/public/images/items/dread_plate.png differ diff --git a/public/images/items/earth_plate.png b/public/images/items/earth_plate.png new file mode 100644 index 00000000000..d40da06f6b6 Binary files /dev/null and b/public/images/items/earth_plate.png differ diff --git a/public/images/items/memory_electric.png b/public/images/items/electric_memory.png similarity index 100% rename from public/images/items/memory_electric.png rename to public/images/items/electric_memory.png diff --git a/public/images/items/memory_fairy.png b/public/images/items/fairy_memory.png similarity index 100% rename from public/images/items/memory_fairy.png rename to public/images/items/fairy_memory.png diff --git a/public/images/items/memory_fighting.png b/public/images/items/fighting_memory.png similarity index 100% rename from public/images/items/memory_fighting.png rename to public/images/items/fighting_memory.png diff --git a/public/images/items/memory_fire.png b/public/images/items/fire_memory.png similarity index 100% rename from public/images/items/memory_fire.png rename to public/images/items/fire_memory.png diff --git a/public/images/items/fist_plate.png b/public/images/items/fist_plate.png new file mode 100644 index 00000000000..6892d821da6 Binary files /dev/null and b/public/images/items/fist_plate.png differ diff --git a/public/images/items/flame_plate.png b/public/images/items/flame_plate.png new file mode 100644 index 00000000000..26a56f18462 Binary files /dev/null and b/public/images/items/flame_plate.png differ diff --git a/public/images/items/memory_flying.png b/public/images/items/flying_memory.png similarity index 100% rename from public/images/items/memory_flying.png rename to public/images/items/flying_memory.png diff --git a/public/images/items/memory_ghost.png b/public/images/items/ghost_memory.png similarity index 100% rename from public/images/items/memory_ghost.png rename to public/images/items/ghost_memory.png diff --git a/public/images/items/memory_grass.png b/public/images/items/grass_memory.png similarity index 100% rename from public/images/items/memory_grass.png rename to public/images/items/grass_memory.png diff --git a/public/images/items/memory_ground.png b/public/images/items/ground_memory.png similarity index 100% rename from public/images/items/memory_ground.png rename to public/images/items/ground_memory.png diff --git a/public/images/items/memory_ice.png b/public/images/items/ice_memory.png similarity index 100% rename from public/images/items/memory_ice.png rename to public/images/items/ice_memory.png diff --git a/public/images/items/icicle_plate.png b/public/images/items/icicle_plate.png new file mode 100644 index 00000000000..67b5138e3e6 Binary files /dev/null and b/public/images/items/icicle_plate.png differ diff --git a/public/images/items/insect_plate.png b/public/images/items/insect_plate.png new file mode 100644 index 00000000000..75b44640a1b Binary files /dev/null and b/public/images/items/insect_plate.png differ diff --git a/public/images/items/iron_plate.png b/public/images/items/iron_plate.png new file mode 100644 index 00000000000..ee892755660 Binary files /dev/null and b/public/images/items/iron_plate.png differ diff --git a/public/images/items/legend_plate.png b/public/images/items/legend_plate.png new file mode 100644 index 00000000000..5b8681ebfe7 Binary files /dev/null and b/public/images/items/legend_plate.png differ diff --git a/public/images/items/meadow_plate.png b/public/images/items/meadow_plate.png new file mode 100644 index 00000000000..a687cb7920d Binary files /dev/null and b/public/images/items/meadow_plate.png differ diff --git a/public/images/items/memory_normal.png b/public/images/items/memory_normal.png deleted file mode 100644 index ab6e5e82729..00000000000 Binary files a/public/images/items/memory_normal.png and /dev/null differ diff --git a/public/images/items/mind_plate.png b/public/images/items/mind_plate.png new file mode 100644 index 00000000000..04001796831 Binary files /dev/null and b/public/images/items/mind_plate.png differ diff --git a/public/images/items/pixie_plate.png b/public/images/items/pixie_plate.png new file mode 100644 index 00000000000..dcc829c107f Binary files /dev/null and b/public/images/items/pixie_plate.png differ diff --git a/public/images/items/memory_poison.png b/public/images/items/poison_memory.png similarity index 100% rename from public/images/items/memory_poison.png rename to public/images/items/poison_memory.png diff --git a/public/images/items/memory_psychic.png b/public/images/items/psychic_memory.png similarity index 100% rename from public/images/items/memory_psychic.png rename to public/images/items/psychic_memory.png diff --git a/public/images/items/memory_rock.png b/public/images/items/rock_memory.png similarity index 100% rename from public/images/items/memory_rock.png rename to public/images/items/rock_memory.png diff --git a/public/images/items/sky_plate.png b/public/images/items/sky_plate.png new file mode 100644 index 00000000000..1fed973142b Binary files /dev/null and b/public/images/items/sky_plate.png differ diff --git a/public/images/items/splash_plate.png b/public/images/items/splash_plate.png new file mode 100644 index 00000000000..a832f3dbf8a Binary files /dev/null and b/public/images/items/splash_plate.png differ diff --git a/public/images/items/spooky_plate.png b/public/images/items/spooky_plate.png new file mode 100644 index 00000000000..b5794713d0d Binary files /dev/null and b/public/images/items/spooky_plate.png differ diff --git a/public/images/items/memory_steel.png b/public/images/items/steel_memory.png similarity index 100% rename from public/images/items/memory_steel.png rename to public/images/items/steel_memory.png diff --git a/public/images/items/stone_plate.png b/public/images/items/stone_plate.png new file mode 100644 index 00000000000..44653583e60 Binary files /dev/null and b/public/images/items/stone_plate.png differ diff --git a/public/images/items/toxic_plate.png b/public/images/items/toxic_plate.png new file mode 100644 index 00000000000..8538e9fce2a Binary files /dev/null and b/public/images/items/toxic_plate.png differ diff --git a/public/images/items/memory_water.png b/public/images/items/water_memory.png similarity index 100% rename from public/images/items/memory_water.png rename to public/images/items/water_memory.png diff --git a/public/images/items/zap_plate.png b/public/images/items/zap_plate.png new file mode 100644 index 00000000000..e582b41937f Binary files /dev/null and b/public/images/items/zap_plate.png differ diff --git a/public/images/pokemon/variant/641-incarnate.json b/public/images/pokemon/variant/641-incarnate.json deleted file mode 100644 index 973f983d2cd..00000000000 --- a/public/images/pokemon/variant/641-incarnate.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "737373": "737373", - "ffffff": "ffffff", - "101010": "101010", - "b5b5bd": "b5b5bd", - "8442ad": "282828", - "5a3173": "121212", - "294a31": "294a31", - "4a9c42": "5fd054", - "422152": "000000", - "ffc500": "ffc500", - "42733a": "317c25", - "6b4229": "6b4229", - "ad7b4a": "ad7b4a", - "deb56b": "deb56b" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/641-therian.json b/public/images/pokemon/variant/641-therian.json deleted file mode 100644 index 5b43a3d7fbf..00000000000 --- a/public/images/pokemon/variant/641-therian.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "5a3a73": "121212", - "8442ad": "282828", - "101010": "101010", - "422152": "000000", - "737373": "737373", - "ffffff": "ffffff", - "b5b5bd": "b5b5bd", - "294a31": "294a31", - "4a9c42": "5fd054", - "deb56b": "ffc500", - "42733a": "317c25", - "ad7b4a": "ad7b4a", - "6b4229": "6b4229", - "de3a29": "deb56b" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/642-incarnate.json b/public/images/pokemon/variant/642-incarnate.json deleted file mode 100644 index 6c247996481..00000000000 --- a/public/images/pokemon/variant/642-incarnate.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "0": { - "737373": "737373", - "101010": "101010", - "b5b5bd": "878787", - "ffffff": "ffffff", - "102152": "521010", - "5a42ad": "992828", - "29426b": "6b2929", - "5284a5": "952f2f", - "63c5ff": "ff6363", - "313131": "313131", - "31317b": "3a1111", - "4a4a4a": "4a4a4a", - "212121": "212121", - "ffc55a": "ffc55a", - "d69431": "d69431" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/642-therian.json b/public/images/pokemon/variant/642-therian.json deleted file mode 100644 index c53d2dbc0fc..00000000000 --- a/public/images/pokemon/variant/642-therian.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "192952": "521010", - "737373": "6a0d0d", - "ffffff": "ffffff", - "101010": "101010", - "5a4aad": "952f2f", - "b5b5bd": "a49696", - "3a3a84": "3a1111", - "5284a5": "7c0b0b", - "29426b": "6b2929", - "63c5ff": "c83f3f", - "d69431": "ffc55a", - "ffc55a": "d69431", - "313131": "313131", - "212121": "212121" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/645-incarnate.json b/public/images/pokemon/variant/645-incarnate.json deleted file mode 100644 index 01a6c034b19..00000000000 --- a/public/images/pokemon/variant/645-incarnate.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "b5b5bd": "999999", - "737373": "737373", - "101010": "101010", - "ffffff": "d0d0d0", - "6b213a": "838383", - "bd4a52": "380d5f", - "a55a3a": "451c6a", - "f77b42": "69418e", - "633110": "2c2c2c", - "ffce63": "9386ff", - "4a2919": "191919", - "634231": "2c143a", - "84634a": "311e42", - "943142": "0b0b0b" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/645-therian.json b/public/images/pokemon/variant/645-therian.json deleted file mode 100644 index b18f38dcfab..00000000000 --- a/public/images/pokemon/variant/645-therian.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "634231": "2c143a", - "101010": "101010", - "bd4a52": "380d5f", - "84634a": "311e42", - "4a2919": "191919", - "737373": "737373", - "ffffff": "d0d0d0", - "b5b5bd": "999999", - "73313a": "838383", - "633110": "2c2c2c", - "f77b42": "69418e", - "a55a3a": "451c6a", - "943142": "0b0b0b", - "ffce63": "9386ff" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/_masterlist.json b/public/images/pokemon/variant/_masterlist.json index adca124fc89..e2802ad3e50 100644 --- a/public/images/pokemon/variant/_masterlist.json +++ b/public/images/pokemon/variant/_masterlist.json @@ -1745,32 +1745,32 @@ 1 ], "641-incarnate": [ - 1, + 0, 0, 0 ], "641-therian": [ - 1, + 0, 0, 0 ], "642-incarnate": [ - 1, + 0, 0, 0 ], "642-therian": [ - 1, + 0, 0, 0 ], "645-incarnate": [ - 1, + 0, 0, 0 ], "645-therian": [ - 1, + 0, 0, 0 ], @@ -4608,32 +4608,32 @@ 1 ], "641-incarnate": [ - 1, + 0, 0, 0 ], "641-therian": [ - 1, + 0, 0, 0 ], "642-incarnate": [ - 1, + 0, 0, 0 ], "642-therian": [ - 1, + 0, 0, 0 ], "645-incarnate": [ - 1, + 0, 0, 0 ], "645-therian": [ - 1, + 0, 0, 0 ], diff --git a/public/images/pokemon/variant/back/641-incarnate.json b/public/images/pokemon/variant/back/641-incarnate.json deleted file mode 100644 index 200c2bbd112..00000000000 --- a/public/images/pokemon/variant/back/641-incarnate.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "0": { - "737373": "737373", - "101010": "101010", - "ffffff": "ffffff", - "b5b5bd": "b5b5bd", - "6b4229": "6b4229", - "deb56b": "deb56b", - "ad7b4a": "ad7b4a", - "5a3173": "121212", - "8442ad": "282828", - "4a9c42": "5fd054", - "294a31": "294a31", - "42733a": "317c25", - "422152": "000000" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/641-therian.json b/public/images/pokemon/variant/back/641-therian.json deleted file mode 100644 index b4ecb861ac8..00000000000 --- a/public/images/pokemon/variant/back/641-therian.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "0": { - "422152": "000000", - "5a3a73": "121212", - "8442ad": "282828", - "101010": "101010", - "ffffff": "ffffff", - "b5b5bd": "b5b5bd", - "737373": "737373", - "294a31": "294a31", - "42733a": "317c25", - "4a9c42": "5fd054", - "ad7b4a": "ad7b4a", - "deb56b": "deb56b", - "6b4229": "6b4229" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/642-incarnate.json b/public/images/pokemon/variant/back/642-incarnate.json deleted file mode 100644 index 10125a512ee..00000000000 --- a/public/images/pokemon/variant/back/642-incarnate.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "0": { - "737373": "737373", - "b5b5bd": "878787", - "ffffff": "ffffff", - "101010": "101010", - "31317b": "3a1111", - "5a42ad": "992828", - "102152": "521010", - "5284a5": "952f2f", - "63c5ff": "ff6363", - "313131": "313131", - "4a4a4a": "4a4a4a", - "212121": "212121", - "29426b": "6b2929" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/642-therian.json b/public/images/pokemon/variant/back/642-therian.json deleted file mode 100644 index 181321289c6..00000000000 --- a/public/images/pokemon/variant/back/642-therian.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "0": { - "737373": "6a0d0d", - "ffffff": "ffffff", - "101010": "101010", - "192952": "521010", - "5a4aad": "952f2f", - "3a3a84": "3a1111", - "b5b5bd": "a49696", - "29426b": "6b2929", - "63c5ff": "c83f3f", - "5284a5": "7c0b0b", - "ffc55a": "d69431", - "d69431": "ffc55a", - "313131": "313131", - "212121": "212121" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/645-incarnate.json b/public/images/pokemon/variant/back/645-incarnate.json deleted file mode 100644 index c3e0980c7eb..00000000000 --- a/public/images/pokemon/variant/back/645-incarnate.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "0": { - "101010": "101010", - "ffffff": "d0d0d0", - "737373": "737373", - "4a2919": "191919", - "bd4a52": "380d5f", - "943142": "0b0b0b", - "b5b5bd": "999999", - "84634a": "311e42", - "634231": "2c143a", - "6b213a": "838383", - "a55a3a": "451c6a", - "633110": "2c2c2c", - "f77b42": "69418e" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/645-therian.json b/public/images/pokemon/variant/back/645-therian.json deleted file mode 100644 index 7b38aaeb747..00000000000 --- a/public/images/pokemon/variant/back/645-therian.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "0": { - "101010": "101010", - "634231": "531975", - "84634a": "311e42", - "4a2919": "191919", - "bd4a52": "380d5f", - "737373": "737373", - "b5b5bd": "999999", - "ffffff": "d0d0d0", - "73313a": "2c143a", - "943142": "311e42", - "633110": "2c2c2c", - "a55a3a": "451c6a", - "ad8c3a": "380d5f", - "f77b42": "69418e", - "ffce63": "9386ff" - } -} \ No newline at end of file diff --git a/public/images/trainer/aqua_grunt_f.json b/public/images/trainer/aqua_grunt_f.json new file mode 100644 index 00000000000..20515f30e5e --- /dev/null +++ b/public/images/trainer/aqua_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "aqua_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 71, + "h": 71 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 22, + "y": 8, + "w": 36, + "h": 71 + }, + "frame": { + "x": 0, + "y": 0, + "w": 36, + "h": 71 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:6db25cb5753163d19bca8e2db45849ae:7d8f51509862bfdf8a78bf42dd0005cd:af0aa9494be37941522487032b556989$" + } +} diff --git a/public/images/trainer/aqua_grunt_f.png b/public/images/trainer/aqua_grunt_f.png new file mode 100644 index 00000000000..132d239c0b8 Binary files /dev/null and b/public/images/trainer/aqua_grunt_f.png differ diff --git a/public/images/trainer/aqua_grunt_m.json b/public/images/trainer/aqua_grunt_m.json new file mode 100644 index 00000000000..93408cc40c8 --- /dev/null +++ b/public/images/trainer/aqua_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "aqua_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 73, + "h": 73 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 17, + "y": 6, + "w": 46, + "h": 73 + }, + "frame": { + "x": 0, + "y": 0, + "w": 46, + "h": 73 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:efd07ff3ed1e610150a4b8ca18974343:d9b85b9eb11182e9e4669e2bd8b08694:72b7b50231708a9486d5f315824e4df1$" + } +} diff --git a/public/images/trainer/aqua_grunt_m.png b/public/images/trainer/aqua_grunt_m.png new file mode 100644 index 00000000000..87dbfd566a1 Binary files /dev/null and b/public/images/trainer/aqua_grunt_m.png differ diff --git a/public/images/trainer/archie.json b/public/images/trainer/archie.json new file mode 100644 index 00000000000..63837d40847 --- /dev/null +++ b/public/images/trainer/archie.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "archie.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 21, + "y": 0, + "w": 42, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 42, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:bfa7fdd7b6ac9be68dc9dc562fb8339f:06f87a279450b21b19294ba956b69c26:4b7980be4e3ac1d20c9eaf970913ec63$" + } +} diff --git a/public/images/trainer/archie.png b/public/images/trainer/archie.png new file mode 100644 index 00000000000..c83975c0690 Binary files /dev/null and b/public/images/trainer/archie.png differ diff --git a/public/images/trainer/cyrus.json b/public/images/trainer/cyrus.json new file mode 100644 index 00000000000..8a3044f4034 --- /dev/null +++ b/public/images/trainer/cyrus.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "cyrus.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 15, + "y": 0, + "w": 48, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 48, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:5fc65535a23867fca7511cc9d7fc15b3:f328e97821f4faffcbca155cc2c5dc2c:55da82f1e1919212896c9c96b682cbd1$" + } +} diff --git a/public/images/trainer/cyrus.png b/public/images/trainer/cyrus.png new file mode 100644 index 00000000000..f7351340568 Binary files /dev/null and b/public/images/trainer/cyrus.png differ diff --git a/public/images/trainer/flare_grunt_f.json b/public/images/trainer/flare_grunt_f.json new file mode 100644 index 00000000000..e536d28a1aa --- /dev/null +++ b/public/images/trainer/flare_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "flare_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 31, + "y": 0, + "w": 23, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 23, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:c30bf82452209a923f4becf13d275a9a:a6355b09f92c9c0388d0b919010f587f:0638dbf213f8a974eb5af76eb1e5ddeb$" + } +} diff --git a/public/images/trainer/flare_grunt_f.png b/public/images/trainer/flare_grunt_f.png new file mode 100644 index 00000000000..4446675dc44 Binary files /dev/null and b/public/images/trainer/flare_grunt_f.png differ diff --git a/public/images/trainer/flare_grunt_m.json b/public/images/trainer/flare_grunt_m.json new file mode 100644 index 00000000000..4d54acbf810 --- /dev/null +++ b/public/images/trainer/flare_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "flare_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 77, + "h": 77 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 24, + "y": 2, + "w": 31, + "h": 77 + }, + "frame": { + "x": 0, + "y": 0, + "w": 31, + "h": 77 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:a26606e70778f88a1a7053b2f2420dde:84abf0d0f6bc90c6a60f660567b2d641:adc35a4070bac9fe828c2605a3b15744$" + } +} diff --git a/public/images/trainer/flare_grunt_m.png b/public/images/trainer/flare_grunt_m.png new file mode 100644 index 00000000000..79eb98449ca Binary files /dev/null and b/public/images/trainer/flare_grunt_m.png differ diff --git a/public/images/trainer/galactic_grunt_f.json b/public/images/trainer/galactic_grunt_f.json new file mode 100644 index 00000000000..d98809432ca --- /dev/null +++ b/public/images/trainer/galactic_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "galactic_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 68, + "h": 68 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 10, + "y": 11, + "w": 57, + "h": 68 + }, + "frame": { + "x": 0, + "y": 0, + "w": 57, + "h": 68 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:3012867f03f02c4ee67a8ab3ad5a000e:77a5f60f1adc158664b3b2ee17bf30fe:7e8259b5177c0a76e5d02d6bdc66affe$" + } +} diff --git a/public/images/trainer/galactic_grunt_f.png b/public/images/trainer/galactic_grunt_f.png new file mode 100644 index 00000000000..209d8ae09ba Binary files /dev/null and b/public/images/trainer/galactic_grunt_f.png differ diff --git a/public/images/trainer/galactic_grunt_m.json b/public/images/trainer/galactic_grunt_m.json new file mode 100644 index 00000000000..508c3fd182a --- /dev/null +++ b/public/images/trainer/galactic_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "galactic_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 73, + "h": 73 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 20, + "y": 6, + "w": 37, + "h": 73 + }, + "frame": { + "x": 0, + "y": 0, + "w": 37, + "h": 73 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:856b85bb5d7a1ea2e7a76708ebf82d21:1687dff972369c6248e4aa5b0795fe62:259dd316440c335df5dc6008166d69ca$" + } +} diff --git a/public/images/trainer/galactic_grunt_m.png b/public/images/trainer/galactic_grunt_m.png new file mode 100644 index 00000000000..1fff818266c Binary files /dev/null and b/public/images/trainer/galactic_grunt_m.png differ diff --git a/public/images/trainer/lysandre.json b/public/images/trainer/lysandre.json new file mode 100644 index 00000000000..931b1633a32 --- /dev/null +++ b/public/images/trainer/lysandre.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "lysandre.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 14, + "y": 0, + "w": 52, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 52, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:6b887c8bab74885a1b05f2b382759db6:ba102d9d25ddd794a3a17f029b971daf:e6066149f6ec4ccb9fc28faea3d64a7f$" + } +} diff --git a/public/images/trainer/lysandre.png b/public/images/trainer/lysandre.png new file mode 100644 index 00000000000..b83b649d142 Binary files /dev/null and b/public/images/trainer/lysandre.png differ diff --git a/public/images/trainer/magma_grunt_f.json b/public/images/trainer/magma_grunt_f.json new file mode 100644 index 00000000000..05c0512bbf0 --- /dev/null +++ b/public/images/trainer/magma_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "magma_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 10, + "y": 0, + "w": 60, + "h": 80 + }, + "frame": { + "x": 10, + "y": 0, + "w": 60, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f63ad48affc076f60fae78992c96a2bf:80928b32710abcb28c07c6fc5a425d99:3b961d8852b62aaf24ceb2030c036515$" + } +} diff --git a/public/images/trainer/magma_grunt_f.png b/public/images/trainer/magma_grunt_f.png new file mode 100644 index 00000000000..215ad83eea1 Binary files /dev/null and b/public/images/trainer/magma_grunt_f.png differ diff --git a/public/images/trainer/magma_grunt_m.json b/public/images/trainer/magma_grunt_m.json new file mode 100644 index 00000000000..ac8cd838c5a --- /dev/null +++ b/public/images/trainer/magma_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "magma_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 10, + "y": 0, + "w": 60, + "h": 80 + }, + "frame": { + "x": 10, + "y": 0, + "w": 60, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:96aa833d987a01bcdcb6f0e7809f5daf:791cce8d026f92b2e52f0b66df8b8e11:35532fd5d9aea30957d50d06f2d2f9a6$" + } +} diff --git a/public/images/trainer/magma_grunt_m.png b/public/images/trainer/magma_grunt_m.png new file mode 100644 index 00000000000..a37b9acbb52 Binary files /dev/null and b/public/images/trainer/magma_grunt_m.png differ diff --git a/public/images/trainer/maxie.json b/public/images/trainer/maxie.json new file mode 100644 index 00000000000..46914ada760 --- /dev/null +++ b/public/images/trainer/maxie.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "maxie.png", + "format": "RGBA8888", + "size": { + "w": 79, + "h": 79 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 20, + "y": 0, + "w": 35, + "h": 79 + }, + "frame": { + "x": 0, + "y": 0, + "w": 35, + "h": 79 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:a943a18803f18065ae5f19e5089c83bb:33a1c168d314f5fb32f9b34244201178:54a227d24523907b8adf8e907821dcd9$" + } +} diff --git a/public/images/trainer/maxie.png b/public/images/trainer/maxie.png new file mode 100644 index 00000000000..232082f869f Binary files /dev/null and b/public/images/trainer/maxie.png differ diff --git a/public/images/trainer/plasma_grunt_f.json b/public/images/trainer/plasma_grunt_f.json new file mode 100644 index 00000000000..4d23eeeb483 --- /dev/null +++ b/public/images/trainer/plasma_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "plasma_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 75, + "h": 75 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 21, + "y": 4, + "w": 37, + "h": 75 + }, + "frame": { + "x": 0, + "y": 0, + "w": 37, + "h": 75 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:c3001e18f1878c01a4825697200e823e:2003e0d4db249f7020c3471872198ac8:b01645b9e941158814978f2126e7e995$" + } +} diff --git a/public/images/trainer/plasma_grunt_f.png b/public/images/trainer/plasma_grunt_f.png new file mode 100644 index 00000000000..95b065f4360 Binary files /dev/null and b/public/images/trainer/plasma_grunt_f.png differ diff --git a/public/images/trainer/plasma_grunt_m.json b/public/images/trainer/plasma_grunt_m.json new file mode 100644 index 00000000000..7c34b16790f --- /dev/null +++ b/public/images/trainer/plasma_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "plasma_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 72, + "h": 72 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 16, + "y": 7, + "w": 47, + "h": 72 + }, + "frame": { + "x": 0, + "y": 0, + "w": 47, + "h": 72 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:61f195ebbcde93ab7442408edad7fe7a:28ae203b3cb42a94c4ba4420fdebdccc:9ae0ee174d431d48052a2f6b74e9d40c$" + } +} diff --git a/public/images/trainer/plasma_grunt_m.png b/public/images/trainer/plasma_grunt_m.png new file mode 100644 index 00000000000..e3ec6dd8c35 Binary files /dev/null and b/public/images/trainer/plasma_grunt_m.png differ diff --git a/public/images/trainer/rocket_grunt_f.json b/public/images/trainer/rocket_grunt_f.json new file mode 100644 index 00000000000..091fedd31f0 --- /dev/null +++ b/public/images/trainer/rocket_grunt_f.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "rocket_grunt_f.png", + "format": "RGBA8888", + "size": { + "w": 67, + "h": 67 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 18, + "y": 9, + "w": 50, + "h": 67 + }, + "frame": { + "x": 0, + "y": 0, + "w": 50, + "h": 67 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f2e4df704ed3262efeba03b98c4f34b6:856ea7816491331f96e020076871263b:fadb24d665ba1be4d210fe9064954d5b$" + } +} diff --git a/public/images/trainer/rocket_grunt_f.png b/public/images/trainer/rocket_grunt_f.png new file mode 100644 index 00000000000..c4f6e96dec4 Binary files /dev/null and b/public/images/trainer/rocket_grunt_f.png differ diff --git a/public/images/trainer/rocket_grunt_m.json b/public/images/trainer/rocket_grunt_m.json new file mode 100644 index 00000000000..b8417d3b763 --- /dev/null +++ b/public/images/trainer/rocket_grunt_m.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "rocket_grunt_m.png", + "format": "RGBA8888", + "size": { + "w": 65, + "h": 65 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 17, + "y": 9, + "w": 42, + "h": 65 + }, + "frame": { + "x": 0, + "y": 0, + "w": 42, + "h": 65 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/rocket_grunt_m.png b/public/images/trainer/rocket_grunt_m.png new file mode 100644 index 00000000000..027da6cacb0 Binary files /dev/null and b/public/images/trainer/rocket_grunt_m.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index df827f5201c..8b469022e31 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -20,8 +20,8 @@ import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesF import AbilityBar from "./ui/ability-bar"; import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr, applyAbAttrs, applyPostBattleInitAbAttrs } from "./data/ability"; import { allAbilities } from "./data/ability"; -import Battle, { BattleType, FixedBattleConfig, fixedBattles } from "./battle"; -import { GameMode, GameModes, gameModes } from "./game-mode"; +import Battle, { BattleType, FixedBattleConfig } from "./battle"; +import { GameMode, GameModes, getGameMode } from "./game-mode"; import FieldSpritePipeline from "./pipelines/field-sprite"; import SpritePipeline from "./pipelines/sprite"; import PartyExpBar from "./ui/party-exp-bar"; @@ -58,7 +58,7 @@ import * as Overrides from "./overrides"; import {InputsController} from "./inputs-controller"; import {UiInputs} from "./ui-inputs"; import { MoneyFormat } from "./enums/money-format"; -import { NewArenaEvent } from "./battle-scene-events"; +import { NewArenaEvent } from "./events/battle-scene"; import { Abilities } from "./data/enums/abilities"; import ArenaFlyout from "./ui/arena-flyout"; import { EaseType } from "./ui/enums/ease-type"; @@ -126,6 +126,7 @@ export default class BattleScene extends SceneBase { public uiTheme: UiTheme = UiTheme.DEFAULT; public windowType: integer = 0; public experimentalSprites: boolean = false; + public musicPreference: integer = 0; public moveAnimations: boolean = true; public expGainsSpeed: integer = 0; public skipSeenDialogues: boolean = false; @@ -154,12 +155,20 @@ export default class BattleScene extends SceneBase { */ public battleStyle: integer = 0; + /** + * Defines whether or not to show type effectiveness hints + * - true: No hints + * - false: Show hints for moves + */ + public typeHints: boolean = false; + public disableMenu: boolean = false; public gameData: GameData; public sessionSlotId: integer; public phaseQueue: Phase[]; + public conditionalQueue: Array<[() => boolean, Phase]>; private phaseQueuePrepend: Phase[]; private phaseQueuePrependSpliceIndex: integer; private nextCommandPhaseQueue: Phase[]; @@ -226,6 +235,7 @@ export default class BattleScene extends SceneBase { public rngSeedOverride: string = ""; public rngOffset: integer = 0; + public inputMethod: string; private infoToggles: InfoToggle[] = []; /** @@ -243,6 +253,7 @@ export default class BattleScene extends SceneBase { super("battle"); this.phaseQueue = []; this.phaseQueuePrepend = []; + this.conditionalQueue = []; this.phaseQueuePrependSpliceIndex = -1; this.nextCommandPhaseQueue = []; this.updateGameInfo(); @@ -305,7 +316,6 @@ export default class BattleScene extends SceneBase { } update() { - this.inputController.update(); this.ui?.update(); } @@ -852,7 +862,7 @@ export default class BattleScene extends SceneBase { this.gameData = new GameData(this); } - this.gameMode = gameModes[GameModes.CLASSIC]; + this.gameMode = getGameMode(GameModes.CLASSIC); this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24)); console.log("Seed:", this.seed); @@ -960,8 +970,8 @@ export default class BattleScene extends SceneBase { const playerField = this.getPlayerField(); - if (this.gameMode.hasFixedBattles && fixedBattles.hasOwnProperty(newWaveIndex) && trainerData === undefined) { - battleConfig = fixedBattles[newWaveIndex]; + if (this.gameMode.isFixedBattle(newWaveIndex) && trainerData === undefined) { + battleConfig = this.gameMode.getFixedBattle(newWaveIndex); newDouble = battleConfig.double; newBattleType = battleConfig.battleType; this.executeWithSeedOffset(() => newTrainer = battleConfig.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8); @@ -1009,7 +1019,8 @@ export default class BattleScene extends SceneBase { if (Overrides.DOUBLE_BATTLE_OVERRIDE) { newDouble = true; } - if (Overrides.SINGLE_BATTLE_OVERRIDE) { + /* Override battles into single only if not fighting with trainers */ + if (newBattleType !== BattleType.TRAINER && Overrides.SINGLE_BATTLE_OVERRIDE) { newDouble = false; } @@ -1381,8 +1392,7 @@ export default class BattleScene extends SceneBase { if (this.money === undefined) { return; } - const formattedMoney = - this.moneyFormat === MoneyFormat.ABBREVIATED ? Utils.formatFancyLargeNumber(this.money, 3) : this.money.toLocaleString(); + const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); this.moneyText.setText(`₽${formattedMoney}`); this.fieldUI.moveAbove(this.moneyText, this.luckText); if (forceVisible) { @@ -1671,56 +1681,148 @@ export default class BattleScene extends SceneBase { getBgmLoopPoint(bgmName: string): number { switch (bgmName) { - case "battle_kanto_champion": + case "battle_kanto_champion": //B2W2 Kanto Champion Battle return 13.950; - case "battle_johto_champion": + case "battle_johto_champion": //B2W2 Johto Champion Battle return 23.498; - case "battle_hoenn_champion": + case "battle_hoenn_champion": //B2W2 Hoenn Champion Battle return 11.328; - case "battle_sinnoh_champion": + case "battle_sinnoh_champion": //B2W2 Sinnoh Champion Battle return 12.235; - case "battle_champion_alder": + case "battle_champion_alder": //BW Unova Champion Battle return 27.653; - case "battle_champion_iris": + case "battle_champion_iris": //B2W2 Unova Champion Battle return 10.145; - case "battle_elite": + case "battle_kalos_champion": //XY Kalos Champion Battle + return 10.380; + case "battle_alola_champion": //USUM Alola Champion Battle + return 13.025; + case "battle_galar_champion": //SWSH Galar Champion Battle + return 61.635; + case "battle_champion_geeta": //SV Champion Geeta Battle + return 37.447; + case "battle_champion_nemona": //SV Champion Nemona Battle + return 14.914; + case "battle_champion_kieran": //SV Champion Kieran Battle + return 7.206; + case "battle_hoenn_elite": //ORAS Elite Four Battle + return 11.350; + case "battle_unova_elite": //BW Elite Four Battle return 17.730; - case "battle_final_encounter": + case "battle_kalos_elite": //XY Elite Four Battle + return 12.340; + case "battle_alola_elite": //SM Elite Four Battle + return 19.212; + case "battle_galar_elite": //SWSH League Tournament Battle + return 164.069; + case "battle_paldea_elite": //SV Elite Four Battle + return 12.770; + case "battle_bb_elite": //SV BB League Elite Four Battle + return 19.434; + case "battle_final_encounter": //PMD RTDX Rayquaza's Domain return 19.159; - case "battle_final": + case "battle_final": //BW Ghetsis Battle return 16.453; - case "battle_kanto_gym": + case "battle_kanto_gym": //B2W2 Kanto Gym Battle return 13.857; - case "battle_johto_gym": + case "battle_johto_gym": //B2W2 Johto Gym Battle return 12.911; - case "battle_hoenn_gym": + case "battle_hoenn_gym": //B2W2 Hoenn Gym Battle return 12.379; - case "battle_sinnoh_gym": + case "battle_sinnoh_gym": //B2W2 Sinnoh Gym Battle return 13.122; - case "battle_unova_gym": + case "battle_unova_gym": //BW Unova Gym Battle return 19.145; - case "battle_legendary_regis": //B2W2 Legendary Titan Battle + case "battle_kalos_gym": //XY Kalos Gym Battle + return 44.810; + case "battle_galar_gym": //SWSH Galar Gym Battle + return 171.262; + case "battle_paldea_gym": //SV Paldea Gym Battle + return 127.489; + case "battle_legendary_kanto": //XY Kanto Legendary Battle + return 32.966; + case "battle_legendary_raikou": //HGSS Raikou Battle + return 12.632; + case "battle_legendary_entei": //HGSS Entei Battle + return 2.905; + case "battle_legendary_suicune": //HGSS Suicune Battle + return 12.636; + case "battle_legendary_lugia": //HGSS Lugia Battle + return 19.770; + case "battle_legendary_ho_oh": //HGSS Ho-oh Battle + return 17.668; + case "battle_legendary_regis_g5": //B2W2 Legendary Titan Battle return 49.500; + case "battle_legendary_regis_g6": //ORAS Legendary Titan Battle + return 21.130; + case "battle_legendary_gro_kyo": //ORAS Groudon & Kyogre Battle + return 10.547; + case "battle_legendary_rayquaza": //ORAS Rayquaza Battle + return 10.495; + case "battle_legendary_deoxys": //ORAS Deoxys Battle + return 13.333; + case "battle_legendary_lake_trio": //ORAS Lake Guardians Battle + return 16.887; + case "battle_legendary_sinnoh": //ORAS Sinnoh Legendary Battle + return 22.770; + case "battle_legendary_dia_pal": //ORAS Dialga & Palkia Battle + return 16.009; + case "battle_legendary_giratina": //ORAS Giratina Battle + return 10.451; + case "battle_legendary_arceus": //HGSS Arceus Battle + return 9.595; case "battle_legendary_unova": //BW Unova Legendary Battle return 13.855; case "battle_legendary_kyurem": //BW Kyurem Battle return 18.314; case "battle_legendary_res_zek": //BW Reshiram & Zekrom Battle return 18.329; - case "battle_rival": + case "battle_legendary_xern_yvel": //XY Xerneas & Yveltal Battle + return 26.468; + case "battle_legendary_tapu": //SM Tapu Battle + return 0.000; + case "battle_legendary_sol_lun": //SM Solgaleo & Lunala Battle + return 6.525; + case "battle_legendary_ub": //SM Ultra Beast Battle + return 9.818; + case "battle_legendary_dusk_dawn": //USUM Dusk Mane & Dawn Wings Necrozma Battle + return 5.211; + case "battle_legendary_ultra_nec": //USUM Ultra Necrozma Battle + return 10.344; + case "battle_legendary_zac_zam": //SWSH Zacian & Zamazenta Battle + return 11.424; + case "battle_legendary_glas_spec": //SWSH Glastrier & Spectrier Battle + return 12.503; + case "battle_legendary_calyrex": //SWSH Calyrex Battle + return 50.641; + case "battle_legendary_birds_galar": //SWSH Galarian Legendary Birds Battle + return 0.175; + case "battle_legendary_ruinous": //SV Treasures of Ruin Battle + return 6.333; + case "battle_legendary_loyal_three": //SV Loyal Three Battle + return 6.500; + case "battle_legendary_ogerpon": //SV Ogerpon Battle + return 14.335; + case "battle_legendary_terapagos": //SV Terapagos Battle + return 24.377; + case "battle_legendary_pecharunt": //SV Pecharunt Battle + return 6.508; + case "battle_rival": //BW Rival Battle return 13.689; - case "battle_rival_2": + case "battle_rival_2": //BW N Battle return 17.714; - case "battle_rival_3": + case "battle_rival_3": //BW Final N Battle return 17.586; - case "battle_trainer": + case "battle_trainer": //BW Trainer Battle return 13.686; - case "battle_wild": + case "battle_wild": //BW Wild Battle return 12.703; - case "battle_wild_strong": + case "battle_wild_strong": //BW Strong Wild Battle return 13.940; - case "end_summit": + case "end_summit": //PMD RTDX Sky Tower Summit return 30.025; + case "battle_plasma_grunt": //BW Team Plasma Battle + return 12.974; } return 0; @@ -1743,6 +1845,21 @@ export default class BattleScene extends SceneBase { return this.standbyPhase; } + /** + * Adds a phase to the conditional queue and ensures it is executed only when the specified condition is met. + * + * This method allows deferring the execution of a phase until certain conditions are met, which is useful for handling + * situations like abilities and entry hazards that depend on specific game states. + * + * @param {Phase} phase - The phase to be added to the conditional queue. + * @param {() => boolean} condition - A function that returns a boolean indicating whether the phase should be executed. + * + */ + pushConditionalPhase(phase: Phase, condition: () => boolean): void { + this.conditionalQueue.push([condition, phase]); + } + + pushPhase(phase: Phase, defer: boolean = false): void { (!defer ? this.phaseQueue : this.nextCommandPhaseQueue).push(phase); } @@ -1786,6 +1903,21 @@ export default class BattleScene extends SceneBase { this.populatePhaseQueue(); } this.currentPhase = this.phaseQueue.shift(); + + // Check if there are any conditional phases queued + if (this.conditionalQueue?.length) { + // Retrieve the first conditional phase from the queue + const conditionalPhase = this.conditionalQueue.shift(); + // Evaluate the condition associated with the phase + if (conditionalPhase[0]()) { + // If the condition is met, add the phase to the front of the phase queue + this.unshiftPhase(conditionalPhase[1]); + } else { + // If the condition is not met, re-add the phase back to the front of the conditional queue + this.conditionalQueue.unshift(conditionalPhase); + } + } + this.currentPhase.start(); } diff --git a/src/battle.ts b/src/battle.ts index c857a8766ed..68e16cb28bb 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -197,7 +197,11 @@ export default class Battle { if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length) { return `encounter_${this.trainer.getEncounterBgm()}`; } - return this.trainer.getBattleBgm(); + if (scene.musicPreference === 0) { + return this.trainer.getBattleBgm(); + } else { + return this.trainer.getMixedBattleBgm(); + } } else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) { return "end_summit"; } @@ -209,22 +213,116 @@ export default class Battle { return "battle_final_encounter"; } if (pokemon.species.legendary || pokemon.species.subLegendary || pokemon.species.mythical) { - if (pokemon.species.speciesId === Species.REGIROCK || pokemon.species.speciesId === Species.REGICE || pokemon.species.speciesId === Species.REGISTEEL || pokemon.species.speciesId === Species.REGIGIGAS || pokemon.species.speciesId === Species.REGIELEKI || pokemon.species.speciesId === Species.REGIDRAGO) { - return "battle_legendary_regis"; - } - if (pokemon.species.speciesId === Species.COBALION || pokemon.species.speciesId === Species.TERRAKION || pokemon.species.speciesId === Species.VIRIZION || pokemon.species.speciesId === Species.TORNADUS || pokemon.species.speciesId === Species.THUNDURUS || pokemon.species.speciesId === Species.LANDORUS || pokemon.species.speciesId === Species.KELDEO || pokemon.species.speciesId === Species.MELOETTA || pokemon.species.speciesId === Species.GENESECT) { + if (scene.musicPreference === 0) { + if (pokemon.species.speciesId === Species.REGIROCK || pokemon.species.speciesId === Species.REGICE || pokemon.species.speciesId === Species.REGISTEEL || pokemon.species.speciesId === Species.REGIGIGAS || pokemon.species.speciesId === Species.REGIELEKI || pokemon.species.speciesId === Species.REGIDRAGO) { + return "battle_legendary_regis_g5"; + } + if (pokemon.species.speciesId === Species.COBALION || pokemon.species.speciesId === Species.TERRAKION || pokemon.species.speciesId === Species.VIRIZION || pokemon.species.speciesId === Species.TORNADUS || pokemon.species.speciesId === Species.THUNDURUS || pokemon.species.speciesId === Species.LANDORUS || pokemon.species.speciesId === Species.KELDEO || pokemon.species.speciesId === Species.MELOETTA || pokemon.species.speciesId === Species.GENESECT) { + return "battle_legendary_unova"; + } + if (pokemon.species.speciesId === Species.KYUREM) { + return "battle_legendary_kyurem"; + } + if (pokemon.species.legendary) { + return "battle_legendary_res_zek"; + } + return "battle_legendary_unova"; + } else { + if (pokemon.species.speciesId === Species.ARTICUNO || pokemon.species.speciesId === Species.ZAPDOS || pokemon.species.speciesId === Species.MOLTRES || pokemon.species.speciesId === Species.MEWTWO || pokemon.species.speciesId === Species.MEW) { + return "battle_legendary_kanto"; + } + if (pokemon.species.speciesId === Species.RAIKOU) { + return "battle_legendary_raikou"; + } + if (pokemon.species.speciesId === Species.ENTEI) { + return "battle_legendary_entei"; + } + if (pokemon.species.speciesId === Species.SUICUNE) { + return "battle_legendary_suicune"; + } + if (pokemon.species.speciesId === Species.LUGIA) { + return "battle_legendary_lugia"; + } + if (pokemon.species.speciesId === Species.HO_OH) { + return "battle_legendary_ho_oh"; + } + if (pokemon.species.speciesId === Species.REGIROCK || pokemon.species.speciesId === Species.REGICE || pokemon.species.speciesId === Species.REGISTEEL || pokemon.species.speciesId === Species.REGIGIGAS || pokemon.species.speciesId === Species.REGIELEKI || pokemon.species.speciesId === Species.REGIDRAGO) { + return "battle_legendary_regis_g6"; + } + if (pokemon.species.speciesId === Species.GROUDON || pokemon.species.speciesId === Species.KYOGRE) { + return "battle_legendary_gro_kyo"; + } + if (pokemon.species.speciesId === Species.RAYQUAZA) { + return "battle_legendary_rayquaza"; + } + if (pokemon.species.speciesId === Species.DEOXYS) { + return "battle_legendary_deoxys"; + } + if (pokemon.species.speciesId === Species.UXIE || pokemon.species.speciesId === Species.MESPRIT || pokemon.species.speciesId === Species.AZELF) { + return "battle_legendary_lake_trio"; + } + if (pokemon.species.speciesId === Species.HEATRAN || pokemon.species.speciesId === Species.CRESSELIA || pokemon.species.speciesId === Species.DARKRAI || pokemon.species.speciesId === Species.SHAYMIN) { + return "battle_legendary_sinnoh"; + } + if (pokemon.species.speciesId === Species.DIALGA || pokemon.species.speciesId === Species.PALKIA) { + return "battle_legendary_dia_pal"; + } + if (pokemon.species.speciesId === Species.GIRATINA) { + return "battle_legendary_giratina"; + } + if (pokemon.species.speciesId === Species.ARCEUS) { + return "battle_legendary_arceus"; + } + if (pokemon.species.speciesId === Species.COBALION || pokemon.species.speciesId === Species.TERRAKION || pokemon.species.speciesId === Species.VIRIZION || pokemon.species.speciesId === Species.TORNADUS || pokemon.species.speciesId === Species.THUNDURUS || pokemon.species.speciesId === Species.LANDORUS || pokemon.species.speciesId === Species.KELDEO || pokemon.species.speciesId === Species.MELOETTA || pokemon.species.speciesId === Species.GENESECT) { + return "battle_legendary_unova"; + } + if (pokemon.species.speciesId === Species.KYUREM) { + return "battle_legendary_kyurem"; + } + if (pokemon.species.speciesId === Species.XERNEAS || pokemon.species.speciesId === Species.YVELTAL || pokemon.species.speciesId === Species.ZYGARDE) { + return "battle_legendary_xern_yvel"; + } + if (pokemon.species.speciesId === Species.TAPU_KOKO || pokemon.species.speciesId === Species.TAPU_LELE || pokemon.species.speciesId === Species.TAPU_BULU || pokemon.species.speciesId === Species.TAPU_FINI) { + return "battle_legendary_tapu"; + } + if (pokemon.species.speciesId === Species.COSMOG || pokemon.species.speciesId === Species.COSMOEM || pokemon.species.speciesId === Species.SOLGALEO || pokemon.species.speciesId === Species.LUNALA || pokemon.species.speciesId === Species.NECROZMA) { + return "battle_legendary_sol_lun"; + } + if (pokemon.species.speciesId === Species.NIHILEGO || pokemon.species.speciesId === Species.BUZZWOLE || pokemon.species.speciesId === Species.PHEROMOSA || pokemon.species.speciesId === Species.XURKITREE || pokemon.species.speciesId === Species.CELESTEELA || pokemon.species.speciesId === Species.KARTANA || pokemon.species.speciesId === Species.GUZZLORD || pokemon.species.speciesId === Species.POIPOLE || pokemon.species.speciesId === Species.NAGANADEL || pokemon.species.speciesId === Species.STAKATAKA || pokemon.species.speciesId === Species.BLACEPHALON) { + return "battle_legendary_ub"; + } + if (pokemon.species.speciesId === Species.ZACIAN || pokemon.species.speciesId === Species.ZAMAZENTA) { + return "battle_legendary_zac_zam"; + } + if (pokemon.species.speciesId === Species.GLASTRIER || pokemon.species.speciesId === Species.SPECTRIER) { + return "battle_legendary_glas_spec"; + } + if (pokemon.species.speciesId === Species.CALYREX) { + return "battle_legendary_calyrex"; + } + if (pokemon.species.speciesId === Species.GALAR_ARTICUNO || pokemon.species.speciesId === Species.GALAR_ZAPDOS || pokemon.species.speciesId === Species.GALAR_MOLTRES) { + return "battle_legendary_birds_galar"; + } + if (pokemon.species.speciesId === Species.WO_CHIEN || pokemon.species.speciesId === Species.CHIEN_PAO || pokemon.species.speciesId === Species.TING_LU || pokemon.species.speciesId === Species.CHI_YU) { + return "battle_legendary_ruinous"; + } + if (pokemon.species.speciesId === Species.OKIDOGI || pokemon.species.speciesId === Species.MUNKIDORI || pokemon.species.speciesId === Species.FEZANDIPITI) { + return "battle_legendary_loyal_three"; + } + if (pokemon.species.speciesId === Species.OGERPON) { + return "battle_legendary_ogerpon"; + } + if (pokemon.species.speciesId === Species.TERAPAGOS) { + return "battle_legendary_terapagos"; + } + if (pokemon.species.speciesId === Species.PECHARUNT) { + return "battle_legendary_pecharunt"; + } + if (pokemon.species.legendary) { + return "battle_legendary_res_zek"; + } return "battle_legendary_unova"; } - if (pokemon.species.speciesId === Species.RESHIRAM || pokemon.species.speciesId === Species.ZEKROM) { - return "battle_legendary_res_zek"; - } - if (pokemon.species.speciesId === Species.KYUREM) { - return "battle_legendary_kyurem"; - } - if (pokemon.species.legendary) { - return "battle_legendary_res_zek"; - } - return "battle_legendary_unova"; } } @@ -322,31 +420,54 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[]): Get }; } -interface FixedBattleConfigs { +export interface FixedBattleConfigs { [key: integer]: FixedBattleConfig } - -export const fixedBattles: FixedBattleConfigs = { +/** + * Youngster/Lass on 5 + * Rival on 8, 55, 95, 145, 195 + * Evil team grunts on 35, 62, 64, 65, 112, 114 (Not currently spawning) + * Evil leader on 115, 165 (Not currently spawning) + * E4 on 182, 184, 186, 188 + * Champion on 190 + */ +export const classicFixedBattles: FixedBattleConfigs = { [5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), [8]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), [25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), + // [35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), [55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), + // [62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), + // [64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), + // [65]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), [95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), + // [112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), + // [114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ])), + // [115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])), [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), + // [165]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) + // .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2 ])), [182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ],TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])), + .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])), [184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY, TrainerType.AMARYS ])), [186]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) - .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, [TrainerType.BEA_ELITE,TrainerType.ALLISTER_ELITE], TrainerType.LARRY_ELITE, TrainerType.LACEY ])), + .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, [ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ], TrainerType.LARRY_ELITE, TrainerType.LACEY ])), [188]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) - .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI,TrainerType.RAIHAN_ELITE, TrainerType.HASSEL, TrainerType.DRAYTON ])), + .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL, TrainerType.DRAYTON ])), [190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])), [195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) diff --git a/src/data/ability.ts b/src/data/ability.ts index ebaf1f47504..5db2e34b2a0 100755 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -12,7 +12,7 @@ import { Gender } from "./gender"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType } from "./enums/arena-tag-type"; -import { Stat } from "./pokemon-stat"; +import { Stat, getStatName } from "./pokemon-stat"; import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { Moves } from "./enums/moves"; import { TerrainType } from "./terrain"; @@ -1032,6 +1032,52 @@ export class FieldPreventExplosiveMovesAbAttr extends AbAttr { } } +/** + * Multiplies a BattleStat if the checked Pokemon lacks this ability. + * If this ability cannot stack, a BooleanHolder can be used to prevent this from stacking. + * @see {@link applyFieldBattleStatMultiplierAbAttrs} + * @see {@link applyFieldBattleStat} + * @see {@link Utils.BooleanHolder} + */ +export class FieldMultiplyBattleStatAbAttr extends AbAttr { + private stat: Stat; + private multiplier: number; + private canStack: boolean; + + constructor(stat: Stat, multiplier: number, canStack: boolean = false) { + super(false); + + this.stat = stat; + this.multiplier = multiplier; + this.canStack = canStack; + } + + /** + * applyFieldBattleStat: Tries to multiply a Pokemon's BattleStat + * @param pokemon {@linkcode Pokemon} the Pokemon using this ability + * @param passive {@linkcode boolean} unused + * @param stat {@linkcode Stat} the type of the checked stat + * @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat + * @param checkedPokemon {@linkcode Pokemon} the Pokemon this ability is targeting + * @param hasApplied {@linkcode Utils.BooleanHolder} whether or not another multiplier has been applied to this stat + * @param args {any[]} unused + * @returns true if this changed the checked stat, false otherwise. + */ + applyFieldBattleStat(pokemon: Pokemon, passive: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): boolean { + if (!this.canStack && hasApplied.value) { + return false; + } + + if (this.stat === stat && checkedPokemon.getAbilityAttrs(FieldMultiplyBattleStatAbAttr).every(attr => (attr as FieldMultiplyBattleStatAbAttr).stat !== stat)) { + statValue.value *= this.multiplier; + hasApplied.value = true; + return true; + } + return false; + } + +} + export class MoveTypeChangeAttr extends PreAttackAbAttr { private newType: Type; private powerMultiplier: number; @@ -1579,7 +1625,9 @@ export class PostSummonStatChangeAbAttr extends PostSummonAbAttr { applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { queueShowAbility(pokemon, passive); // TODO: Better solution than manually showing the ability here if (this.selfTarget) { - pokemon.scene.pushPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + // we unshift the StatChangePhase to put it right after the showAbility and not at the end of the + // phase list (which could be after CommandPhase for example) + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); return true; } for (const opponent of pokemon.getOpponents()) { @@ -2949,6 +2997,7 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { /** * Checks if enemy Pokemon is trapped by an Arena Trap-esque ability * If the enemy is a Ghost type, it is not trapped + * If the enemy has the ability Run Away, it is not trapped. * If the user has Magnet Pull and the enemy is not a Steel type, it is not trapped. * If the user has Arena Trap and the enemy is not grounded, it is not trapped. * @param pokemon The {@link Pokemon} with this {@link AbAttr} @@ -2963,6 +3012,9 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { if (otherPokemon.getTypes(true).includes(Type.GHOST) || (otherPokemon.getTypes(true).includes(Type.STELLAR) && otherPokemon.getTypes().includes(Type.GHOST))) { trapped.value = false; return false; + } else if (otherPokemon.hasAbility(Abilities.RUN_AWAY)) { + trapped.value = false; + return false; } trapped.value = true; return true; @@ -3569,6 +3621,21 @@ export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]) return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args); } +/** + * Applies a field Battle Stat multiplier attribute + * @param attrType {@linkcode FieldMultiplyBattleStatAbAttr} should always be FieldMultiplyBattleStatAbAttr for the time being + * @param pokemon {@linkcode Pokemon} the Pokemon applying this ability + * @param stat {@linkcode Stat} the type of the checked stat + * @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat + * @param checkedPokemon {@linkcode Pokemon} the Pokemon with the checked stat + * @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 }, + 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 }, pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args); @@ -4039,8 +4106,7 @@ export function initAbilities() { .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr) - .attr(NoFusionAbilityAbAttr) - .unimplemented(), + .attr(NoFusionAbilityAbAttr), new Ability(Abilities.FLOWER_GIFT, 4) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), BattleStatMultiplierAbAttr, BattleStat.SPDEF, 1.5) @@ -4392,8 +4458,7 @@ export function initAbilities() { .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr) - .attr(NoFusionAbilityAbAttr) - .unimplemented(), + .attr(NoFusionAbilityAbAttr), new Ability(Abilities.ELECTRIC_SURGE, 7) .attr(PostSummonTerrainChangeAbAttr, TerrainType.ELECTRIC) .attr(PostBiomeChangeTerrainChangeAbAttr, TerrainType.ELECTRIC), @@ -4594,17 +4659,21 @@ export function initAbilities() { .ignorable() .partial(), new Ability(Abilities.VESSEL_OF_RUIN, 9) - .ignorable() - .unimplemented(), + .attr(FieldMultiplyBattleStatAbAttr, Stat.SPATK, 0.75) + .attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Vessel of Ruin lowered the ${getStatName(Stat.SPATK)}\nof all surrounding Pokémon!`)) + .ignorable(), new Ability(Abilities.SWORD_OF_RUIN, 9) - .ignorable() - .unimplemented(), + .attr(FieldMultiplyBattleStatAbAttr, Stat.DEF, 0.75) + .attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Sword of Ruin lowered the ${getStatName(Stat.DEF)}\nof all surrounding Pokémon!`)) + .ignorable(), new Ability(Abilities.TABLETS_OF_RUIN, 9) - .ignorable() - .unimplemented(), + .attr(FieldMultiplyBattleStatAbAttr, Stat.ATK, 0.75) + .attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Tablets of Ruin lowered the ${getStatName(Stat.ATK)}\nof all surrounding Pokémon!`)) + .ignorable(), new Ability(Abilities.BEADS_OF_RUIN, 9) - .ignorable() - .unimplemented(), + .attr(FieldMultiplyBattleStatAbAttr, Stat.SPDEF, 0.75) + .attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Beads of Ruin lowered the ${getStatName(Stat.SPDEF)}\nof all surrounding Pokémon!`)) + .ignorable(), new Ability(Abilities.ORICHALCUM_PULSE, 9) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SUNNY) .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SUNNY) diff --git a/src/data/challenge.ts b/src/data/challenge.ts new file mode 100644 index 00000000000..916f59ab2c2 --- /dev/null +++ b/src/data/challenge.ts @@ -0,0 +1,577 @@ +import * as Utils from "../utils"; +import { Challenges } from "./enums/challenges"; +import i18next from "#app/plugins/i18n.js"; +import { GameData } from "#app/system/game-data.js"; +import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species"; +import Pokemon from "#app/field/pokemon.js"; +import { BattleType, FixedBattleConfig } from "#app/battle.js"; +import { TrainerType } from "./enums/trainer-type"; +import Trainer, { TrainerVariant } from "#app/field/trainer.js"; +import { GameMode } from "#app/game-mode.js"; +import { Species } from "./enums/species"; +import { Type } from "./type"; + +/** + * An enum for all the challenge types. The parameter entries on these describe the + * parameters to use when calling the applyChallenges function. + */ +export enum ChallengeType { + /** + * Challenges which modify what starters you can choose + * @param args [0] {@link PokemonSpecies} The species to check + * [1] {@link Utils.BooleanHolder} Sets to false if illegal, pass in true. + */ + STARTER_CHOICE, + /** + * Challenges which modify how many starter points you have + * @param args [0] {@link Utils.NumberHolder} The amount of starter points you have + */ + STARTER_POINTS, + /** + * Challenges which modify your starters in some way + * Not Fully Implemented + */ + STARTER_MODIFY, + /** + * Challenges which limit which pokemon you can have in battle. + * @param args [0] {@link Pokemon} The pokemon to check + * [1] {@link Utils.BooleanHolder} Sets to false if illegal, pass in true. + */ + POKEMON_IN_BATTLE, + /** + * Adds or modifies the fixed battles in a run + * @param args [0] integer The wave to get a battle for + * [1] {@link FixedBattleConfig} A new fixed battle. It'll be modified if a battle exists. + */ + FIXED_BATTLES, +} + +/** + * A challenge object. Exists only to serve as a base class. + */ +export abstract class Challenge { + public id: Challenges; // The id of the challenge + + public value: integer; // The "strength" of the challenge, all challenges have a numerical value. + public maxValue: integer; // The maximum strength of the challenge. + public severity: integer; // The current severity of the challenge. Some challenges have multiple severities in addition to strength. + public maxSeverity: integer; // The maximum severity of the challenge. + + public conditions: ChallengeCondition[]; + public challengeTypes: ChallengeType[]; + + /** + * @param {Challenges} id The enum value for the challenge + */ + constructor(id: Challenges, maxValue: integer = Number.MAX_SAFE_INTEGER) { + this.id = id; + + this.value = 0; + this.maxValue = maxValue; + this.severity = 0; + this.maxSeverity = 0; + this.conditions = []; + this.challengeTypes = []; + } + + /** + * Reset the challenge to a base state. + */ + reset(): void { + this.value = 0; + this.severity = 0; + } + + /** + * Gets the localisation key for the challenge + * @returns The i18n key for this challenge + */ + geti18nKey(): string { + return Challenges[this.id].split("_").map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join(""); + } + + /** + * Used for unlockable challenges to check if they're unlocked. + * @param {GameData} data The save data. + * @returns {boolean} Whether this challenge is unlocked. + */ + isUnlocked(data: GameData): boolean { + return this.conditions.every(f => f(data)); + } + + /** + * Adds an unlock condition to this challenge. + * @param {ChallengeCondition} condition The condition to add. + * @returns {Challenge} This challenge + */ + condition(condition: ChallengeCondition): Challenge { + this.conditions.push(condition); + + return this; + } + + /** + * If this challenge is of a particular type + * @param {ChallengeType} challengeType The challenge type to check. + * @returns {Challenge} This challenge + */ + isOfType(challengeType: ChallengeType): boolean { + return this.challengeTypes.some(c => c === challengeType); + } + + /** + * Adds a challenge type to this challenge. + * @param {ChallengeType} challengeType The challenge type to add. + * @returns {Challenge} This challenge + */ + addChallengeType(challengeType: ChallengeType): Challenge { + this.challengeTypes.push(challengeType); + + return this; + } + + /** + * @returns {string} The localised name of this challenge. + */ + getName(): string { + return i18next.t(`challenges:${this.geti18nKey()}.name`); + } + + /** + * 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 i18next.t(`challenges:${this.geti18nKey()}.value.${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; + } + return i18next.t(`challenges:${this.geti18nKey()}.desc.${this.value}`); + } + + /** + * Increase the value of the challenge + * @returns {boolean} Returns true if the value changed + */ + increaseValue(): boolean { + if (this.value < this.maxValue) { + this.value = Math.min(this.value + 1, this.maxValue); + return true; + } + return false; + } + + /** + * Decrease the value of the challenge + * @returns {boolean} Returns true if the value changed + */ + decreaseValue(): boolean { + if (this.value > 0) { + this.value = Math.max(this.value - 1, 0); + return true; + } + return false; + } + + /** + * Whether to allow choosing this challenge's severity. + */ + hasSeverity(): boolean { + return this.value !== 0 && this.maxSeverity > 0; + } + + /** + * Decrease the severity of the challenge + * @returns {boolean} Returns true if the value changed + */ + decreaseSeverity(): boolean { + if (this.severity > 0) { + this.severity = Math.max(this.severity - 1, 0); + return true; + } + return false; + } + + /** + * Increase the severity of the challenge + * @returns {boolean} Returns true if the value changed + */ + increaseSeverity(): boolean { + if (this.severity < this.maxSeverity) { + this.severity = Math.min(this.severity + 1, this.maxSeverity); + return true; + } + return false; + } + + /** + * Gets the "difficulty" value of this challenge. + * @returns {integer} The difficulty value. + */ + getDifficulty(): integer { + return this.value; + } + + /** + * Gets the minimum difficulty added by this challenge. + * @returns {integer} The difficulty value. + */ + getMinDifficulty(): integer { + return 0; + } + + /** + * Modifies the data or game state in some way to apply the challenge. + * @param {ChallengeType} challengeType Which challenge type this is being applied for. + * @param args Irrelevant. See the specific challenge's apply function for additional information. + */ + abstract apply(challengeType: ChallengeType, args: any[]): boolean; + + /** + * Clones a challenge, either from another challenge or json. Chainable. + * @param {Challenge | any} source The source challenge of json. + * @returns {Challenge} This challenge. + */ + static loadChallenge(source: Challenge | any): Challenge { + throw new Error("Method not implemented! Use derived class"); + } +} + +type ChallengeCondition = (data: GameData) => boolean; + +/** + * Implements a mono generation challenge. + */ +export class SingleGenerationChallenge extends Challenge { + constructor() { + super(Challenges.SINGLE_GENERATION, 9); + this.addChallengeType(ChallengeType.STARTER_CHOICE); + this.addChallengeType(ChallengeType.POKEMON_IN_BATTLE); + this.addChallengeType(ChallengeType.FIXED_BATTLES); + } + + apply(challengeType: ChallengeType, args: any[]): boolean { + if (this.value === 0) { + return false; + } + + /** + * We have special code below for victini because it is classed as a generation 4 pokemon in the code + * despite being a generation 5 pokemon. This is due to UI constraints, the starter select screen has + * no more room for pokemon so victini is put in the gen 4 section instead. This code just overrides the + * normal generation check to correctly treat victini as gen 5. + */ + switch (challengeType) { + case ChallengeType.STARTER_CHOICE: + const species = args[0] as PokemonSpecies; + const isValidStarter = args[1] as Utils.BooleanHolder; + const starterGeneration = species.speciesId === Species.VICTINI ? 5 : species.generation; + if (starterGeneration !== this.value) { + isValidStarter.value = false; + return true; + } + break; + case ChallengeType.POKEMON_IN_BATTLE: + const pokemon = args[0] as Pokemon; + const isValidPokemon = args[1] as Utils.BooleanHolder; + const baseGeneration = pokemon.species.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.species.speciesId).generation; + const fusionGeneration = pokemon.isFusion() ? pokemon.fusionSpecies.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.fusionSpecies.speciesId).generation : 0; + if (pokemon.isPlayer() && (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))) { + isValidPokemon.value = false; + return true; + } + break; + case ChallengeType.FIXED_BATTLES: + const waveIndex = args[0] as integer; + const battleConfig = args[1] as FixedBattleConfig; + let trainerTypes: TrainerType[] = []; + switch (waveIndex) { + case 182: + trainerTypes = [ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, Utils.randSeedItem([ TrainerType.HALA, TrainerType.MOLAYNE ]),TrainerType.MARNIE_ELITE, TrainerType.RIKA ]; + break; + case 184: + trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ]; + break; + case 186: + trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([TrainerType.BEA_ELITE,TrainerType.ALLISTER_ELITE]), TrainerType.LARRY_ELITE ]; + break; + case 188: + trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ]; + break; + case 190: + trainerTypes = [ TrainerType.BLUE, Utils.randSeedItem([ TrainerType.RED, TrainerType.LANCE_CHAMPION ]), Utils.randSeedItem([ TrainerType.STEVEN, TrainerType.WALLACE ]), TrainerType.CYNTHIA, Utils.randSeedItem([ TrainerType.ALDER, TrainerType.IRIS ]), TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, Utils.randSeedItem([ TrainerType.GEETA, TrainerType.NEMONA ]) ]; + break; + } + if (trainerTypes.length === 0) { + return false; + } else { + battleConfig.setBattleType(BattleType.TRAINER).setGetTrainerFunc(scene => new Trainer(scene, trainerTypes[this.value - 1], TrainerVariant.DEFAULT)); + return true; + } + } + return false; + } + + /** + * @overrides + */ + getDifficulty(): number { + return this.value > 0 ? 1 : 0; + } + + static loadChallenge(source: SingleGenerationChallenge | any): SingleGenerationChallenge { + const newChallenge = new SingleGenerationChallenge(); + newChallenge.value = source.value; + newChallenge.severity = source.severity; + return newChallenge; + } +} + +interface monotypeOverride { + /** The species to override */ + species: Species; + /** The type to count as */ + type: Type; + /** If part of a fusion, should we check the fused species instead of the base species? */ + fusion: boolean; +} + +/** + * Implements a mono type challenge. + */ +export class SingleTypeChallenge extends Challenge { + private static TYPE_OVERRIDES: monotypeOverride[] = [ + {species: Species.MELOETTA, type: Type.PSYCHIC, fusion: true}, + {species: Species.CASTFORM, type: Type.NORMAL, fusion: false}, + ]; + + constructor() { + super(Challenges.SINGLE_TYPE, 18); + this.addChallengeType(ChallengeType.STARTER_CHOICE); + this.addChallengeType(ChallengeType.POKEMON_IN_BATTLE); + } + + apply(challengeType: ChallengeType, args: any[]): boolean { + if (this.value === 0) { + return false; + } + + switch (challengeType) { + case ChallengeType.STARTER_CHOICE: + const species = args[0] as PokemonSpecies; + const isValidStarter = args[1] as Utils.BooleanHolder; + if (!species.isOfType(this.value - 1)) { + isValidStarter.value = false; + return true; + } + break; + case ChallengeType.POKEMON_IN_BATTLE: + const pokemon = args[0] as Pokemon; + const isValidPokemon = args[1] as Utils.BooleanHolder; + if (pokemon.isPlayer() && !pokemon.isOfType(this.value - 1, false, false, true) + && !SingleTypeChallenge.TYPE_OVERRIDES.some(o => o.type === (this.value - 1) && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies : pokemon.species).speciesId === o.species)) { + isValidPokemon.value = false; + return true; + } + break; + } + return false; + } + + /** + * @overrides + */ + getDifficulty(): number { + return this.value > 0 ? 1 : 0; + } + + static loadChallenge(source: SingleTypeChallenge | any): SingleTypeChallenge { + const newChallenge = new SingleTypeChallenge(); + newChallenge.value = source.value; + newChallenge.severity = source.severity; + return newChallenge; + } +} + +/** + * Implements a fresh start challenge. + */ +export class FreshStartChallenge extends Challenge { + constructor() { + super(Challenges.FRESH_START, 1); + this.addChallengeType(ChallengeType.STARTER_CHOICE); + this.addChallengeType(ChallengeType.STARTER_MODIFY); + } + + apply(challengeType: ChallengeType, args: any[]): boolean { + if (this.value === 0) { + return false; + } + + switch (challengeType) { + case ChallengeType.STARTER_CHOICE: + const species = args[0] as PokemonSpecies; + const isValidStarter = args[1] as Utils.BooleanHolder; + if (species) { + isValidStarter.value = false; + return true; + } + break; + } + return false; + } + + /** + * @overrides + */ + getDifficulty(): number { + return 0; + } + + static loadChallenge(source: FreshStartChallenge | any): FreshStartChallenge { + const newChallenge = new FreshStartChallenge(); + newChallenge.value = source.value; + newChallenge.severity = source.severity; + return newChallenge; + } +} + +/** + * Lowers the amount of starter points available. + */ +export class LowerStarterMaxCostChallenge extends Challenge { + constructor() { + super(Challenges.LOWER_MAX_STARTER_COST, 9); + this.addChallengeType(ChallengeType.STARTER_CHOICE); + } + + /** + * @override + */ + getValue(overrideValue?: integer): string { + if (overrideValue === undefined) { + overrideValue = this.value; + } + return (10 - overrideValue).toString(); + } + + apply(challengeType: ChallengeType, args: any[]): boolean { + if (this.value === 0) { + return false; + } + + switch (challengeType) { + case ChallengeType.STARTER_CHOICE: + const species = args[0] as PokemonSpecies; + const isValid = args[1] as Utils.BooleanHolder; + if (speciesStarters[species.speciesId] > 10 - this.value) { + isValid.value = false; + return true; + } + } + return false; + } + + static loadChallenge(source: LowerStarterMaxCostChallenge | any): LowerStarterMaxCostChallenge { + const newChallenge = new LowerStarterMaxCostChallenge(); + newChallenge.value = source.value; + newChallenge.severity = source.severity; + return newChallenge; + } +} + +/** + * Lowers the maximum cost of starters available. + */ +export class LowerStarterPointsChallenge extends Challenge { + constructor() { + super(Challenges.LOWER_STARTER_POINTS, 9); + this.addChallengeType(ChallengeType.STARTER_POINTS); + } + + /** + * @override + */ + getValue(overrideValue?: integer): string { + if (overrideValue === undefined) { + overrideValue = this.value; + } + return (10 - overrideValue).toString(); + } + + apply(challengeType: ChallengeType, args: any[]): boolean { + if (this.value === 0) { + return false; + } + + switch (challengeType) { + case ChallengeType.STARTER_POINTS: + const points = args[0] as Utils.NumberHolder; + points.value -= this.value; + return true; + } + return false; + } + + static loadChallenge(source: LowerStarterPointsChallenge | any): LowerStarterPointsChallenge { + const newChallenge = new LowerStarterPointsChallenge(); + newChallenge.value = source.value; + newChallenge.severity = source.severity; + return newChallenge; + } +} + +/** + * Apply all challenges of a given challenge type. + * @param {BattleScene} scene The current scene + * @param {ChallengeType} challengeType What challenge type to apply + * @param {any[]} args Any args for that challenge type + * @returns {boolean} True if any challenge was successfully applied. + */ +export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType, ...args: any[]): boolean { + let ret = false; + gameMode.challenges.forEach(v => { + if (v.isOfType(challengeType)) { + ret ||= v.apply(challengeType, args); + } + }); + return ret; +} + +export function copyChallenge(source: Challenge | any): Challenge { + switch (source.id) { + case Challenges.SINGLE_GENERATION: + return SingleGenerationChallenge.loadChallenge(source); + case Challenges.SINGLE_TYPE: + return SingleTypeChallenge.loadChallenge(source); + case Challenges.LOWER_MAX_STARTER_COST: + return LowerStarterMaxCostChallenge.loadChallenge(source); + case Challenges.LOWER_STARTER_POINTS: + return LowerStarterPointsChallenge.loadChallenge(source); + } + throw new Error("Unknown challenge copied"); +} + +export const allChallenges: Challenge[] = []; + +export function initChallenges() { + allChallenges.push( + new SingleGenerationChallenge(), + new SingleTypeChallenge(), + // new LowerStarterMaxCostChallenge(), + // new LowerStarterPointsChallenge(), + // new FreshStartChallenge() + ); +} diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts index cb4bfddc685..c9b097bfcc0 100644 --- a/src/data/daily-run.ts +++ b/src/data/daily-run.ts @@ -1,6 +1,5 @@ import BattleScene from "../battle-scene"; import { PlayerPokemon } from "../field/pokemon"; -import { GameModes, gameModes } from "../game-mode"; import { Starter } from "../ui/starter-select-ui-handler"; import * as Utils from "../utils"; import { Species } from "./enums/species"; @@ -29,7 +28,7 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[] const starters: Starter[] = []; scene.executeWithSeedOffset(() => { - const startingLevel = gameModes[GameModes.DAILY].getStartingLevel(); + const startingLevel = scene.gameMode.getStartingLevel(); if (/\d{18}$/.test(seed)) { for (let s = 0; s < 3; s++) { diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index 2076123610f..5b5e0d865ba 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -449,6 +449,222 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], + [TrainerType.ROCKET_GRUNT]: [ + { + encounter: [ + "dialogue:rocket_grunt.encounter.1" + ], + victory: [ + "dialogue:rocket_grunt.victory.1" + ] + } + ], + [TrainerType.MAGMA_GRUNT]: [ + { + encounter: [ + "dialogue:magma_grunt.encounter.1" + ], + victory: [ + "dialogue:magma_grunt.victory.1" + ] + } + ], + [TrainerType.AQUA_GRUNT]: [ + { + encounter: [ + "dialogue:aqua_grunt.encounter.1" + ], + victory: [ + "dialogue:aqua_grunt.victory.1" + ] + } + ], + [TrainerType.GALACTIC_GRUNT]: [ + { + encounter: [ + "dialogue:galactic_grunt.encounter.1" + ], + victory: [ + "dialogue:galactic_grunt.victory.1" + ] + } + ], + [TrainerType.PLASMA_GRUNT]: [ + { + encounter: [ + "dialogue:plasma_grunt.encounter.1" + ], + victory: [ + "dialogue:plasma_grunt.victory.1" + ] + } + ], + [TrainerType.FLARE_GRUNT]: [ + { + encounter: [ + "dialogue:flare_grunt.encounter.1" + ], + victory: [ + "dialogue:flare_grunt.victory.1" + ] + } + ], + [TrainerType.ROCKET_BOSS_GIOVANNI_1]: [ + { + encounter: [ + "dialogue:rocket_boss_giovanni_1.encounter.1" + ], + victory: [ + "dialogue:rocket_boss_giovanni_1.victory.1" + ], + defeat: [ + "dialogue:rocket_boss_giovanni_1.defeat.1" + ] + } + ], + [TrainerType.ROCKET_BOSS_GIOVANNI_2]: [ + { + encounter: [ + "dialogue:rocket_boss_giovanni_2.encounter.1" + ], + victory: [ + "dialogue:rocket_boss_giovanni_2.victory.1" + ], + defeat: [ + "dialogue:rocket_boss_giovanni_2.defeat.1" + ] + } + ], + [TrainerType.MAXIE]: [ + { + encounter: [ + "dialogue:magma_boss_maxie_1.encounter.1" + ], + victory: [ + "dialogue:magma_boss_maxie_1.victory.1" + ], + defeat: [ + "dialogue:magma_boss_maxie_1.defeat.1" + ] + } + ], + [TrainerType.MAXIE_2]: [ + { + encounter: [ + "dialogue:magma_boss_maxie_2.encounter.1" + ], + victory: [ + "dialogue:magma_boss_maxie_2.victory.1" + ], + defeat: [ + "dialogue:magma_boss_maxie_2.defeat.1" + ] + } + ], + [TrainerType.ARCHIE]: [ + { + encounter: [ + "dialogue:aqua_boss_archie_1.encounter.1" + ], + victory: [ + "dialogue:aqua_boss_archie_1.victory.1" + ], + defeat: [ + "dialogue:aqua_boss_archie_1.defeat.1" + ] + } + ], + [TrainerType.ARCHIE_2]: [ + { + encounter: [ + "dialogue:aqua_boss_archie_2.encounter.1" + ], + victory: [ + "dialogue:aqua_boss_archie_2.victory.1" + ], + defeat: [ + "dialogue:aqua_boss_archie_2.defeat.1" + ] + } + ], + [TrainerType.CYRUS]: [ + { + encounter: [ + "dialogue:galactic_boss_cyrus_1.encounter.1" + ], + victory: [ + "dialogue:galactic_boss_cyrus_1.victory.1" + ], + defeat: [ + "dialogue:galactic_boss_cyrus_1.defeat.1" + ] + } + ], + [TrainerType.CYRUS_2]: [ + { + encounter: [ + "dialogue:galactic_boss_cyrus_2.encounter.1" + ], + victory: [ + "dialogue:galactic_boss_cyrus_2.victory.1" + ], + defeat: [ + "dialogue:galactic_boss_cyrus_2.defeat.1" + ] + } + ], + [TrainerType.GHETSIS]: [ + { + encounter: [ + "dialogue:plasma_boss_ghetsis_1.encounter.1" + ], + victory: [ + "dialogue:plasma_boss_ghetsis_1.victory.1" + ], + defeat: [ + "dialogue:plasma_boss_ghetsis_1.defeat.1" + ] + } + ], + [TrainerType.GHETSIS_2]: [ + { + encounter: [ + "dialogue:plasma_boss_ghetsis_2.encounter.1" + ], + victory: [ + "dialogue:plasma_boss_ghetsis_2.victory.1" + ], + defeat: [ + "dialogue:plasma_boss_ghetsis_2.defeat.1" + ] + } + ], + [TrainerType.LYSANDRE]: [ + { + encounter: [ + "dialogue:flare_boss_lysandre_1.encounter.1" + ], + victory: [ + "dialogue:flare_boss_lysandre_1.victory.1" + ], + defeat: [ + "dialogue:flare_boss_lysandre_1.defeat.1" + ] + } + ], + [TrainerType.LYSANDRE_2]: [ + { + encounter: [ + "dialogue:flare_boss_lysandre_2.encounter.1" + ], + victory: [ + "dialogue:flare_boss_lysandre_2.victory.1" + ], + defeat: [ + "dialogue:flare_boss_lysandre_2.defeat.1" + ] + } + ], [TrainerType.BROCK]: { encounter: [ "dialogue:brock.encounter.1", diff --git a/src/data/egg.ts b/src/data/egg.ts index 74371049363..da6100446ec 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -1,6 +1,6 @@ import BattleScene from "../battle-scene"; import { Species } from "./enums/species"; -import { getPokemonSpecies, speciesStarters } from "./pokemon-species"; +import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species"; import { EggTier } from "./enums/egg-type"; import i18next from "../plugins/i18n"; @@ -111,3 +111,20 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta return ret; } + +/** + * Check for a given species EggTier Value + * @param species - Species for wich we will check the egg tier it belongs to + * @returns The egg tier of a given pokemon species + */ +export function getEggTierForSpecies(pokemonSpecies :PokemonSpecies): EggTier { + const speciesBaseValue = speciesStarters[pokemonSpecies.getRootSpeciesId()]; + if (speciesBaseValue <= 3) { + return EggTier.COMMON; + } else if (speciesBaseValue <= 5) { + return EggTier.GREAT; + } else if (speciesBaseValue <= 7) { + return EggTier.ULTRA; + } + return EggTier.MASTER; +} diff --git a/src/data/enums/challenges.ts b/src/data/enums/challenges.ts new file mode 100644 index 00000000000..690e1cdc32d --- /dev/null +++ b/src/data/enums/challenges.ts @@ -0,0 +1,7 @@ +export enum Challenges { + SINGLE_GENERATION, + SINGLE_TYPE, + LOWER_MAX_STARTER_COST, + LOWER_STARTER_POINTS, + FRESH_START +} diff --git a/src/data/enums/trainer-type.ts b/src/data/enums/trainer-type.ts index 64eb07e22ce..6bd8f567acb 100644 --- a/src/data/enums/trainer-type.ts +++ b/src/data/enums/trainer-type.ts @@ -52,6 +52,24 @@ export enum TrainerType { WAITER, WORKER, YOUNGSTER, + ROCKET_GRUNT, + MAGMA_GRUNT, + AQUA_GRUNT, + GALACTIC_GRUNT, + PLASMA_GRUNT, + FLARE_GRUNT, + ROCKET_BOSS_GIOVANNI_1, + ROCKET_BOSS_GIOVANNI_2, + MAXIE, + MAXIE_2, + ARCHIE, + ARCHIE_2, + CYRUS, + CYRUS_2, + GHETSIS, + GHETSIS_2, + LYSANDRE, + LYSANDRE_2, BROCK = 200, MISTY, diff --git a/src/data/move.ts b/src/data/move.ts old mode 100755 new mode 100644 index 82d1bec32f7..8e1c1ad921d --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1251,11 +1251,18 @@ export class PartyStatusCureAttr extends MoveEffectAttr { this.abilityCondition = abilityCondition; } + //The same as MoveEffectAttr.canApply, except it doesn't check for the target's HP. + canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { + const isTargetValid = + (this.selfTarget && user.hp && !user.getTag(BattlerTagType.FRENZY)) || + (!this.selfTarget && (!target.getTag(BattlerTagType.PROTECTED) || move.hasFlag(MoveFlags.IGNORE_PROTECT))); + return !!isTargetValid; + } + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!super.apply(user, target, move, args)) { + if (!this.canApply(user, target, move, args)) { return false; } - this.addPartyCurePhase(user); } @@ -1467,7 +1474,7 @@ export class HitHealAttr extends MoveEffectAttr { message = i18next.t("battle:drainMessage", {pokemonName: target.name}); } else { // Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc. - healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1); + healAmount = Math.max(Math.floor(user.turnData.currDamageDealt * this.healRatio), 1); message = i18next.t("battle:regainHealth", {pokemonName: user.name}); } if (reverseDrain) { @@ -3321,6 +3328,19 @@ export class VariableMoveTypeAttr extends MoveAttr { } } +export class FormChangeItemTypeAttr extends VariableMoveTypeAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.ARCEUS) || [user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.SILVALLY)) { + const form = user.species.speciesId === Species.ARCEUS || user.species.speciesId === Species.SILVALLY ? user.formIndex : user.fusionSpecies.formIndex; + + move.type = Type[Type[form]]; + return true; + } + + return false; + } +} + export class TechnoBlastTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.GENESECT)) { @@ -4416,7 +4436,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } const party = player ? user.scene.getParty() : user.scene.getEnemyParty(); - return (!player && !user.scene.currentBattle.battleType) || party.filter(p => !p.isFainted() && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > user.scene.currentBattle.getBattlerCount(); + return (!player && !user.scene.currentBattle.battleType) || party.filter(p => p.isAllowedInBattle() && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > user.scene.currentBattle.getBattlerCount(); }; } @@ -5097,7 +5117,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr { target.summonData.abilitySuppressed = true; - target.scene.queueMessage(getPokemonMessage(target, " ability\nwas suppressed!")); + target.scene.queueMessage(getPokemonMessage(target, "'s ability\nwas suppressed!")); return true; } @@ -5107,6 +5127,35 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr { } } +/** + * Applies the effects of {@linkcode SuppressAbilitiesAttr} if the target has already moved this turn. + * @extends MoveEffectAttr + * @see {@linkcode Moves.CORE_ENFORCER} (the move which uses this effect) + */ +export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr { + /** + * If the target has already acted this turn, apply a {@linkcode SuppressAbilitiesAttr} effect unless the + * 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. + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) { + return false; + } + + if (target.turnData.acted) { + const suppressAttr = new SuppressAbilitiesAttr(); + if (suppressAttr.getCondition()(user, target, move)) { + suppressAttr.apply(user, target, move, args); + } + } + + return true; + } +} + export class TransformAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { @@ -6005,7 +6054,7 @@ export function initMoves() { ], true) .attr(RemoveArenaTrapAttr), new StatusMove(Moves.SWEET_SCENT, Type.NORMAL, 100, 20, -1, 0, 2) - .attr(StatChangeAttr, BattleStat.EVA, -1) + .attr(StatChangeAttr, BattleStat.EVA, -2) .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.IRON_TAIL, Type.STEEL, MoveCategory.PHYSICAL, 100, 75, 15, 30, 0, 2) .attr(StatChangeAttr, BattleStat.DEF, -1), @@ -6605,7 +6654,7 @@ export function initMoves() { .attr(ConfuseAttr) .soundBased(), new AttackMove(Moves.JUDGMENT, Type.NORMAL, MoveCategory.SPECIAL, 100, 100, 10, -1, 0, 4) - .partial(), + .attr(FormChangeItemTypeAttr), new AttackMove(Moves.BUG_BITE, Type.BUG, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4) .attr(StealEatBerryAttr), new AttackMove(Moves.CHARGE_BEAM, Type.ELECTRIC, MoveCategory.SPECIAL, 50, 90, 10, 70, 0, 4) @@ -7291,7 +7340,7 @@ export function initMoves() { .attr(MatchUserTypeAttr), new AttackMove(Moves.CORE_ENFORCER, Type.DRAGON, MoveCategory.SPECIAL, 100, 100, 10, -1, 0, 7) .target(MoveTarget.ALL_NEAR_ENEMIES) - .partial(), + .attr(SuppressAbilitiesIfActedAttr), new AttackMove(Moves.TROP_KICK, Type.GRASS, MoveCategory.PHYSICAL, 70, 100, 15, 100, 0, 7) .attr(StatChangeAttr, BattleStat.ATK, -1), new StatusMove(Moves.INSTRUCT, Type.PSYCHIC, -1, 15, -1, 0, 7) @@ -7375,7 +7424,7 @@ export function initMoves() { new AttackMove(Moves.NATURES_MADNESS, Type.FAIRY, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 7) .attr(TargetHalfHpDamageAttr), new AttackMove(Moves.MULTI_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 10, -1, 0, 7) - .partial(), + .attr(FormChangeItemTypeAttr), /* Unused */ new AttackMove(Moves.TEN_MILLION_VOLT_THUNDERBOLT, Type.ELECTRIC, MoveCategory.SPECIAL, 195, -1, 1, -1, 0, 7) .partial() diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 77991ee6434..998752f4d34 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -86,7 +86,45 @@ export enum FormChangeItem { SHOCK_DRIVE, BURN_DRIVE, CHILL_DRIVE, - DOUSE_DRIVE + DOUSE_DRIVE, + + FIST_PLATE = 100, + SKY_PLATE, + TOXIC_PLATE, + EARTH_PLATE, + STONE_PLATE, + INSECT_PLATE, + SPOOKY_PLATE, + IRON_PLATE, + FLAME_PLATE, + SPLASH_PLATE, + MEADOW_PLATE, + ZAP_PLATE, + MIND_PLATE, + ICICLE_PLATE, + DRACO_PLATE, + DREAD_PLATE, + PIXIE_PLATE, + BLANK_PLATE, // TODO: Find a potential use for this + LEGEND_PLATE, // TODO: Find a potential use for this + FIGHTING_MEMORY, + FLYING_MEMORY, + POISON_MEMORY, + GROUND_MEMORY, + ROCK_MEMORY, + BUG_MEMORY, + GHOST_MEMORY, + STEEL_MEMORY, + FIRE_MEMORY, + WATER_MEMORY, + GRASS_MEMORY, + ELECTRIC_MEMORY, + PSYCHIC_MEMORY, + ICE_MEMORY, + DRAGON_MEMORY, + DARK_MEMORY, + FAIRY_MEMORY, + BLANK_MEMORY // TODO: Find a potential use for this } export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean; @@ -533,6 +571,25 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.SHAYMIN, "sky", "land", new SpeciesFormChangeTimeOfDayTrigger(TimeOfDay.DAWN, TimeOfDay.NIGHT)), new SpeciesFormChange(Species.SHAYMIN, "sky", "land", new SpeciesFormChangeStatusEffectTrigger(StatusEffect.FREEZE)) ], + [Species.ARCEUS]: [ + new SpeciesFormChange(Species.ARCEUS, "normal", "fighting", new SpeciesFormChangeItemTrigger(FormChangeItem.FIST_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "flying", new SpeciesFormChangeItemTrigger(FormChangeItem.SKY_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "poison", new SpeciesFormChangeItemTrigger(FormChangeItem.TOXIC_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "ground", new SpeciesFormChangeItemTrigger(FormChangeItem.EARTH_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "rock", new SpeciesFormChangeItemTrigger(FormChangeItem.STONE_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "bug", new SpeciesFormChangeItemTrigger(FormChangeItem.INSECT_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "ghost", new SpeciesFormChangeItemTrigger(FormChangeItem.SPOOKY_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "steel", new SpeciesFormChangeItemTrigger(FormChangeItem.IRON_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "fire", new SpeciesFormChangeItemTrigger(FormChangeItem.FLAME_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "water", new SpeciesFormChangeItemTrigger(FormChangeItem.SPLASH_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "grass", new SpeciesFormChangeItemTrigger(FormChangeItem.MEADOW_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "electric", new SpeciesFormChangeItemTrigger(FormChangeItem.ZAP_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "psychic", new SpeciesFormChangeItemTrigger(FormChangeItem.MIND_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "ice", new SpeciesFormChangeItemTrigger(FormChangeItem.ICICLE_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "dragon", new SpeciesFormChangeItemTrigger(FormChangeItem.DRACO_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "dark", new SpeciesFormChangeItemTrigger(FormChangeItem.DREAD_PLATE)), + new SpeciesFormChange(Species.ARCEUS, "normal", "fairy", new SpeciesFormChangeItemTrigger(FormChangeItem.PIXIE_PLATE)) + ], [Species.DARMANITAN]: [ new SpeciesFormChange(Species.DARMANITAN, "", "zen", new SpeciesFormChangeManualTrigger(), true), new SpeciesFormChange(Species.DARMANITAN, "zen", "", new SpeciesFormChangeManualTrigger(), true) @@ -597,6 +654,25 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.WISHIWASHI, "", "school", new SpeciesFormChangeManualTrigger(), true), new SpeciesFormChange(Species.WISHIWASHI, "school", "", new SpeciesFormChangeManualTrigger(), true) ], + [Species.SILVALLY]: [ + new SpeciesFormChange(Species.SILVALLY, "normal", "fighting", new SpeciesFormChangeItemTrigger(FormChangeItem.FIGHTING_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "flying", new SpeciesFormChangeItemTrigger(FormChangeItem.FLYING_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "poison", new SpeciesFormChangeItemTrigger(FormChangeItem.POISON_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "ground", new SpeciesFormChangeItemTrigger(FormChangeItem.GROUND_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "rock", new SpeciesFormChangeItemTrigger(FormChangeItem.ROCK_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "bug", new SpeciesFormChangeItemTrigger(FormChangeItem.BUG_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "ghost", new SpeciesFormChangeItemTrigger(FormChangeItem.GHOST_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "steel", new SpeciesFormChangeItemTrigger(FormChangeItem.STEEL_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "fire", new SpeciesFormChangeItemTrigger(FormChangeItem.FIRE_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "water", new SpeciesFormChangeItemTrigger(FormChangeItem.WATER_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "grass", new SpeciesFormChangeItemTrigger(FormChangeItem.GRASS_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "electric", new SpeciesFormChangeItemTrigger(FormChangeItem.ELECTRIC_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "psychic", new SpeciesFormChangeItemTrigger(FormChangeItem.PSYCHIC_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "ice", new SpeciesFormChangeItemTrigger(FormChangeItem.ICE_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "dragon", new SpeciesFormChangeItemTrigger(FormChangeItem.DRAGON_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "dark", new SpeciesFormChangeItemTrigger(FormChangeItem.DARK_MEMORY)), + new SpeciesFormChange(Species.SILVALLY, "normal", "fairy", new SpeciesFormChangeItemTrigger(FormChangeItem.FAIRY_MEMORY)) + ], [Species.MINIOR]: [ new SpeciesFormChange(Species.MINIOR, "red-meteor", "red", new SpeciesFormChangeManualTrigger(), true), new SpeciesFormChange(Species.MINIOR, "red", "red-meteor", new SpeciesFormChangeManualTrigger(), true), diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 4f6098734ec..398fecd2d03 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -2321,7 +2321,7 @@ export function initSpecies() { new PokemonForm("Ruby Swirl", "ruby-swirl", Type.FAIRY, null, 0.3, 0.5, Abilities.SWEET_VEIL, Abilities.NONE, Abilities.AROMA_VEIL, 495, 65, 60, 75, 110, 121, 64, 100, 50, 173, false, null, true), new PokemonForm("Caramel Swirl", "caramel-swirl", Type.FAIRY, null, 0.3, 0.5, Abilities.SWEET_VEIL, Abilities.NONE, Abilities.AROMA_VEIL, 495, 65, 60, 75, 110, 121, 64, 100, 50, 173, false, null, true), new PokemonForm("Rainbow Swirl", "rainbow-swirl", Type.FAIRY, null, 0.3, 0.5, Abilities.SWEET_VEIL, Abilities.NONE, Abilities.AROMA_VEIL, 495, 65, 60, 75, 110, 121, 64, 100, 50, 173, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FAIRY, null, 30, 0.5, Abilities.SWEET_VEIL, Abilities.NONE, Abilities.AROMA_VEIL, 595, 80, 70, 85, 140, 150, 65, 100, 50, 173), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FAIRY, null, 30, 0.5, Abilities.SWEET_VEIL, Abilities.NONE, Abilities.AROMA_VEIL, 595, 85, 70, 85, 140, 150, 65, 100, 50, 173), ), new PokemonSpecies(Species.FALINKS, 8, false, false, false, "Formation Pokémon", Type.FIGHTING, null, 3, 62, Abilities.BATTLE_ARMOR, Abilities.NONE, Abilities.DEFIANT, 470, 65, 100, 100, 70, 60, 75, 45, 50, 165, GrowthRate.MEDIUM_FAST, null, false), new PokemonSpecies(Species.PINCURCHIN, 8, false, false, false, "Sea Urchin Pokémon", Type.ELECTRIC, null, 0.3, 1, Abilities.LIGHTNING_ROD, Abilities.NONE, Abilities.ELECTRIC_SURGE, 435, 48, 101, 95, 91, 85, 15, 75, 50, 152, GrowthRate.MEDIUM_FAST, 50, false), @@ -2617,19 +2617,19 @@ export function initSpecies() { ), new PokemonSpecies(Species.GALAR_YAMASK, 8, false, false, false, "Spirit Pokémon", Type.GROUND, Type.GHOST, 0.5, 1.5, Abilities.WANDERING_SPIRIT, Abilities.NONE, Abilities.NONE, 303, 38, 55, 85, 30, 65, 30, 190, 50, 61, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.GALAR_STUNFISK, 8, false, false, false, "Trap Pokémon", Type.GROUND, Type.STEEL, 0.7, 20.5, Abilities.MIMICRY, Abilities.NONE, Abilities.NONE, 471, 109, 81, 99, 66, 84, 32, 75, 70, 165, GrowthRate.MEDIUM_FAST, 50, false), - new PokemonSpecies(Species.HISUI_GROWLITHE, 8, false, false, false, "Puppy Pokémon", Type.FIRE, Type.ROCK, 0.8, 22.7, Abilities.INTIMIDATE, Abilities.FLASH_FIRE, Abilities.ROCK_HEAD, 350, 60, 85, 45, 65, 50, 55, 190, 50, 70, GrowthRate.SLOW, 75, false), + new PokemonSpecies(Species.HISUI_GROWLITHE, 8, false, false, false, "Puppy Pokémon", Type.FIRE, Type.ROCK, 0.8, 22.7, Abilities.INTIMIDATE, Abilities.FLASH_FIRE, Abilities.ROCK_HEAD, 350, 60, 75, 45, 65, 50, 55, 190, 50, 70, GrowthRate.SLOW, 75, false), new PokemonSpecies(Species.HISUI_ARCANINE, 8, false, false, false, "Legendary Pokémon", Type.FIRE, Type.ROCK, 2, 168, Abilities.INTIMIDATE, Abilities.FLASH_FIRE, Abilities.ROCK_HEAD, 555, 95, 115, 80, 95, 80, 90, 85, 50, 194, GrowthRate.SLOW, 75, false), new PokemonSpecies(Species.HISUI_VOLTORB, 8, false, false, false, "Ball Pokémon", Type.ELECTRIC, Type.GRASS, 0.5, 13, Abilities.SOUNDPROOF, Abilities.STATIC, Abilities.AFTERMATH, 330, 40, 30, 50, 55, 55, 100, 190, 80, 66, GrowthRate.MEDIUM_FAST, null, false), new PokemonSpecies(Species.HISUI_ELECTRODE, 8, false, false, false, "Ball Pokémon", Type.ELECTRIC, Type.GRASS, 1.2, 81, Abilities.SOUNDPROOF, Abilities.STATIC, Abilities.AFTERMATH, 490, 60, 50, 70, 80, 80, 150, 60, 70, 172, GrowthRate.MEDIUM_FAST, null, false), - new PokemonSpecies(Species.HISUI_TYPHLOSION, 8, false, false, false, "Volcano Pokémon", Type.FIRE, Type.GHOST, 1.6, 69.8, Abilities.BLAZE, Abilities.NONE, Abilities.FRISK, 534, 83, 84, 78, 119, 85, 95, 45, 70, 240, GrowthRate.MEDIUM_SLOW, 87.5, false), + new PokemonSpecies(Species.HISUI_TYPHLOSION, 8, false, false, false, "Volcano Pokémon", Type.FIRE, Type.GHOST, 1.6, 69.8, Abilities.BLAZE, Abilities.NONE, Abilities.FRISK, 534, 73, 84, 78, 119, 85, 95, 45, 70, 240, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.HISUI_QWILFISH, 8, false, false, false, "Balloon Pokémon", Type.DARK, Type.POISON, 0.5, 3.9, Abilities.POISON_POINT, Abilities.SWIFT_SWIM, Abilities.INTIMIDATE, 440, 65, 95, 85, 55, 55, 85, 45, 50, 88, GrowthRate.MEDIUM_FAST, 50, false), - new PokemonSpecies(Species.HISUI_SNEASEL, 8, false, false, false, "Sharp Claw Pokémon", Type.FIGHTING, Type.POISON, 0.9, 27, Abilities.INNER_FOCUS, Abilities.KEEN_EYE, Abilities.PICKPOCKET, 430, 55, 95, 55, 35, 85, 115, 60, 35, 86, GrowthRate.MEDIUM_SLOW, 50, true), + new PokemonSpecies(Species.HISUI_SNEASEL, 8, false, false, false, "Sharp Claw Pokémon", Type.FIGHTING, Type.POISON, 0.9, 27, Abilities.INNER_FOCUS, Abilities.KEEN_EYE, Abilities.PICKPOCKET, 430, 55, 95, 55, 35, 75, 115, 60, 35, 86, GrowthRate.MEDIUM_SLOW, 50, true), new PokemonSpecies(Species.HISUI_SAMUROTT, 8, false, false, false, "Formidable Pokémon", Type.WATER, Type.DARK, 1.5, 58.2, Abilities.TORRENT, Abilities.NONE, Abilities.SHARPNESS, 528, 90, 108, 80, 100, 65, 85, 45, 80, 238, GrowthRate.MEDIUM_SLOW, 87.5, false), - new PokemonSpecies(Species.HISUI_LILLIGANT, 8, false, false, false, "Flowering Pokémon", Type.GRASS, Type.FIGHTING, 1.2, 19.2, Abilities.CHLOROPHYLL, Abilities.HUSTLE, Abilities.LEAF_GUARD, 480, 80, 105, 75, 50, 75, 105, 75, 50, 168, GrowthRate.MEDIUM_FAST, 0, false), - new PokemonSpecies(Species.HISUI_ZORUA, 8, false, false, false, "Tricky Fox Pokémon", Type.NORMAL, Type.GHOST, 0.7, 12.5, Abilities.ILLUSION, Abilities.NONE, Abilities.NONE, 330, 35, 60, 40, 85, 40, 80, 75, 50, 66, GrowthRate.MEDIUM_SLOW, 87.5, false), + new PokemonSpecies(Species.HISUI_LILLIGANT, 8, false, false, false, "Flowering Pokémon", Type.GRASS, Type.FIGHTING, 1.2, 19.2, Abilities.CHLOROPHYLL, Abilities.HUSTLE, Abilities.LEAF_GUARD, 480, 70, 105, 75, 50, 75, 105, 75, 50, 168, GrowthRate.MEDIUM_FAST, 0, false), + new PokemonSpecies(Species.HISUI_ZORUA, 8, false, false, false, "Tricky Fox Pokémon", Type.NORMAL, Type.GHOST, 0.7, 12.5, Abilities.ILLUSION, Abilities.NONE, Abilities.NONE, 330, 35, 60, 40, 85, 40, 70, 75, 50, 66, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.HISUI_ZOROARK, 8, false, false, false, "Illusion Fox Pokémon", Type.NORMAL, Type.GHOST, 1.6, 83, Abilities.ILLUSION, Abilities.NONE, Abilities.NONE, 510, 55, 100, 60, 125, 60, 110, 45, 50, 179, GrowthRate.MEDIUM_SLOW, 87.5, false), - new PokemonSpecies(Species.HISUI_BRAVIARY, 8, false, false, false, "Valiant Pokémon", Type.PSYCHIC, Type.FLYING, 1.7, 43.4, Abilities.KEEN_EYE, Abilities.SHEER_FORCE, Abilities.TINTED_LENS, 510, 110, 83, 80, 112, 70, 65, 60, 50, 179, GrowthRate.SLOW, 100, false), - new PokemonSpecies(Species.HISUI_SLIGGOO, 8, false, false, false, "Soft Tissue Pokémon", Type.STEEL, Type.DRAGON, 0.7, 68.5, Abilities.SAP_SIPPER, Abilities.SHELL_ARMOR, Abilities.GOOEY, 452, 58, 85, 83, 83, 113, 40, 45, 35, 158, GrowthRate.SLOW, 50, false), + new PokemonSpecies(Species.HISUI_BRAVIARY, 8, false, false, false, "Valiant Pokémon", Type.PSYCHIC, Type.FLYING, 1.7, 43.4, Abilities.KEEN_EYE, Abilities.SHEER_FORCE, Abilities.TINTED_LENS, 510, 110, 83, 70, 112, 70, 65, 60, 50, 179, GrowthRate.SLOW, 100, false), + new PokemonSpecies(Species.HISUI_SLIGGOO, 8, false, false, false, "Soft Tissue Pokémon", Type.STEEL, Type.DRAGON, 0.7, 68.5, Abilities.SAP_SIPPER, Abilities.SHELL_ARMOR, Abilities.GOOEY, 452, 58, 75, 83, 83, 113, 40, 45, 35, 158, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.HISUI_GOODRA, 8, false, false, false, "Dragon Pokémon", Type.STEEL, Type.DRAGON, 1.7, 334.1, Abilities.SAP_SIPPER, Abilities.SHELL_ARMOR, Abilities.GOOEY, 600, 80, 100, 100, 110, 150, 60, 45, 35, 270, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.HISUI_AVALUGG, 8, false, false, false, "Iceberg Pokémon", Type.ICE, Type.ROCK, 1.4, 262.4, Abilities.STRONG_JAW, Abilities.ICE_BODY, Abilities.STURDY, 514, 95, 127, 184, 34, 36, 38, 55, 50, 180, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.HISUI_DECIDUEYE, 8, false, false, false, "Arrow Quill Pokémon", Type.GRASS, Type.FIGHTING, 1.6, 37, Abilities.OVERGROW, Abilities.NONE, Abilities.SCRAPPY, 530, 88, 112, 80, 95, 95, 60, 45, 50, 239, GrowthRate.MEDIUM_SLOW, 87.5, false), diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 8a955afa746..43ce8c8444a 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -187,6 +187,7 @@ export class TrainerConfig { public isBoss: boolean = false; public hasStaticParty: boolean = false; public useSameSeedForAllMembers: boolean = false; + public mixedBattleBgm: string; public battleBgm: string; public encounterBgm: string; public femaleEncounterBgm: string; @@ -217,6 +218,7 @@ export class TrainerConfig { this.trainerType = trainerType; this.name = Utils.toReadableString(TrainerType[this.getDerivedType()]); this.battleBgm = "battle_trainer"; + this.mixedBattleBgm = "battle_trainer"; this.victoryBgm = "victory_trainer"; this.partyTemplates = [trainerPartyTemplates.TWO_AVG]; this.speciesFilter = species => (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) && !species.isTrainerForbidden(); @@ -293,6 +295,25 @@ export class TrainerConfig { case TrainerType.LARRY_ELITE: trainerType = TrainerType.LARRY; break; + case TrainerType.ROCKET_BOSS_GIOVANNI_1: + case TrainerType.ROCKET_BOSS_GIOVANNI_2: + trainerType = TrainerType.GIOVANNI; + break; + case TrainerType.MAXIE_2: + trainerType = TrainerType.MAXIE; + break; + case TrainerType.ARCHIE_2: + trainerType = TrainerType.ARCHIE; + break; + case TrainerType.CYRUS_2: + trainerType = TrainerType.CYRUS; + break; + case TrainerType.GHETSIS_2: + trainerType = TrainerType.GHETSIS; + break; + case TrainerType.LYSANDRE_2: + trainerType = TrainerType.LYSANDRE; + break; case TrainerType.MARNIE_ELITE: trainerType = TrainerType.MARNIE; break; @@ -440,6 +461,11 @@ export class TrainerConfig { return this; } + setMixedBattleBgm(mixedBattleBgm: string): TrainerConfig { + this.mixedBattleBgm = mixedBattleBgm; + return this; + } + setBattleBgm(battleBgm: string): TrainerConfig { this.battleBgm = battleBgm; return this; @@ -501,6 +527,39 @@ export class TrainerConfig { return this; } + /** + * Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though. + * @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader. + * @param {Type[]} specialtyTypes - The specialty types for the evil team Leader. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], ...specialtyTypes: Type[]): TrainerConfig { + if (!getIsInitialized()) { + initI18n(); + } + this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); + signatureSpecies.forEach((speciesPool, s) => { + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + if (specialtyTypes.length) { + this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined); + this.setSpecialtyTypes(...specialtyTypes); + } + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + this.setTitle(title); + this.setMoneyMultiplier(2.5); + this.setBoss(); + this.setStaticParty(); + this.setBattleBgm("battle_unova_gym"); // TODO: change + this.setVictoryBgm("victory_gym"); // TODO: change + + return this; + } + /** * Initializes the trainer configuration for a Gym Leader. * @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader. @@ -605,7 +664,7 @@ export class TrainerConfig { this.setMoneyMultiplier(3.25); this.setBoss(); this.setStaticParty(); - this.setBattleBgm("battle_elite"); + this.setBattleBgm("battle_unova_elite"); this.setVictoryBgm("victory_gym"); this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : null)); @@ -754,6 +813,34 @@ interface TrainerConfigs { [key: integer]: TrainerConfig } +/** + * The function to get variable strength grutns + * @param scene the singleton scene being passed in + * @returns the correct TrainerPartyTemplate + */ +function getEvilGruntPartyTemplate(scene: BattleScene): TrainerPartyTemplate { + const waveIndex = scene.currentBattle?.waveIndex; + if (waveIndex < 40) { + return trainerPartyTemplates.TWO_AVG; + } else if (waveIndex < 80) { + switch (waveIndex) { + case 62: + return trainerPartyTemplates.THREE_AVG; + case 64: + return trainerPartyTemplates.TWO_AVG_ONE_STRONG; + case 65: + return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + } + } else { + switch (waveIndex) { + case 112: + return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + case 114: + return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger + } + } +} + function getWavePartyTemplate(scene: BattleScene, ...templates: TrainerPartyTemplate[]) { return templates[Math.min(Math.max(Math.ceil((scene.gameMode.getWaveForDifficulty(scene.currentBattle?.waveIndex || startingWave, true) - 20) / 30), 0), templates.length - 1)]; } @@ -876,22 +963,22 @@ export const signatureSpecies: SignatureSpecies = { RYME: [Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], TULIP: [Species.GIRAFARIG, Species.FLITTLE, Species.RALTS], GRUSHA: [Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO], - LORELEI: [Species.SLOWBRO, Species.LAPRAS, Species.DEWGONG, Species.ALOLA_SANDSLASH], - BRUNO: [Species.ONIX, Species.HITMONCHAN, Species.HITMONLEE, Species.ALOLA_GOLEM], - AGATHA: [Species.GENGAR, Species.ARBOK, Species.CROBAT, Species.ALOLA_MAROWAK], + LORELEI: [Species.JYNX, [Species.SLOWBRO, Species.GALAR_SLOWBRO], Species.LAPRAS, [Species.ALOLA_SANDSLASH, Species.CLOYSTER]], + BRUNO: [Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [Species.ALOLA_GOLEM, Species.GOLEM]], + AGATHA: [Species.GENGAR, [Species.ARBOK, Species.WEEZING], Species.CROBAT, Species.ALOLA_MAROWAK], LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR], - WILL: [Species.XATU, Species.JYNX, Species.SLOWBRO, Species.EXEGGUTOR], - KOGA: [Species.WEEZING, Species.VENOMOTH, Species.CROBAT, Species.TENTACRUEL], + WILL: [Species.XATU, Species.JYNX, [Species.SLOWBRO, Species.SLOWKING], Species.EXEGGUTOR], + KOGA: [[Species.WEEZING, Species.MUK], [Species.VENOMOTH, Species.ARIADOS], Species.CROBAT, Species.TENTACRUEL], KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE], - SIDNEY: [Species.SHIFTRY, Species.SHARPEDO, Species.ABSOL, Species.ZOROARK], - PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, Species.CHANDELURE], + SIDNEY: [[Species.SHIFTRY, Species.CACTURNE], [Species.SHARPEDO, Species.CRAWDAUNT], Species.ABSOL, Species.MIGHTYENA], + PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [Species.MISMAGIUS, Species.DRIFBLIM]], GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW], DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA], - AARON: [Species.SCIZOR, Species.HERACROSS, Species.VESPIQUEN, Species.DRAPION], + AARON: [[Species.SCIZOR, Species.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION], BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR], - FLINT: [Species.FLAREON, Species.HOUNDOOM, Species.RAPIDASH, Species.INFERNAPE], - LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, Species.ALAKAZAM], - SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.DRIFBLIM], + FLINT: [[Species.FLAREON, Species.RAPIDASH], Species.MAGMORTAR, [Species.STEELIX, Species.LOPUNNY], Species.INFERNAPE], + LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [Species.ALAKAZAM, Species.ESPEON]], + SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT], MARSHAL: [Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK], GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE], CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS], @@ -899,35 +986,35 @@ export const signatureSpecies: SignatureSpecies = { SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE], WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH], DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN], - HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, Species.POLIWRATH], + HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, [Species.POLIWRATH, Species.ANNIHILAPE]], MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO], - OLIVIA: [Species.ARMALDO, Species.CRADILY, Species.ALOLA_GOLEM, Species.LYCANROC], - ACEROLA: [Species.BANETTE, Species.DRIFBLIM, Species.DHELMISE, Species.PALOSSAND], - KAHILI: [Species.BRAVIARY, Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON], - MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, Species.TOXICROAK, Species.SCRAFTY, Species.GRIMMSNARL], - NESSA_ELITE: [Species.GOLISOPOD, Species.PELIPPER, Species.QUAGSIRE, Species.TOXAPEX, Species.DREDNAW], - BEA_ELITE: [Species.HAWLUCHA, Species.GRAPPLOCT, Species.SIRFETCHD, Species.FALINKS, Species.MACHAMP], - ALLISTER_ELITE:[Species.DUSKNOIR, Species.CHANDELURE, Species.CURSOLA, Species.RUNERIGUS, Species.GENGAR], - RAIHAN_ELITE: [Species.TORKOAL, Species.GOODRA, Species.TURTONATOR, Species.FLYGON, Species.DURALUDON], - RIKA: [Species.WHISCASH, Species.DONPHAN, Species.CAMERUPT, Species.CLODSIRE], + OLIVIA: [Species.RELICANTH, Species.CARBINK, Species.ALOLA_GOLEM, Species.LYCANROC], + ACEROLA: [[Species.BANETTE, Species.DRIFBLIM], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND], + KAHILI: [[Species.BRAVIARY, Species.MANDIBUZZ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON], + MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL], + NESSA_ELITE: [Species.GOLISOPOD, [Species.PELIPPER, Species.QUAGSIRE], Species.TOXAPEX, Species.DREDNAW], + BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP], + ALLISTER_ELITE:[Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR], + RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON], + RIKA: [Species.WHISCASH, [Species.DONPHAN, Species.DUGTRIO], Species.CAMERUPT, Species.CLODSIRE], POPPY: [Species.COPPERAJAH, Species.BRONZONG, Species.CORVIKNIGHT, Species.TINKATON], LARRY_ELITE: [Species.STARAPTOR, Species.FLAMIGO, Species.ALTARIA, Species.TROPIUS], - HASSEL: [Species.NOIVERN, Species.HAXORUS, Species.DRAGALGE, Species.BAXCALIBUR], + HASSEL: [Species.NOIVERN, [Species.FLAPPLE, Species.APPLETUN], Species.DRAGALGE, Species.BAXCALIBUR], CRISPIN: [Species.TALONFLAME, Species.CAMERUPT, Species.MAGMORTAR, Species.BLAZIKEN], AMARYS: [Species.SKARMORY, Species.EMPOLEON, Species.SCIZOR, Species.METAGROSS], - LACEY: [Species.EXCADRILL, Species.PRIMARINA, Species.ALCREMIE, Species.GALAR_SLOWBRO], - DRAYTON: [Species.DRAGONITE, Species.ARCHALUDON, Species.FLYGON, Species.SCEPTILE], + LACEY: [Species.EXCADRILL, Species.PRIMARINA, [Species.ALCREMIE, Species.GRANBULL], Species.WHIMSICOTT], + DRAYTON: [Species.DRAGONITE, Species.ARCHALUDON, Species.HAXORUS, Species.SCEPTILE], BLUE: [[Species.GYARADOS, Species.EXEGGUTOR, Species.ARCANINE], Species.HO_OH, [Species.RHYPERIOR, Species.MAGNEZONE]], // Alakazam lead, Mega Pidgeot RED: [Species.LUGIA, Species.SNORLAX, [Species.ESPEON, Species.UMBREON, Species.SYLVEON]], // GMax Pikachu lead, Mega gen 1 starter - LANCE_CHAMPION: [Species.DRAGONITE, Species.KINGDRA, Species.ALOLA_EXEGGUTOR], // Aerodactyl lead, Mega Lati@s - STEVEN: [Species.AGGRON, [Species.ARMALDO, Species.CRADILY], Species.DIALGA], // Skarmorly lead, Mega Metagross + LANCE_CHAMPION: [Species.DRAGONITE, Species.KINGDRA, Species.ALOLA_EXEGGUTOR], // Aerodactyl lead, Mega Latias/Latios + STEVEN: [Species.AGGRON, [Species.ARMALDO, Species.CRADILY], Species.DIALGA], // Skarmory lead, Mega Metagross WALLACE: [Species.MILOTIC, Species.PALKIA, Species.LUDICOLO], // Pelipper lead, Mega Swampert CYNTHIA: [Species.GIRATINA, Species.LUCARIO, Species.TOGEKISS], // Spiritomb lead, Mega Garchomp ALDER: [Species.VOLCARONA, Species.ZEKROM, [Species.ACCELGOR, Species.ESCAVALIER], Species.KELDEO], // Bouffalant/Braviary lead IRIS: [Species.HAXORUS, Species.RESHIRAM, Species.ARCHEOPS], // Druddigon lead, Gmax Lapras DIANTHA: [Species.HAWLUCHA, Species.XERNEAS, Species.GOODRA], // Gourgeist lead, Mega Gardevoir HAU: [[Species.SOLGALEO, Species.LUNALA], Species.NOIVERN, [Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA], [Species.TAPU_BULU, Species.TAPU_FINI, Species.TAPU_KOKO, Species.TAPU_LELE]], // Alola Raichu lead - LEON: [Species.DRAGAPULT, [Species.ZACIAN, Species.ZAMAZENTA], Species.AEGISLASH], // Rillaboom/Cinderace/Inteleon lead + LEON: [Species.DRAGAPULT, [Species.ZACIAN, Species.ZAMAZENTA], Species.AEGISLASH], // Rillaboom/Cinderace/Inteleon lead, GMax Charizard GEETA: [Species.MIRAIDON, [Species.ESPATHRA, Species.VELUZA], [Species.AVALUGG, Species.HISUI_AVALUGG], Species.KINGAMBIT], // Glimmora lead NEMONA: [Species.KORAIDON, Species.PAWMOT, [Species.DUDUNSPARCE, Species.ORTHWORM], [Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL]], // Lycanroc lead KIERAN: [[Species.GRIMMSNARL, Species.INCINEROAR, Species.PORYGON_Z], Species.OGERPON, Species.TERAPAGOS, Species.HYDRAPPLE], // Poliwrath/Politoed lead @@ -1096,124 +1183,172 @@ export const trainerConfigs: TrainerConfigs = { .setSpeciesPools( [Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP] ), - [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"],true, Type.ROCK).setBattleBgm("battle_kanto_gym"), - [TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"],false, Type.WATER).setBattleBgm("battle_kanto_gym"), - [TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LT_SURGE"],true, Type.ELECTRIC).setBattleBgm("battle_kanto_gym"), - [TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ERIKA"],false, Type.GRASS).setBattleBgm("battle_kanto_gym"), - [TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JANINE"],false, Type.POISON).setBattleBgm("battle_kanto_gym"), - [TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SABRINA"],false, Type.PSYCHIC).setBattleBgm("battle_kanto_gym"), - [TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BLAINE"],true, Type.FIRE).setBattleBgm("battle_kanto_gym"), - [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GIOVANNI"],true, Type.DARK).setBattleBgm("battle_kanto_gym"), - [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FALKNER"],true, Type.FLYING).setBattleBgm("battle_johto_gym"), - [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BUGSY"],true, Type.BUG).setBattleBgm("battle_johto_gym"), - [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WHITNEY"],false, Type.NORMAL).setBattleBgm("battle_johto_gym"), - [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MORTY"],true, Type.GHOST).setBattleBgm("battle_johto_gym"), - [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHUCK"],true, Type.FIGHTING).setBattleBgm("battle_johto_gym"), - [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JASMINE"],false, Type.STEEL).setBattleBgm("battle_johto_gym"), - [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PRYCE"],true, Type.ICE).setBattleBgm("battle_johto_gym"), - [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAIR"],false, Type.DRAGON).setBattleBgm("battle_johto_gym"), - [TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXANNE"],false, Type.ROCK).setBattleBgm("battle_hoenn_gym"), - [TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRAWLY"],true, Type.FIGHTING).setBattleBgm("battle_hoenn_gym"), - [TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WATTSON"],true, Type.ELECTRIC).setBattleBgm("battle_hoenn_gym"), - [TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FLANNERY"],false, Type.FIRE).setBattleBgm("battle_hoenn_gym"), - [TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["NORMAN"],true, Type.NORMAL).setBattleBgm("battle_hoenn_gym"), - [TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WINONA"],false, Type.FLYING).setBattleBgm("battle_hoenn_gym"), - [TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TATE"],true, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setHasDouble("tate_liza_double").setDoubleTrainerType(TrainerType.LIZA).setDoubleTitle("gym_leader_double"), - [TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LIZA"],false, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setHasDouble("liza_tate_double").setDoubleTrainerType(TrainerType.TATE).setDoubleTitle("gym_leader_double"), - [TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JUAN"],true, Type.WATER).setBattleBgm("battle_hoenn_gym"), - [TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROARK"],true, Type.ROCK).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GARDENIA"],false, Type.GRASS).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MAYLENE"],false, Type.FIGHTING).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRASHER_WAKE"],true, Type.WATER).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FANTINA"],false, Type.GHOST).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BYRON"],true, Type.STEEL).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CANDICE"],false, Type.ICE).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VOLKNER"],true, Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym"), - [TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CILAN"],true, Type.GRASS), - [TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHILI"],true, Type.FIRE), - [TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRESS"],true, Type.WATER), - [TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHEREN"],true, Type.NORMAL), - [TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LENORA"],false, Type.NORMAL), - [TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXIE"],false, Type.POISON), - [TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BURGH"],true, Type.BUG), - [TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ELESA"],false, Type.ELECTRIC), - [TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAY"],true, Type.GROUND), - [TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SKYLA"],false, Type.FLYING), - [TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRYCEN"],true, Type.ICE), - [TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["DRAYDEN"],true, Type.DRAGON), - [TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MARLON"],true, Type.WATER), - [TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VIOLA"],false, Type.BUG), - [TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRANT"],true, Type.ROCK), - [TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KORRINA"],false, Type.FIGHTING), - [TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RAMOS"],true, Type.GRASS), - [TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLEMONT"],true, Type.ELECTRIC), - [TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VALERIE"],false, Type.FAIRY), - [TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OLYMPIA"],false, Type.PSYCHIC), - [TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WULFRIC"],true, Type.ICE), - [TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MILO"],true, Type.GRASS), - [TrainerType.NESSA]: new TrainerConfig(++t).setName("Nessa").initForGymLeader(signatureSpecies["NESSA"],false, Type.WATER), - [TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KABU"],true, Type.FIRE), - [TrainerType.BEA]: new TrainerConfig(++t).setName("Bea").initForGymLeader(signatureSpecies["BEA"],false, Type.FIGHTING), - [TrainerType.ALLISTER]: new TrainerConfig(++t).setName("Allister").initForGymLeader(signatureSpecies["ALLISTER"],true, Type.GHOST), - [TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OPAL"],false, Type.FAIRY), - [TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BEDE"],true, Type.FAIRY), - [TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GORDIE"],true, Type.ROCK), - [TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MELONY"],false, Type.ICE), - [TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"],true, Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double"), - [TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"],false, Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double"), - [TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"],true, Type.DRAGON), - [TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"],false, Type.BUG), - [TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"],true, Type.GRASS), - [TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"],false, Type.ELECTRIC), - [TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"],true, Type.WATER), - [TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"],true, Type.NORMAL), - [TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"],false, Type.GHOST), - [TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"],false, Type.PSYCHIC), - [TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"],true, Type.ICE), + [TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING], + [TrainerPoolTier.UNCOMMON]: [Species.GRIMER, Species.CUBONE, Species.ODDISH, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], + [TrainerPoolTier.RARE]: [Species.GYARADOS, Species.TAUROS, Species.SCYTHER], + [TrainerPoolTier.SUPER_RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], + [TrainerPoolTier.ULTRA_RARE]: [Species.DRATINI, Species.LARVITAR] + }), + [TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY], + [TrainerPoolTier.UNCOMMON]: [Species.PHANPY, Species.SWINUB, Species.GLIGAR, Species.TORKOAL, Species.BALTOY, Species.BARBOACH], + [TrainerPoolTier.RARE]: [Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA], + [TrainerPoolTier.SUPER_RARE]: [Species.TRAPINCH, Species.HEATMOR], + [TrainerPoolTier.ULTRA_RARE]: [Species.TURTONATOR, Species.CHARCADET] + }), + [TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH], + [TrainerPoolTier.UNCOMMON]: [Species.SPHEAL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL ], + [TrainerPoolTier.RARE]: [Species.CLAMPERL, Species.REMORAID, Species.ARROKUDA], + [TrainerPoolTier.SUPER_RARE]: [Species.MANTINE, Species.BASCULEGION], + [TrainerPoolTier.ULTRA_RARE]: [Species.DONDOZO] + }), + [TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE], + [TrainerPoolTier.UNCOMMON]: [Species.BRONZOR, Species.DRIFLOON, Species.BURMY], + [TrainerPoolTier.RARE]: [Species.CARNIVINE], + [TrainerPoolTier.SUPER_RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], + [TrainerPoolTier.ULTRA_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] + }), + [TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE], + [TrainerPoolTier.UNCOMMON]: [ Species.FRILLISH, Species.VENIPEDE, Species.SANDILE, Species.TRUBBISH, Species.GOLETT], + [TrainerPoolTier.RARE]: [Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS, Species.DRILBUR, Species.KLINK, Species.VULLABY], + [TrainerPoolTier.SUPER_RARE]: [Species.PAWNIARD, Species.VULLABY, Species.DRUDDIGON, Species.BOUFFALANT, Species.ZORUA], + [TrainerPoolTier.ULTRA_RARE]: [Species.AXEW, Species.DEINO, Species.DURANT] + }), + [TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI], + [TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN], + [TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL], + [TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN], + [TrainerPoolTier.ULTRA_RARE]: [] + }), + [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"],true, Type.ROCK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"],false, Type.WATER).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LT_SURGE"],true, Type.ELECTRIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ERIKA"],false, Type.GRASS).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JANINE"],false, Type.POISON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SABRINA"],false, Type.PSYCHIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BLAINE"],true, Type.FIRE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GIOVANNI"],true, Type.DARK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FALKNER"],true, Type.FLYING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BUGSY"],true, Type.BUG).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WHITNEY"],false, Type.NORMAL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MORTY"],true, Type.GHOST).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHUCK"],true, Type.FIGHTING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JASMINE"],false, Type.STEEL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PRYCE"],true, Type.ICE).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAIR"],false, Type.DRAGON).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXANNE"],false, Type.ROCK).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRAWLY"],true, Type.FIGHTING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WATTSON"],true, Type.ELECTRIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FLANNERY"],false, Type.FIRE).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["NORMAN"],true, Type.NORMAL).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WINONA"],false, Type.FLYING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TATE"],true, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("tate_liza_double").setDoubleTrainerType(TrainerType.LIZA).setDoubleTitle("gym_leader_double"), + [TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LIZA"],false, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("liza_tate_double").setDoubleTrainerType(TrainerType.TATE).setDoubleTitle("gym_leader_double"), + [TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JUAN"],true, Type.WATER).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROARK"],true, Type.ROCK).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GARDENIA"],false, Type.GRASS).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MAYLENE"],false, Type.FIGHTING).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRASHER_WAKE"],true, Type.WATER).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FANTINA"],false, Type.GHOST).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BYRON"],true, Type.STEEL).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CANDICE"],false, Type.ICE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VOLKNER"],true, Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CILAN"],true, Type.GRASS).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHILI"],true, Type.FIRE).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRESS"],true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHEREN"],true, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LENORA"],false, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXIE"],false, Type.POISON).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BURGH"],true, Type.BUG).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ELESA"],false, Type.ELECTRIC).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAY"],true, Type.GROUND).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SKYLA"],false, Type.FLYING).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRYCEN"],true, Type.ICE).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["DRAYDEN"],true, Type.DRAGON).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MARLON"],true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VIOLA"],false, Type.BUG).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRANT"],true, Type.ROCK).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KORRINA"],false, Type.FIGHTING).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RAMOS"],true, Type.GRASS).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLEMONT"],true, Type.ELECTRIC).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VALERIE"],false, Type.FAIRY).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OLYMPIA"],false, Type.PSYCHIC).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WULFRIC"],true, Type.ICE).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MILO"],true, Type.GRASS).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.NESSA]: new TrainerConfig(++t).setName("Nessa").initForGymLeader(signatureSpecies["NESSA"],false, Type.WATER).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KABU"],true, Type.FIRE).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.BEA]: new TrainerConfig(++t).setName("Bea").initForGymLeader(signatureSpecies["BEA"],false, Type.FIGHTING).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.ALLISTER]: new TrainerConfig(++t).setName("Allister").initForGymLeader(signatureSpecies["ALLISTER"],true, Type.GHOST).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OPAL"],false, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BEDE"],true, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GORDIE"],true, Type.ROCK).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MELONY"],false, Type.ICE).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"],true, Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), + [TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"],false, Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), + [TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"],true, Type.DRAGON).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"],false, Type.BUG).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"],true, Type.GRASS).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"],false, Type.ELECTRIC).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"],true, Type.WATER).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"],true, Type.NORMAL).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"],false, Type.GHOST).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"],false, Type.PSYCHIC).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"],true, Type.ICE).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"],false, Type.ICE), - [TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BRUNO"], true, Type.FIGHTING), - [TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AGATHA"], false,Type.GHOST), - [TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour(signatureSpecies["LANCE"],true, Type.DRAGON), - [TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WILL"],true, Type.PSYCHIC), - [TrainerType.KOGA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KOGA"], true, Type.POISON), - [TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAREN"],false, Type.DARK), - [TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIDNEY"],true, Type.DARK), - [TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["PHOEBE"],false, Type.GHOST), - [TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GLACIA"],false, Type.ICE), - [TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"],true, Type.DRAGON), - [TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"],true, Type.BUG), - [TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"],false, Type.GROUND), - [TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"],true, Type.FIRE), - [TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], true,Type.PSYCHIC), - [TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"],false, Type.GHOST), - [TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"],true, Type.FIGHTING), - [TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GRIMSLEY"],true, Type.DARK), - [TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CAITLIN"],false, Type.PSYCHIC), - [TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MALVA"], false,Type.FIRE), - [TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIEBOLD"], true,Type.WATER), - [TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WIKSTROM"],true, Type.STEEL), - [TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRASNA"],false, Type.DRAGON), - [TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HALA"],true, Type.FIGHTING), - [TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MOLAYNE"],true, Type.STEEL), - [TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["OLIVIA"],false, Type.ROCK), - [TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["ACEROLA"],false, Type.GHOST), - [TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAHILI"],false, Type.FLYING), - [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t).setName("Marnie").initForEliteFour(signatureSpecies["MARNIE_ELITE"],false, Type.DARK), - [TrainerType.NESSA_ELITE]: new TrainerConfig(++t).setName("Nessa").initForEliteFour(signatureSpecies["NESSA_ELITE"],false, Type.WATER), - [TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"],false, Type.FIGHTING), - [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"],true, Type.GHOST), - [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"],true, Type.DRAGON), - [TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"],false, Type.GROUND), - [TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"],false, Type.STEEL), - [TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"],true, Type.NORMAL, Type.FLYING), - [TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"],true, Type.DRAGON), - [TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"],true, Type.FIRE), - [TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"],false, Type.STEEL), - [TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"],false, Type.FAIRY), - [TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"],true, Type.DRAGON), + [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"],false, Type.ICE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BRUNO"], true, Type.FIGHTING).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AGATHA"], false,Type.GHOST).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour(signatureSpecies["LANCE"],true, Type.DRAGON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WILL"],true, Type.PSYCHIC).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.KOGA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KOGA"], true, Type.POISON).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAREN"],false, Type.DARK).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIDNEY"],true, Type.DARK).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["PHOEBE"],false, Type.GHOST).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GLACIA"],false, Type.ICE).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"],true, Type.DRAGON).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"],true, Type.BUG).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"],false, Type.GROUND).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"],true, Type.FIRE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], true,Type.PSYCHIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"],false, Type.GHOST).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"],true, Type.FIGHTING).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GRIMSLEY"],true, Type.DARK).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CAITLIN"],false, Type.PSYCHIC).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MALVA"], false,Type.FIRE).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIEBOLD"], true,Type.WATER).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WIKSTROM"],true, Type.STEEL).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRASNA"],false, Type.DRAGON).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HALA"],true, Type.FIGHTING).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MOLAYNE"],true, Type.STEEL).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["OLIVIA"],false, Type.ROCK).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["ACEROLA"],false, Type.GHOST).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAHILI"],false, Type.FLYING).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t).setName("Marnie").initForEliteFour(signatureSpecies["MARNIE_ELITE"],false, Type.DARK).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.NESSA_ELITE]: new TrainerConfig(++t).setName("Nessa").initForEliteFour(signatureSpecies["NESSA_ELITE"],false, Type.WATER).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"],false, Type.FIGHTING).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"],true, Type.GHOST).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"],true, Type.DRAGON).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"],false, Type.GROUND).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"],false, Type.STEEL).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"],true, Type.NORMAL, Type.FLYING).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"],true, Type.DRAGON).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"],true, Type.FIRE).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"],false, Type.STEEL).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"],false, Type.FAIRY).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"],true, Type.DRAGON).setMixedBattleBgm("battle_bb_elite"), - [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"],true).setBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double") + [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"],true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALAKAZAM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1221,7 +1356,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"],true).setBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double") + [TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"],true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PIKACHU], TrainerSlot.TRAINER, true, p => { p.formIndex = 8; p.generateAndPopulateMoveset(); @@ -1230,7 +1365,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"],true).setBattleBgm("battle_johto_champion") + [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"],true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.AERODACTYL], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1238,7 +1373,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"],true).setBattleBgm("battle_hoenn_champion").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") + [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"],true).setBattleBgm("battle_hoenn_champion").setMixedBattleBgm("battle_hoenn_champion").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1246,7 +1381,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"],true).setBattleBgm("battle_hoenn_champion").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double") + [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"],true).setBattleBgm("battle_hoenn_champion").setMixedBattleBgm("battle_hoenn_champion").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Drizzle p.generateAndPopulateMoveset(); @@ -1255,7 +1390,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"],false).setBattleBgm("battle_sinnoh_champion") + [TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"],false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SPIRITOMB], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1263,11 +1398,11 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"],true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder") + [TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"],true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BOUFFALANT, Species.BRAVIARY], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"],false).setBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double") + [TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"],false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRUDDIGON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1275,7 +1410,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"],false) + [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"],false).setMixedBattleBgm("battle_kalos_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GOURGEIST], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1283,11 +1418,11 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"],true) + [TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"],true).setMixedBattleBgm("battle_alola_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALOLA_RAICHU], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"],true) + [TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"],true).setMixedBattleBgm("battle_galar_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1295,35 +1430,35 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 3; p.generateAndPopulateMoveset(); })), - [TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"],false) + [TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"],false).setMixedBattleBgm("battle_champion_geeta") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GLIMMORA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"],false) + [TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"],false).setMixedBattleBgm("battle_champion_nemona") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { + p.formIndex = 0; // Midday form p.generateAndPopulateMoveset(); })), - [TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"],true) + [TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"],true).setMixedBattleBgm("battle_champion_kieran") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.POLIWRATH, Species.POLITOED], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - - [TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL) + [TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL) .setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE, Species.TREECKO, Species.TORCHIC, Species.MUDKIP, Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP, Species.SNIVY, Species.TEPIG, Species.OSHAWOTT, Species.CHESPIN, Species.FENNEKIN, Species.FROAKIE, Species.ROWLET, Species.LITTEN, Species.POPPLIO, Species.GROOKEY, Species.SCORBUNNY, Species.SOBBLE, Species.SPRIGATITO, Species.FUECOCO, Species.QUAXLY], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEY, Species.HOOTHOOT, Species.TAILLOW, Species.STARLY, Species.PIDOVE, Species.FLETCHLING, Species.PIKIPEK, Species.ROOKIDEE, Species.WATTREL], TrainerSlot.TRAINER, true)), - [TrainerType.RIVAL_2]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_2) + [TrainerType.RIVAL_2]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_2) .setModifierRewardFuncs(() => modifierTypes.EXP_SHARE) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.IVYSAUR, Species.CHARMELEON, Species.WARTORTLE, Species.BAYLEEF, Species.QUILAVA, Species.CROCONAW, Species.GROVYLE, Species.COMBUSKEN, Species.MARSHTOMP, Species.GROTLE, Species.MONFERNO, Species.PRINPLUP, Species.SERVINE, Species.PIGNITE, Species.DEWOTT, Species.QUILLADIN, Species.BRAIXEN, Species.FROGADIER, Species.DARTRIX, Species.TORRACAT, Species.BRIONNE, Species.THWACKEY, Species.RABOOT, Species.DRIZZILE, Species.FLORAGATO, Species.CROCALOR, Species.QUAXWELL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOTTO, Species.HOOTHOOT, Species.TAILLOW, Species.STARAVIA, Species.TRANQUILL, Species.FLETCHINDER, Species.TRUMBEAK, Species.CORVISQUIRE, Species.WATTREL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)), - [TrainerType.RIVAL_3]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_3) + [TrainerType.RIVAL_3]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_3) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540), - [TrainerType.RIVAL_4]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(1.75).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_2").setPartyTemplates(trainerPartyTemplates.RIVAL_4) + [TrainerType.RIVAL_4]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(1.75).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_2").setMixedBattleBgm("battle_rival_2").setPartyTemplates(trainerPartyTemplates.RIVAL_4) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) @@ -1332,7 +1467,7 @@ export const trainerConfigs: TrainerConfigs = { const starter = party[0]; return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; }), - [TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5) + [TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true, p => p.setBoss(true, 2))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL], TrainerSlot.TRAINER, true)) @@ -1348,7 +1483,7 @@ export const trainerConfigs: TrainerConfigs = { const starter = party[0]; return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; }), - [TrainerType.RIVAL_6]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm("final").setBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_6) + [TrainerType.RIVAL_6]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm("final").setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_6) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 3); @@ -1373,4 +1508,211 @@ export const trainerConfigs: TrainerConfigs = { const starter = party[0]; return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; }), + + [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN , Species.ALOLA_PERSIAN])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NIDOKING , Species.NIDOQUEEN ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RHYPERIOR ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.DUGTRIO, Species.ALOLA_DUGTRIO ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.MAROWAK , Species.ALOLA_MAROWAK])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.TYRANITAR , Species.IRON_THORNS], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.EXCADRILL ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HIPPOWDON ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GASTRODON])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEWTWO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIGHTYENA ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WEEZING, Species.GALAR_WEEZING ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MAGMORTAR, Species.TORKOAL ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.FLYGON])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GREAT_TUSK ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SHIFTRY, Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 0; // Chlorophyll + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TORKOAL, Species.NINETALES ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // DROUGHT + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LINOONE ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.PELIPPER ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MUK, Species.ALOLA_MUK ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TENTACRUEL ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.RELICANTH, Species.WAILORD ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.KINGDRA, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BEARTIC, Species.ARMALDO ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // Swift Swim + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.HUNTAIL, Species.GOREBYSS ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 0; // Swift Swim + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.POLITOED, Species.PELIPPER ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // Drizzle + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.BASCULEGION ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.OVERQWIL ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })), + [TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ELECTRODE, Species.HISUI_ELECTRODE ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.ROARING_MOON ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HISUI_ZOROARK ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })), + [TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS, Species.RUNERIGUS ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BOUFFALANT ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SEISMITOAD, Species.CARRACOSTA ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.EELEKTROSS, Species.GALVANTULA ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.VOLCARONA ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDREIGON ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })), + [TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SLITHER_WING, Species.IRON_MOTH ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DURANT ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DARMANITAN, Species.GALAR_DARMANITAN ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KINGAMBIT ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })), + [TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MILOTIC ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HELIOLISK ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), + [TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[]) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GHOLDENGO, Species.AEGISLASH ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + })), }; diff --git a/src/data/type.ts b/src/data/type.ts index b2bf8117249..c92416afca9 100644 --- a/src/data/type.ts +++ b/src/data/type.ts @@ -501,6 +501,52 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): } } +/** + * Retrieve the color corresponding to a specific damage multiplier + * @returns A color or undefined if the default color should be used + */ +export function getTypeDamageMultiplierColor(multiplier: TypeDamageMultiplier, side: "defense" | "offense"): string | undefined { + if (side === "offense") { + switch (multiplier) { + case 0: + return "#929292"; + case 0.125: + return "#FF5500"; + case 0.25: + return "#FF7400"; + case 0.5: + return "#FE8E00"; + case 1: + return undefined; + case 2: + return "#4AA500"; + case 4: + return "#4BB400"; + case 8: + return "#52C200"; + } + } else if (side === "defense") { + switch (multiplier) { + case 0: + return "#B1B100"; + case 0.125: + return "#2DB4FF"; + case 0.25: + return "#00A4FF"; + case 0.5: + return "#0093FF"; + case 1: + return undefined; + case 2: + return "#FE8E00"; + case 4: + return "#FF7400"; + case 8: + return "#FF5500"; + } + } +} + export function getTypeRgb(type: Type): [ integer, integer, integer ] { switch (type) { case Type.NORMAL: diff --git a/src/egg-hatch-phase.ts b/src/egg-hatch-phase.ts index 320b768e1e5..b86e7a9f2ca 100644 --- a/src/egg-hatch-phase.ts +++ b/src/egg-hatch-phase.ts @@ -12,7 +12,8 @@ import { achvs } from "./system/achv"; import { pokemonPrevolutions } from "./data/pokemon-evolutions"; import { EggTier } from "./data/enums/egg-type"; import PokemonInfoContainer from "./ui/pokemon-info-container"; -import EggsToHatchCountContainer from "./ui/eggs-to-hatch-count-container"; +import EggCounterContainer from "./ui/egg-counter-container"; +import { EggCountChangedEvent } from "./events/egg"; /** * Class that represents egg hatching @@ -24,7 +25,7 @@ export class EggHatchPhase extends Phase { /** The number of eggs that are hatching */ private eggsToHatchCount: integer; /** The container that lists how many eggs are hatching */ - private eggsToHatchCountContainer: EggsToHatchCountContainer; + private eggCounterContainer: EggCounterContainer; /** The scene handler for egg hatching */ private eggHatchHandler: EggHatchSceneHandler; @@ -110,10 +111,8 @@ export class EggHatchPhase extends Phase { this.eggContainer.add(this.eggLightraysOverlay); this.eggHatchContainer.add(this.eggContainer); - this.eggsToHatchCountContainer = new EggsToHatchCountContainer(this.scene, this.eggsToHatchCount); - this.eggsToHatchCountContainer.setup(); - - this.eggHatchContainer.add(this.eggsToHatchCountContainer); + this.eggCounterContainer = new EggCounterContainer(this.scene, this.eggsToHatchCount); + this.eggHatchContainer.add(this.eggCounterContainer); const getPokemonSprite = () => { const ret = this.scene.add.sprite(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2, "pkmn__sub"); @@ -308,13 +307,6 @@ export class EggHatchPhase extends Phase { * Function to do the logic and animation of completing a hatch and revealing the Pokemon */ doReveal(): void { - // Update/reduce count of hatching eggs when revealed if count is at least 1 - // If count is 0, hide eggsToHatchCountContainer instead - if (this.eggsToHatchCount > 1) { - this.eggsToHatchCount -= 1; - } else { - this.eggsToHatchCountContainer.setVisible(false); - } const isShiny = this.pokemon.isShiny(); if (this.pokemon.species.subLegendary) { this.scene.validateAchv(achvs.HATCH_SUB_LEGENDARY); @@ -336,10 +328,8 @@ export class EggHatchPhase extends Phase { this.pokemonSprite.setPipelineData("variant", this.pokemon.variant); this.pokemonSprite.setVisible(true); this.scene.time.delayedCall(Utils.fixedInt(250), () => { - if (this.eggsToHatchCount < 10) { - this.eggsToHatchCountContainer.setWindowToDefaultSize(); - } - this.eggsToHatchCountContainer.eggCountText.setText(`${this.eggsToHatchCount}`); + this.eggsToHatchCount--; + this.eggHatchHandler.eventTarget.dispatchEvent(new EggCountChangedEvent(this.eggsToHatchCount)); this.pokemon.cry(); if (isShiny) { this.scene.time.delayedCall(Utils.fixedInt(500), () => { diff --git a/src/battle-scene-events.ts b/src/events/battle-scene.ts similarity index 95% rename from src/battle-scene-events.ts rename to src/events/battle-scene.ts index aaeb590f8ba..b2e4461f8d0 100644 --- a/src/battle-scene-events.ts +++ b/src/events/battle-scene.ts @@ -1,5 +1,5 @@ -import Move from "./data/move"; -import { BerryModifier } from "./modifier/modifier"; +import Move from "../data/move"; +import { BerryModifier } from "../modifier/modifier"; /** Alias for all {@linkcode BattleScene} events */ export enum BattleSceneEventType { @@ -7,7 +7,7 @@ export enum BattleSceneEventType { * Triggers when the corresponding setting is changed * @see {@linkcode CandyUpgradeNotificationChangedEvent} */ - CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeDisplayChanged", + CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeNotificationChanged", /** * Triggers when a move is successfully used diff --git a/src/events/egg.ts b/src/events/egg.ts new file mode 100644 index 00000000000..b30c37a25e8 --- /dev/null +++ b/src/events/egg.ts @@ -0,0 +1,21 @@ +export enum EggEventType { + /** + * Triggers when egg count is changed. + * @see {@linkcode MoveUsedEvent} + */ + EGG_COUNT_CHANGED = "onEggCountChanged" +} + +/** + * Container class for {@linkcode EggEventType.EGG_COUNT_CHANGED} events + * @extends Event +*/ +export class EggCountChangedEvent extends Event { + /** The updated egg count. */ + public eggCount: integer; + + constructor(eggCount: number) { + super(EggEventType.EGG_COUNT_CHANGED); + this.eggCount = eggCount; + } +} diff --git a/src/evolution-phase.ts b/src/evolution-phase.ts index 29382807ccb..c7986f6664f 100644 --- a/src/evolution-phase.ts +++ b/src/evolution-phase.ts @@ -531,6 +531,11 @@ export class EvolutionPhase extends Phase { } export class EndEvolutionPhase extends Phase { + + constructor(scene: BattleScene) { + super(scene); + } + start() { super.start(); diff --git a/src/field/arena.ts b/src/field/arena.ts index d34cd2c9bea..0cdf27b7983 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -19,7 +19,7 @@ import { Terrain, TerrainType } from "../data/terrain"; import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability"; import Pokemon from "./pokemon"; import * as Overrides from "../overrides"; -import { WeatherChangedEvent, TerrainChangedEvent, TagAddedEvent, TagRemovedEvent } from "./arena-events"; +import { WeatherChangedEvent, TerrainChangedEvent, TagAddedEvent, TagRemovedEvent } from "./events/arena"; export class Arena { public scene: BattleScene; diff --git a/src/field/arena-events.ts b/src/field/events/arena.ts similarity index 100% rename from src/field/arena-events.ts rename to src/field/events/arena.ts diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index ff277fc865b..7bf3c8ca52d 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -27,7 +27,7 @@ import { TempBattleStat } from "../data/temp-battle-stat"; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag"; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Ability, AbAttr, BattleStatMultiplierAbAttr, MoveTypeChangeAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr } from "../data/ability"; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr } from "../data/ability"; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from "../system/pokemon-data"; import { BattlerIndex } from "../battle"; @@ -48,6 +48,7 @@ import { BerryType } from "../data/enums/berry-type"; import i18next from "../plugins/i18n"; import { speciesEggMoves } from "../data/egg-moves"; import { ModifierTier } from "../modifier/modifier-tier"; +import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; export enum FieldPosition { CENTER, @@ -266,11 +267,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return !this.hp && (!checkStatus || this.status?.effect === StatusEffect.FAINT); } + /** + * Check if this pokemon is both not fainted and allowed to be in battle. + * This is frequently a better alternative to {@link isFainted} + * @returns {boolean} True if pokemon is allowed in battle + */ + isAllowedInBattle(): boolean { + const challengeAllowed = new Utils.BooleanHolder(true); + applyChallenges(this.scene.gameMode, ChallengeType.POKEMON_IN_BATTLE, this, challengeAllowed); + return !this.isFainted() && challengeAllowed.value; + } + isActive(onField?: boolean): boolean { if (!this.scene) { return false; } - return !this.isFainted() && !!this.scene && (!onField || this.isOnField()); + return this.isAllowedInBattle() && !!this.scene && (!onField || this.isOnField()); } getDexAttr(): bigint { @@ -644,6 +656,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), battleStat as integer as TempBattleStat, statLevel); } const statValue = new Utils.NumberHolder(this.getStat(stat)); + const fieldApplied = new Utils.BooleanHolder(false); + for (const pokemon of this.scene.getField(true)) { + applyFieldBattleStatMultiplierAbAttrs(FieldMultiplyBattleStatAbAttr, pokemon, stat, statValue, this, fieldApplied); + if (fieldApplied.value) { + break; + } + } applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, battleStat, statValue); let ret = statValue.value * (Math.max(2, 2 + statLevel.value) / Math.max(2, 2 - statLevel.value)); switch (stat) { @@ -845,11 +864,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!ignoreOverride && this.summonData?.types) { this.summonData.types.forEach(t => types.push(t)); } else { - const speciesForm = this.getSpeciesForm(); + const speciesForm = this.getSpeciesForm(ignoreOverride); types.push(speciesForm.type1); - const fusionSpeciesForm = this.getFusionSpeciesForm(); + const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride); if (fusionSpeciesForm) { if (fusionSpeciesForm.type2 !== null && fusionSpeciesForm.type2 !== speciesForm.type1) { types.push(fusionSpeciesForm.type2); @@ -885,8 +904,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return types; } - isOfType(type: Type, forDefend: boolean = false): boolean { - return !!this.getTypes(true, forDefend).find(t => t === type); + isOfType(type: Type, includeTeraType: boolean = true, forDefend: boolean = false, ignoreOverride?: boolean): boolean { + return !!this.getTypes(includeTeraType, forDefend, ignoreOverride).some(t => t === type); } /** @@ -939,6 +958,29 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return allAbilities[starterPassiveAbilities[starterSpeciesId]]; } + /** + * Gets a list of all instances of a given ability attribute among abilities this pokemon has. + * Accounts for all the various effects which can affect whether an ability will be present or + * in effect, and both passive and non-passive. + * @param attrType {@linkcode AbAttr} The ability attribute to check for. + * @param canApply {@linkcode Boolean} If false, it doesn't check whether the ability is currently active + * @param ignoreOverride {@linkcode Boolean} If true, it ignores ability changing effects + * @returns {AbAttr[]} A list of all the ability attributes on this ability. + */ + getAbilityAttrs(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): AbAttr[] { + const abilityAttrs: AbAttr[] = []; + + if (!canApply || this.canApplyAbility()) { + abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs(attrType)); + } + + if (!canApply || this.canApplyAbility(true)) { + abilityAttrs.push(...this.getPassiveAbility().getAttrs(attrType)); + } + + return abilityAttrs; + } + /** * Checks if a pokemon has a passive either from: * - bought with starter candy @@ -1054,18 +1096,42 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } isGrounded(): boolean { - return !this.isOfType(Type.FLYING, true) && !this.hasAbility(Abilities.LEVITATE); + return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE); } - getAttackMoveEffectiveness(source: Pokemon, pokemonMove: PokemonMove): TypeDamageMultiplier { + /** + * Calculates the effectiveness of a move against the Pokémon. + * + * @param source - The Pokémon using the move. + * @param move - The move being used. + * @returns The type damage multiplier or undefined if it's a status move + */ + getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined { + if (move.getMove().category === MoveCategory.STATUS) { + return undefined; + } + + return this.getAttackMoveEffectiveness(source, move, true); + } + + /** + * Calculates the effectiveness of an attack move against the Pokémon. + * + * @param source - The attacking Pokémon. + * @param pokemonMove - The move being used by the attacking Pokémon. + * @param ignoreAbility - Whether to check for abilities that might affect type effectiveness or immunity. + * @returns The type damage multiplier, indicating the effectiveness of the move + */ + getAttackMoveEffectiveness(source: Pokemon, pokemonMove: PokemonMove, ignoreAbility: boolean = false): TypeDamageMultiplier { const move = pokemonMove.getMove(); const typeless = move.hasAttr(TypelessAttr); const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.type, source)); const cancelled = new Utils.BooleanHolder(false); - if (!typeless) { + applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier); + if (!typeless && !ignoreAbility) { applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); } - if (!cancelled.value) { + if (!cancelled.value && !ignoreAbility) { applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); } return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier; @@ -1576,11 +1642,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + this.battleInfo.updateEffectiveness(effectiveness); + } + toggleStats(visible: boolean): void { this.battleInfo.toggleStats(visible); } + toggleFlyout(visible: boolean): void { - this.battleInfo.flyoutMenu?.toggleFlyout(visible); + this.battleInfo.toggleFlyout(visible); } addExp(exp: integer) { diff --git a/src/field/trainer.ts b/src/field/trainer.ts index fb85bfbe8b7..1646866189b 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -122,6 +122,14 @@ export default class Trainer extends Phaser.GameObjects.Container { // Determine the title to include based on the configuration and includeTitle flag. let title = includeTitle && this.config.title ? this.config.title : null; + if (this.name === "" && name.toLowerCase().includes("grunt")) { + // This is a evil team grunt so we localize it by only using the "name" as the title + title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`); + console.log("Localized grunt name: " + title); + // Since grunts are not named we can just return the title + return title; + } + // If the trainer has a name (not null or undefined). if (this.name) { // If the title should be included. @@ -166,6 +174,10 @@ export default class Trainer extends Phaser.GameObjects.Container { return this.config.doubleOnly || this.variant === TrainerVariant.DOUBLE; } + getMixedBattleBgm(): string { + return this.config.mixedBattleBgm; + } + getBattleBgm(): string { return this.config.battleBgm; } diff --git a/src/game-mode.ts b/src/game-mode.ts index 4d46971dcb5..cb042b2757c 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -1,17 +1,20 @@ -import { fixedBattles } from "./battle"; +import i18next from "i18next"; +import { classicFixedBattles, FixedBattleConfig, FixedBattleConfigs } from "./battle"; import BattleScene from "./battle-scene"; +import { allChallenges, applyChallenges, Challenge, ChallengeType, copyChallenge } from "./data/challenge"; import { Biome } from "./data/enums/biome"; import { Species } from "./data/enums/species"; import PokemonSpecies, { allSpecies } from "./data/pokemon-species"; import { Arena } from "./field/arena"; -import * as Utils from "./utils"; import * as Overrides from "./overrides"; +import * as Utils from "./utils"; export enum GameModes { CLASSIC, ENDLESS, SPLICED_ENDLESS, - DAILY + DAILY, + CHALLENGE } interface GameModeConfig { @@ -19,12 +22,12 @@ interface GameModeConfig { isEndless?: boolean; isDaily?: boolean; hasTrainers?: boolean; - hasFixedBattles?: boolean; hasNoShop?: boolean; hasShortBiomes?: boolean; hasRandomBiomes?: boolean; hasRandomBosses?: boolean; isSplicedOnly?: boolean; + isChallenge?: boolean; } export class GameMode implements GameModeConfig { @@ -33,16 +36,23 @@ export class GameMode implements GameModeConfig { public isEndless: boolean; public isDaily: boolean; public hasTrainers: boolean; - public hasFixedBattles: boolean; public hasNoShop: boolean; public hasShortBiomes: boolean; public hasRandomBiomes: boolean; public hasRandomBosses: boolean; public isSplicedOnly: boolean; + public isChallenge: boolean; + public challenges: Challenge[]; + public battleConfig: FixedBattleConfigs; - constructor(modeId: GameModes, config: GameModeConfig) { + constructor(modeId: GameModes, config: GameModeConfig, battleConfig?: FixedBattleConfigs) { this.modeId = modeId; + this.challenges = []; Object.assign(this, config); + if (this.isChallenge) { + this.challenges = allChallenges.map(c => copyChallenge(c)); + } + this.battleConfig = battleConfig || {}; } /** @@ -112,7 +122,7 @@ export class GameMode implements GameModeConfig { if (w === waveIndex) { continue; } - if ((w % 30) === (arena.scene.offsetGym ? 0 : 20) || fixedBattles.hasOwnProperty(w)) { + if ((w % 30) === (arena.scene.offsetGym ? 0 : 20) || this.isFixedBattle(waveIndex)) { allowTrainerBattle = false; break; } else if (w < waveIndex) { @@ -161,6 +171,7 @@ export class GameMode implements GameModeConfig { isWaveFinal(waveIndex: integer, modeId: GameModes = this.modeId): boolean { switch (modeId) { case GameModes.CLASSIC: + case GameModes.CHALLENGE: return waveIndex === 200; case GameModes.ENDLESS: case GameModes.SPLICED_ENDLESS: @@ -208,10 +219,36 @@ export class GameMode implements GameModeConfig { (this.modeId === GameModes.ENDLESS || this.modeId === GameModes.SPLICED_ENDLESS); } + /** + * Checks whether there is a fixed battle on this gamemode on a given wave. + * @param {integer} waveIndex The wave to check. + * @returns {boolean} If this game mode has a fixed battle on this wave + */ + isFixedBattle(waveIndex: integer): boolean { + const dummyConfig = new FixedBattleConfig(); + return this.battleConfig.hasOwnProperty(waveIndex) || applyChallenges(this, ChallengeType.FIXED_BATTLES, waveIndex, dummyConfig); + + } + + /** + * Returns the config for the fixed battle for a particular wave. + * @param {integer} waveIndex The wave to check. + * @returns {boolean} The fixed battle for this wave. + */ + getFixedBattle(waveIndex: integer): FixedBattleConfig { + const challengeConfig = new FixedBattleConfig(); + if (applyChallenges(this, ChallengeType.FIXED_BATTLES, waveIndex, challengeConfig)) { + return challengeConfig; + } else { + return this.battleConfig[waveIndex]; + } + } + getClearScoreBonus(): integer { switch (this.modeId) { case GameModes.CLASSIC: + case GameModes.CHALLENGE: return 5000; case GameModes.DAILY: return 2500; @@ -221,6 +258,7 @@ export class GameMode implements GameModeConfig { getEnemyModifierChance(isBoss: boolean): integer { switch (this.modeId) { case GameModes.CLASSIC: + case GameModes.CHALLENGE: case GameModes.DAILY: return !isBoss ? 18 : 6; case GameModes.ENDLESS: @@ -232,20 +270,45 @@ export class GameMode implements GameModeConfig { getName(): string { switch (this.modeId) { case GameModes.CLASSIC: - return "Classic"; + return i18next.t("gameMode:classic"); case GameModes.ENDLESS: - return "Endless"; + return i18next.t("gameMode:endless"); case GameModes.SPLICED_ENDLESS: - return "Endless (Spliced)"; + return i18next.t("gameMode:endlessSpliced"); case GameModes.DAILY: - return "Daily Run"; + return i18next.t("gameMode:dailyRun"); + case GameModes.CHALLENGE: + return i18next.t("gameMode:challenge"); + } + } + + static getModeName(modeId: GameModes): string { + switch (modeId) { + case GameModes.CLASSIC: + return i18next.t("gameMode:classic"); + case GameModes.ENDLESS: + return i18next.t("gameMode:endless"); + case GameModes.SPLICED_ENDLESS: + return i18next.t("gameMode:endlessSpliced"); + case GameModes.DAILY: + return i18next.t("gameMode:dailyRun"); + case GameModes.CHALLENGE: + return i18next.t("gameMode:challenge"); } } } -export const gameModes = Object.freeze({ - [GameModes.CLASSIC]: new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true, hasFixedBattles: true }), - [GameModes.ENDLESS]: new GameMode(GameModes.ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true }), - [GameModes.SPLICED_ENDLESS]: new GameMode(GameModes.SPLICED_ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true, isSplicedOnly: true }), - [GameModes.DAILY]: new GameMode(GameModes.DAILY, { isDaily: true, hasTrainers: true, hasNoShop: true }) -}); +export function getGameMode(gameMode: GameModes): GameMode { + switch (gameMode) { + case GameModes.CLASSIC: + return new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true }, classicFixedBattles); + case GameModes.ENDLESS: + return new GameMode(GameModes.ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true }); + case GameModes.SPLICED_ENDLESS: + return new GameMode(GameModes.SPLICED_ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true, isSplicedOnly: true }); + case GameModes.DAILY: + return new GameMode(GameModes.DAILY, { isDaily: true, hasTrainers: true, hasNoShop: true }); + case GameModes.CHALLENGE: + return new GameMode(GameModes.CHALLENGE, { isClassic: true, hasTrainers: true, isChallenge: true }, classicFixedBattles); + } +} diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index 3ef8fa24115..1f10197903c 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -1,7 +1,6 @@ import Phaser from "phaser"; import * as Utils from "./utils"; import {deepCopy} from "./utils"; -import {initTouchControls} from "./touch-controls"; import pad_generic from "./configs/inputs/pad_generic"; import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES"; import pad_xbox360 from "./configs/inputs/pad_xbox360"; @@ -21,6 +20,7 @@ import { import BattleScene from "./battle-scene"; import {SettingGamepad} from "#app/system/settings/settings-gamepad.js"; import {SettingKeyboard} from "#app/system/settings/settings-keyboard"; +import TouchControl from "#app/touch-controls"; export interface DeviceMapping { [key: string]: number; @@ -48,7 +48,7 @@ export interface InterfaceConfig { custom?: MappingLayout; } -const repeatInputDelayMillis = 500; +const repeatInputDelayMillis = 250; // Phaser.Input.Gamepad.GamepadPlugin#refreshPads declare module "phaser" { @@ -92,7 +92,7 @@ export class InputsController { private scene: BattleScene; public events: Phaser.Events.EventEmitter; - private buttonLock: Button; + private buttonLock: Button[] = new Array(); private interactions: Map> = new Map(); private configs: Map = new Map(); @@ -101,10 +101,10 @@ export class InputsController { private disconnectedGamepads: Array = new Array(); - private pauseUpdate: boolean = false; public lastSource: string = "keyboard"; - private keys: Array = []; + private inputInterval: NodeJS.Timeout[] = new Array(); + private touchControls: TouchControl; /** * Initializes a new instance of the game control system, setting up initial state and configurations. @@ -181,7 +181,7 @@ export class InputsController { this.scene.input.keyboard.on("keydown", this.keyboardKeyDown, this); this.scene.input.keyboard.on("keyup", this.keyboardKeyUp, this); } - initTouchControls(this.events); + this.touchControls = new TouchControl(this.scene); } /** @@ -192,6 +192,7 @@ export class InputsController { */ loseFocus(): void { this.deactivatePressedKey(); + this.touchControls.deactivatePressedKey(); } /** @@ -232,47 +233,6 @@ export class InputsController { this.initChosenLayoutKeyboard(layoutKeyboard); } - /** - * Updates the interaction handling by processing input states. - * This method gives priority to certain buttons by reversing the order in which they are checked. - * This method loops through all button values, checks for valid and timely interactions, and conditionally processes - * or ignores them based on the current state of gamepad support and other criteria. - * - * It handles special conditions such as the absence of gamepad support or mismatches between the source of the input and - * the currently chosen gamepad. It also respects the paused state of updates to prevent unwanted input processing. - * - * If an interaction is valid and should be processed, it emits an 'input_down' event with details of the interaction. - */ - update(): void { - if (this.pauseUpdate) { - return; - } - for (const b of Utils.getEnumValues(Button).reverse()) { - if ( - this.interactions.hasOwnProperty(b) && - this.repeatInputDurationJustPassed(b as Button) && - this.interactions[b].isPressed - ) { - // Prevents repeating button interactions when gamepad support is disabled. - if ( - (!this.gamepadSupport && this.interactions[b].source === "gamepad") || - (this.interactions[b].source === "gamepad" && this.interactions[b].sourceName && this.interactions[b].sourceName !== this.selectedDevice[Device.GAMEPAD]) || - (this.interactions[b].source === "keyboard" && this.interactions[b].sourceName && this.interactions[b].sourceName !== this.selectedDevice[Device.KEYBOARD]) - ) { - // Deletes the last interaction for a button if gamepad is disabled. - this.delLastProcessedMovementTime(b as Button); - return; - } - // Emits an event for the button press. - this.events.emit("input_down", { - controller_type: this.interactions[b].source, - button: b, - }); - this.setLastProcessedMovementTime(b as Button, this.interactions[b].source, this.interactions[b].sourceName); - } - } - } - /** * Retrieves the identifiers of all connected gamepads, excluding any that are currently marked as disconnected. * @returns Array An array of strings representing the IDs of the connected gamepads. @@ -404,19 +364,24 @@ export class InputsController { */ keyboardKeyDown(event): void { this.lastSource = "keyboard"; - const keyDown = event.keyCode; this.ensureKeyboardIsInit(); - if (this.keys.includes(keyDown)) { - return; - } - this.keys.push(keyDown); - const buttonDown = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), keyDown); + const buttonDown = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), event.keyCode); if (buttonDown !== undefined) { + if (this.buttonLock.includes(buttonDown)) { + return; + } this.events.emit("input_down", { controller_type: "keyboard", button: buttonDown, }); - this.setLastProcessedMovementTime(buttonDown, "keyboard", this.selectedDevice[Device.KEYBOARD]); + clearInterval(this.inputInterval[buttonDown]); + this.inputInterval[buttonDown] = setInterval(() => { + this.events.emit("input_down", { + controller_type: "keyboard", + button: buttonDown, + }); + }, repeatInputDelayMillis); + this.buttonLock.push(buttonDown); } } @@ -427,16 +392,15 @@ export class InputsController { */ keyboardKeyUp(event): void { this.lastSource = "keyboard"; - const keyDown = event.keyCode; - this.keys = this.keys.filter(k => k !== keyDown); - this.ensureKeyboardIsInit(); - const buttonUp = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), keyDown); + const buttonUp = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), event.keyCode); if (buttonUp !== undefined) { this.events.emit("input_up", { controller_type: "keyboard", button: buttonUp, }); - this.delLastProcessedMovementTime(buttonUp); + const index = this.buttonLock.indexOf(buttonUp); + this.buttonLock.splice(index, 1); + clearInterval(this.inputInterval[buttonUp]); } } @@ -466,11 +430,25 @@ export class InputsController { const activeConfig = this.getActiveConfig(Device.GAMEPAD); const buttonDown = activeConfig && getButtonWithKeycode(activeConfig, button.index); if (buttonDown !== undefined) { + if (this.buttonLock.includes(buttonDown)) { + return; + } this.events.emit("input_down", { controller_type: "gamepad", button: buttonDown, }); - this.setLastProcessedMovementTime(buttonDown, "gamepad", pad.id); + clearInterval(this.inputInterval[buttonDown]); + this.inputInterval[buttonDown] = setInterval(() => { + if (!this.buttonLock.includes(buttonDown)) { + clearInterval(this.inputInterval[buttonDown]); + return; + } + this.events.emit("input_down", { + controller_type: "gamepad", + button: buttonDown, + }); + }, repeatInputDelayMillis); + this.buttonLock.push(buttonDown); } } @@ -497,7 +475,9 @@ export class InputsController { controller_type: "gamepad", button: buttonUp, }); - this.delLastProcessedMovementTime(buttonUp); + const index = this.buttonLock.indexOf(buttonUp); + this.buttonLock.splice(index, 1); + clearInterval(this.inputInterval[buttonUp]); } } @@ -540,144 +520,13 @@ export class InputsController { } /** - * repeatInputDurationJustPassed returns true if @param button has been held down long - * enough to fire a repeated input. A button must claim the buttonLock before - * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. - */ - repeatInputDurationJustPassed(button: Button): boolean { - if (!this.isButtonLocked(button)) { - return false; - } - const duration = Date.now() - this.interactions[button].pressTime; - if (duration >= repeatInputDelayMillis) { - return true; - } - } - - /** - * This method updates the interaction state to reflect that the button is pressed. - * - * @param button - The button for which to set the interaction. - * @param source - The source of the input (defaults to 'keyboard'). This helps identify the origin of the input, especially useful in environments with multiple input devices. - * - * @remarks - * This method is responsible for updating the interaction state of a button within the `interactions` dictionary. If the button is not already registered, this method returns immediately. - * When invoked, it performs the following updates: - * - `pressTime`: Sets this to the current time, representing when the button was initially pressed. - * - `isPressed`: Marks the button as currently being pressed. - * - `source`: Identifies the source device of the input, which can vary across different hardware (e.g., keyboard, gamepad). - * - * Additionally, this method locks the button (by calling `setButtonLock`) to prevent it from being re-processed until it is released, ensuring that each press is handled distinctly. - */ - setLastProcessedMovementTime(button: Button, source: String = "keyboard", sourceName?: String): void { - if (!this.interactions.hasOwnProperty(button)) { - return; - } - this.setButtonLock(button); - this.interactions[button].pressTime = Date.now(); - this.interactions[button].isPressed = true; - this.interactions[button].source = source; - this.interactions[button].sourceName = sourceName.toLowerCase(); - } - - /** - * Clears the last interaction for a specified button. - * - * @param button - The button for which to clear the interaction. - * - * @remarks - * This method resets the interaction details of the button, allowing it to be processed as a new input when pressed again. - * If the button is not registered in the `interactions` dictionary, this method returns immediately, otherwise: - * - `pressTime` is cleared. This was previously storing the timestamp of when the button was initially pressed. - * - `isPressed` is set to false, indicating that the button is no longer being pressed. - * - `source` is set to null, which had been indicating the device from which the button input was originating. - * - * It releases the button lock, which prevents the button from being processed repeatedly until it's explicitly released. - */ - delLastProcessedMovementTime(button: Button): void { - if (!this.interactions.hasOwnProperty(button)) { - return; - } - this.releaseButtonLock(button); - this.interactions[button].pressTime = null; - this.interactions[button].isPressed = false; - this.interactions[button].source = null; - this.interactions[button].sourceName = null; - } - - /** - * Deactivates all currently pressed keys and resets their interaction states. - * - * @remarks - * This method is used to reset the state of all buttons within the `interactions` dictionary, - * effectively deactivating any currently pressed keys. It performs the following actions: - * - * - Releases button lock for predefined buttons, allowing them - * to be pressed again or properly re-initialized in future interactions. - * - Iterates over all possible button values obtained via `Utils.getEnumValues(Button)`, and for - * each button: - * - Checks if the button is currently registered in the `interactions` dictionary. - * - Resets `pressTime` to null, indicating that there is no ongoing interaction. - * - Sets `isPressed` to false, marking the button as not currently active. - * - Clears the `source` field, removing the record of which device the button press came from. - * - * This method is typically called when needing to ensure that all inputs are neutralized. + * Deactivates all currently pressed keys. */ deactivatePressedKey(): void { - this.pauseUpdate = true; - this.releaseButtonLock(this.buttonLock); - for (const b of Utils.getEnumValues(Button)) { - if (this.interactions.hasOwnProperty(b)) { - this.interactions[b].pressTime = null; - this.interactions[b].isPressed = false; - this.interactions[b].source = null; - this.interactions[b].sourceName = null; - } - } - this.pauseUpdate = false; - } - - /** - * Checks if a specific button is currently locked. - * - * @param button - The button to check for a lock status. - * @returns `true` if the button is locked, otherwise `false`. - * - * @remarks - * This method is used to determine if a given button is currently prevented from being processed due to a lock. - * It checks against two separate lock variables, allowing for up to two buttons to be locked simultaneously. - */ - isButtonLocked(button: Button): boolean { - return this.buttonLock === button; - } - - /** - * Sets a lock on a given button. - * - * @param button - The button to lock. - * - * @remarks - * This method ensures that a button is not processed multiple times inadvertently. - * It checks if the button is already locked. - */ - setButtonLock(button: Button): void { - this.buttonLock = button; - } - - /** - * Releases a lock on a specific button, allowing it to be processed again. - * - * @param button - The button whose lock is to be released. - * - * @remarks - * This method checks lock variable. - * If either lock matches the specified button, that lock is cleared. - * This action frees the button to be processed again, ensuring it can respond to new inputs. - */ - releaseButtonLock(button: Button): void { - if (this.buttonLock === button) { - this.buttonLock = null; + for (const key of Object.keys(this.inputInterval)) { + clearInterval(this.inputInterval[key]); } + this.buttonLock = []; } /** @@ -751,8 +600,7 @@ export class InputsController { * @param pressedButton The button that was pressed. */ assignBinding(config, settingName, pressedButton): boolean { - this.pauseUpdate = true; - setTimeout(() => this.pauseUpdate = false, 500); + this.deactivatePressedKey(); if (config.padType === "keyboard") { return assign(config, settingName, pressedButton); } else { diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 8bb811e3d9b..7a097cc8b37 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -18,8 +18,10 @@ import {initMoves} from "#app/data/move"; import {initAbilities} from "#app/data/ability"; import {initAchievements} from "#app/system/achv"; import {initTrainerTypeDialogue} from "#app/data/dialogue"; +import { initChallenges } from "./data/challenge"; import i18next from "i18next"; import { initStatsKeys } from "./ui/game-stats-ui-handler"; +import { initVouchers } from "./system/voucher"; export class LoadingScene extends SceneBase { constructor() { @@ -329,6 +331,7 @@ export class LoadingScene extends SceneBase { this.loadLoadingScreen(); + initVouchers(); initAchievements(); initStatsKeys(); initPokemonPrevolutions(); @@ -339,6 +342,7 @@ export class LoadingScene extends SceneBase { initSpecies(); initMoves(); initAbilities(); + initChallenges(); } loadLoadingScreen() { @@ -432,7 +436,7 @@ export class LoadingScene extends SceneBase { }); this.load.on("fileprogress", file => { - assetText.setText(`Loading asset: ${file.key}`); + assetText.setText(i18next.t("menu:loadingAsset", { assetName: file.key })); }); loadingGraphics.push(bg, graphics, progressBar, progressBox, logo, percentText, assetText); diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts index d3fbdfc1b77..652c16eb662 100644 --- a/src/locales/de/ability-trigger.ts +++ b/src/locales/de/ability-trigger.ts @@ -3,6 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!", "badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!", - "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!", - "iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!" + "windPowerCharged": "Der Treffer durch {{moveName}} läd die Stärke von {{pokemonName}} auf!", + "iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!", } as const; diff --git a/src/locales/de/achv.ts b/src/locales/de/achv.ts index 42f2b2cf86c..64721e48af6 100644 --- a/src/locales/de/achv.ts +++ b/src/locales/de/achv.ts @@ -1,6 +1,7 @@ -import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; +import {AchievementTranslationEntries} from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Errungenschaften", }, @@ -10,7 +11,7 @@ export const achv: AchievementTranslationEntries = { "MoneyAchv": { - description:"Häufe eine Gesamtsumme von {{moneyAmount}} ₽ an", + description: "Häufe eine Gesamtsumme von {{moneyAmount}} ₽ an.", }, "10K_MONEY": { name: "Besserverdiener", @@ -26,7 +27,7 @@ export const achv: AchievementTranslationEntries = { }, "DamageAchv": { - description: "Füge mit einem Treffer {{damageAmount}} Schaden zu", + description: "Füge mit einem Treffer {{damageAmount}} Schaden zu.", }, "250_DMG": { name: "Harte Treffer", @@ -42,7 +43,7 @@ export const achv: AchievementTranslationEntries = { }, "HealAchv": { - description: "Heile {{healAmount}} {{HP}} auf einmal. Mit einer Attacke, Fähigkeit oder einem gehaltenen Gegenstand", + description: "Heile {{healAmount}} {{HP}} auf einmal. Mit einer Attacke, Fähigkeit oder einem gehaltenen Gegenstand.", }, "250_HEAL": { name: "Anfänger-Heiler", @@ -58,7 +59,7 @@ export const achv: AchievementTranslationEntries = { }, "LevelAchv": { - description: "Erhöhe das Level eines Pokémon auf {{level}}", + description: "Erhöhe das Level eines Pokémon auf {{level}}.", }, "LV_100": { name: "Warte, es gibt mehr!", @@ -67,14 +68,14 @@ export const achv: AchievementTranslationEntries = { name: "Elite", }, "LV_1000": { - name: "Geh noch höher hinaus!", + name: "Geh noch höher hinaus!", }, "RibbonAchv": { - description: "Sammle insgesamt {{ribbonAmount}} Bänder", + description: "Sammle insgesamt {{ribbonAmount}} Bänder.", }, "10_RIBBONS": { - name: "Champion der Pokémon Liga", + name: "Champion der Pokémon Liga", }, "25_RIBBONS": { name: "Bänder-Sammler", @@ -91,82 +92,286 @@ export const achv: AchievementTranslationEntries = { "TRANSFER_MAX_BATTLE_STAT": { name: "Teamwork", - description: "Nutze Staffette, während der Anwender mindestens eines Statuswertes maximiert hat", + description: "Nutze Staffette, während der Anwender mindestens eines Statuswertes maximiert hat.", }, "MAX_FRIENDSHIP": { - name: "Freundschaftsmaximierung", - description: "Erreiche maximale Freundschaft bei einem Pokémon", + name: "Freundschaftsmaximierung", + description: "Erreiche maximale Freundschaft bei einem Pokémon.", }, "MEGA_EVOLVE": { name: "Megaverwandlung", - description: "Megaentwickle ein Pokémon", + description: "Megaentwickle ein Pokémon.", }, "GIGANTAMAX": { name: "Absolute Einheit", - description: "Gigadynamaximiere ein Pokémon", + description: "Gigadynamaximiere ein Pokémon.", }, "TERASTALLIZE": { name: "Typen-Bonus Enthusiast", - description: "Terrakristallisiere ein Pokémon", + description: "Terrakristallisiere ein Pokémon.", }, "STELLAR_TERASTALLIZE": { name: "Der geheime Typ", - description: "Terrakristallisiere ein Pokémon zum Typen Stellar", + description: "Terrakristallisiere ein Pokémon zum Typen Stellar.", }, "SPLICE": { name: "Unendliche Fusion", - description: "Kombiniere zwei Pokémon mit einem DNS-Keil", + description: "Kombiniere zwei Pokémon mit einem DNS-Keil.", }, "MINI_BLACK_HOLE": { name: "Ein Loch voller Items", - description: "Erlange ein Mini-Schwarzes Loch", + description: "Erlange ein Mini-Schwarzes Loch.", }, "CATCH_MYTHICAL": { - name: "Mysteriöses!", - description: "Fange ein mysteriöses Pokémon", + name: "Mysteriöses!", + description: "Fange ein mysteriöses Pokémon.", }, "CATCH_SUB_LEGENDARY": { name: "Sub-Legendär", - description: "Fange ein sub-legendäres Pokémon", + description: "Fange ein sub-legendäres Pokémon.", }, "CATCH_LEGENDARY": { name: "Legendär", - description: "Fange ein legendäres Pokémon", + description: "Fange ein legendäres Pokémon.", }, "SEE_SHINY": { name: "Schillerndes Licht", - description: "Finde ein wildes schillerndes Pokémon", + description: "Finde ein wildes schillerndes Pokémon.", }, "SHINY_PARTY": { name: "Das ist Hingabe", - description: "Habe ein Team aus schillernden Pokémon", + description: "Habe ein Team aus schillernden Pokémon.", }, "HATCH_MYTHICAL": { name: "Mysteriöses Ei", - description: "Lass ein mysteriöses Pokémon aus einem Ei schlüpfen", + description: "Lass ein mysteriöses Pokémon aus einem Ei schlüpfen.", }, "HATCH_SUB_LEGENDARY": { name: "Sub-Legendäres Ei", - description: "Lass ein sub-legendäres Pokémon aus einem Ei schlüpfen", + description: "Lass ein sub-legendäres Pokémon aus einem Ei schlüpfen.", }, "HATCH_LEGENDARY": { name: "Legendäres Ei", - description: "Lass ein legendäres Pokémon aus einem Ei schlüpfen", + description: "Lass ein legendäres Pokémon aus einem Ei schlüpfen.", }, "HATCH_SHINY": { name: "Schillerndes Ei", - description: "Lass ein schillerndes Pokémon aus einem Ei schlüpfen", + description: "Lass ein schillerndes Pokémon aus einem Ei schlüpfen.", }, "HIDDEN_ABILITY": { name: "Geheimes Talent", - description: "Fang ein Pokémon mit versteckter Fähigkeit", + description: "Fang ein Pokémon mit versteckter Fähigkeit.", }, "PERFECT_IVS": { name: "Zertifikat der Echtheit", - description: "Erhalte ein Pokémon mit perfekten IS-Werten", + description: "Erhalte ein Pokémon mit perfekten IS-Werten.", }, "CLASSIC_VICTORY": { name: "Ungeschlagen", - description: "Beende den klassischen Modus erfolgreich", + description: "Beende den klassischen Modus erfolgreich.", + }, + "MONO_GEN_ONE": { + name: "Der originale Rivale", + description: "Schließe die 'Nur 1. Generation' Herausforderung ab.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Schließe die 'Nur 2. Generation' Herausforderung ab.", + }, + "MONO_GEN_THREE": { + name: "Zu viel Wasser?", + description: "Schließe die 'Nur 3. Generation' Herausforderung ab.", + }, + "MONO_GEN_FOUR": { + name: "Ist SIE wirklich die Stärkste?", + description: "Schließe die 'Nur 4. Generation' Herausforderung ab.", + }, + "MONO_GEN_FIVE": { + name: "Komplett Original", + description: "Schließe die 'Nur 5. Generation' Herausforderung ab.", + }, + "MONO_GEN_SIX": { + name: "Fast Königlich", + description: "Schließe die 'Nur 6. Generation' Herausforderung ab." + }, + "MONO_GEN_SEVEN": { + name: "Technisch gesehen", + description: "Schließe die 'Nur 7. Generation' Herausforderung ab." + }, + "MONO_GEN_EIGHT": { + name: "Die Zeit des Champions", + description: "Schließe die 'Nur 8. Generation' Herausforderung ab." + }, + "MONO_GEN_NINE": { + name: "Sie hat es dir leicht gemacht...", + description: "Schließe die 'Nur 9. Generation' Herausforderung ab." + }, + + "MonoType": { + description: "Beende die Monotyp-{{type}} Herausforderung." + }, + "MONO_NORMAL": { + name: "Normaler Typ", + }, + "MONO_FIGHTING": { + name: "Ich kenne Kung Fu." + }, + "MONO_FLYING": { + name: "Ich glaube ich kann fliegen.", + }, + "MONO_POISON": { + name: "Kantos Liebling", + }, + "MONO_GROUND": { + name: "Auf dem Boden bleiben.", + }, + "MONO_ROCK": { + name: "So hart wie Rocko.", + }, + "MONO_BUG": { + name: "Steche wie ein Bibor.", + }, + "MONO_GHOST": { + name: "Wer wird angerufen?", + }, + "MONO_STEEL": { + name: "Stahlharte Entschlossenheit", + }, + "MONO_FIRE": { + name: "Brennende Leidenschaft", + }, + "MONO_WATER": { + name: "Wenn es regnet, schüttet es!", + }, + "MONO_GRASS": { + name: "Grüner Daumen", + }, + "MONO_ELECTRIC": { + name: "Elektrisierend", + }, + "MONO_PSYCHIC": { + name: "Übernatürliches Talent", + }, + "MONO_ICE": { + name: "Eis Eis Baby", + }, + "MONO_DRAGON": { + name: "Siegfried bist du es?", + }, + "MONO_DARK": { + name: "Es ist nur eine Phase!", + }, + "MONO_FAIRY": { + name: "Ein ewiges Abenteuer!", }, } as const; + +// Achievement translations for the when the player character is female +export const PGFachv: AchievementTranslationEntries = { + "Achievements": { + name: PGMachv.Achievements.name, + }, + "Locked": { + name: PGMachv.Locked.name, + }, + + + "MoneyAchv": PGMachv.MoneyAchv, + "10K_MONEY": { + name: "Besserverdienerin", + }, + "100K_MONEY": PGMachv["100K_MONEY"], + "1M_MONEY": { + name: "Millionärin", + }, + "10M_MONEY": PGMachv["10M_MONEY"], + + "DamageAchv": PGMachv.DamageAchv, + "250_DMG": PGMachv["250_DMG"], + "1000_DMG": PGMachv["1000_DMG"], + "2500_DMG": PGMachv["2500_DMG"], + "10000_DMG": { + name: "One Punch Woman", + }, + + "HealAchv": PGMachv.HealAchv, + "250_HEAL": { + name: "Anfänger-Heilerin", + }, + "1000_HEAL": PGMachv["1000_HEAL"], + "2500_HEAL": { + name: "Klerikerin", + }, + "10000_HEAL": { + name: "Wiederherstellungsmeisterin", + }, + + "LevelAchv": PGMachv.LevelAchv, + "LV_100": PGMachv["LV_100"], + "LV_250": PGMachv["LV_250"], + "LV_1000": PGMachv["LV_1000"], + + "RibbonAchv": PGMachv.RibbonAchv, + "10_RIBBONS": PGMachv["10_RIBBONS"], + "25_RIBBONS": { + name: "Bänder-Sammlerin", + }, + "50_RIBBONS": { + name: "Bänder-Expertin", + }, + "75_RIBBONS": PGMachv["75_RIBBONS"], + "100_RIBBONS": { + name: "Bänder-Meisterin", + }, + + "TRANSFER_MAX_BATTLE_STAT": PGMachv.TRANSFER_MAX_BATTLE_STAT, + "MAX_FRIENDSHIP": PGMachv.MAX_FRIENDSHIP, + "MEGA_EVOLVE": PGMachv.MEGA_EVOLVE, + "GIGANTAMAX": PGMachv.GIGANTAMAX, + "TERASTALLIZE": PGMachv.TERASTALLIZE, + "STELLAR_TERASTALLIZE": PGMachv.STELLAR_TERASTALLIZE, + "SPLICE": PGMachv.SPLICE, + "MINI_BLACK_HOLE": PGMachv.MINI_BLACK_HOLE, + "CATCH_MYTHICAL": PGMachv.CATCH_MYTHICAL, + "CATCH_SUB_LEGENDARY": PGMachv.CATCH_SUB_LEGENDARY, + "CATCH_LEGENDARY": PGMachv.CATCH_LEGENDARY, + "SEE_SHINY": PGMachv.SEE_SHINY, + "SHINY_PARTY": PGMachv.SHINY_PARTY, + "HATCH_MYTHICAL": PGMachv.HATCH_MYTHICAL, + "HATCH_SUB_LEGENDARY": PGMachv.HATCH_SUB_LEGENDARY, + "HATCH_LEGENDARY": PGMachv.HATCH_LEGENDARY, + "HATCH_SHINY": PGMachv.HATCH_SHINY, + "HIDDEN_ABILITY": PGMachv.HIDDEN_ABILITY, + "PERFECT_IVS": PGMachv.PERFECT_IVS, + "CLASSIC_VICTORY": PGMachv.CLASSIC_VICTORY, + "MONO_GEN_ONE": PGMachv.MONO_GEN_ONE, + "MONO_GEN_TWO": PGMachv.MONO_GEN_TWO, + "MONO_GEN_THREE": PGMachv.MONO_GEN_THREE, + "MONO_GEN_FOUR": PGMachv.MONO_GEN_FOUR, + "MONO_GEN_FIVE": PGMachv.MONO_GEN_FIVE, + "MONO_GEN_SIX": PGMachv.MONO_GEN_SIX, + "MONO_GEN_SEVEN": PGMachv.MONO_GEN_SEVEN, + "MONO_GEN_EIGHT": PGMachv.MONO_GEN_EIGHT, + "MONO_GEN_NINE": PGMachv.MONO_GEN_NINE, + + "MonoType": PGMachv.MonoType, + "MONO_NORMAL": PGMachv.MONO_NORMAL, + "MONO_FIGHTING": PGMachv.MONO_FIGHTING, + "MONO_FLYING": PGMachv.MONO_FLYING, + "MONO_POISON": PGMachv.MONO_POISON, + "MONO_GROUND": PGMachv.MONO_GROUND, + "MONO_ROCK": PGMachv.MONO_ROCK, + "MONO_BUG": PGMachv.MONO_BUG, + "MONO_GHOST": PGMachv.MONO_GHOST, + "MONO_STEEL": PGMachv.MONO_STEEL, + "MONO_FIRE": PGMachv.MONO_FIRE, + "MONO_WATER": PGMachv.MONO_WATER, + "MONO_GRASS": PGMachv.MONO_GRASS, + "MONO_ELECTRIC": PGMachv.MONO_ELECTRIC, + "MONO_PSYCHIC": PGMachv.MONO_PSYCHIC, + "MONO_ICE": PGMachv.MONO_ICE, + "MONO_DRAGON": PGMachv.MONO_DRAGON, + "MONO_DARK": PGMachv.MONO_DARK, + "MONO_FAIRY": PGMachv.MONO_FAIRY, +} as const; + diff --git a/src/locales/de/berry.ts b/src/locales/de/berry.ts index 330b36fffc8..093c3f708eb 100644 --- a/src/locales/de/berry.ts +++ b/src/locales/de/berry.ts @@ -3,46 +3,46 @@ import { BerryTranslationEntries } from "#app/plugins/i18n"; export const berry: BerryTranslationEntries = { "SITRUS": { name: "Tsitrubeere", - effect: "Stellt 25% der KP wieder her, wenn die KP unter 50% sind" + effect: "Stellt 25% der KP wieder her, wenn die KP unter 50% sind." }, "LUM": { name: "Prunusbeere", - effect: "Heilt jede nichtflüchtige Statusveränderung und Verwirrung" + effect: "Heilt jede nichtflüchtige Statusveränderung und Verwirrung." }, "ENIGMA": { name: "Enigmabeere", - effect: "Stellt 25% der KP wieder her, wenn der Träger von einer sehr effektiven Attacke getroffen wird", + effect: "Stellt 25% der KP wieder her, wenn der Träger von einer sehr effektiven Attacke getroffen wird.", }, "LIECHI": { name: "Lydzibeere", - effect: "Steigert den Angriff, wenn die KP unter 25% sind" + effect: "Steigert den Angriff, wenn die KP unter 25% sind." }, "GANLON": { name: "Linganbeere", - effect: "Steigert die Verteidigung, wenn die KP unter 25% sind" + effect: "Steigert die Verteidigung, wenn die KP unter 25% sind." }, "PETAYA": { name: "Tahaybeere", - effect: "Steigert den Spezial-Angriff, wenn die KP unter 25% sind" + effect: "Steigert den Spezial-Angriff, wenn die KP unter 25% sind." }, "APICOT": { name: "Apikobeere", - effect: "Steigert die Spezial-Verteidigung, wenn die KP unter 25% sind" + effect: "Steigert die Spezial-Verteidigung, wenn die KP unter 25% sind." }, "SALAC": { name: "Salkabeere", - effect: "Steigert die Initiative, wenn die KP unter 25% sind" + effect: "Steigert die Initiative, wenn die KP unter 25% sind." }, "LANSAT": { name: "Lansatbeere", - effect: "Erhöht die Volltrefferchance, wenn die KP unter 25% sind" + effect: "Erhöht die Volltrefferchance, wenn die KP unter 25% sind." }, "STARF": { name: "Krambobeere", - effect: "Erhöht einen zufälligen Statuswert stark, wenn die KP unter 25% sind" + effect: "Erhöht einen zufälligen Statuswert stark, wenn die KP unter 25% sind." }, "LEPPA": { name: "Jonagobeere", - effect: "Stellt 10 AP für eine Attacke wieder her, wenn deren AP auf 0 fallen" + effect: "Stellt 10 AP für eine Attacke wieder her, wenn deren AP auf 0 fallen." }, } as const; diff --git a/src/locales/de/challenges.ts b/src/locales/de/challenges.ts new file mode 100644 index 00000000000..1dbd4505986 --- /dev/null +++ b/src/locales/de/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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." + +} as const; diff --git a/src/locales/de/config.ts b/src/locales/de/config.ts index afee437a652..b02bd5aeee6 100644 --- a/src/locales/de/config.ts +++ b/src/locales/de/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const deConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const deConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const deConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/de/dialogue.ts b/src/locales/de/dialogue.ts index 6b0bdc7c16a..1bfff5aa000 100644 --- a/src/locales/de/dialogue.ts +++ b/src/locales/de/dialogue.ts @@ -367,6 +367,17 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Ich werde für das nächste Rennen tunen." }, }, + "rocket_grunt": { + "encounter": { + 1: `Jetzt gibt es Ärger!… + $und es kommt noch härter! + $Wir wollen über die Erde regieren… + $und naja du kennst den Rest…!` + }, + "victory": { + 1: "Das war mal wieder ein Schuss in den Ofen!" + }, + }, "firebreather": { "encounter": { 1: "Meine Flammen werden dich verschlingen!", @@ -391,6 +402,190 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "Ich glaube, ich bin der der seekrank ist..." }, }, + "magma_grunt": { + "encounter": { + 1: "Keiner, der sich Team Magma in den Weg stellt, bekommt Gnade, nicht einmal Kinder!" + }, + "victory": { + 1: "Wie kann das sein? Ich bin Teil vom mächtigen Team Magma! Wir wollen doch nur die Welt verbessern…" + }, + }, + "aqua_grunt": { + "encounter": { + 1: "Du willst dich also mit Team Aqua anlegen? Du traust dich ja was… Dich werfe ich über Bord!", + }, + "victory": { + 1: "Vielleicht sollte ich wohl lieber selber über die Planke gehen…", + }, + }, + "galactic_grunt": { + "encounter": { + 1: "Team Galaktik wird die Welt in eine bessere Welt verwandeln! Und du wirst uns nicht aufhalten!" + }, + "victory": { + 1: "Zyrus wird uns für diese Niederlage bestrafen…" + }, + }, + "plasma_grunt": { + "encounter": { + 1: "Pokémon sollten frei sein! Team Plasma wird sie befreien!" + }, + "victory": { + 1: "Wie konnte ich verlieren? Ich dachte, ich würde die Welt retten…" + }, + }, + "flare_grunt": { + "encounter": { + 1: `Ich bin ein Mitglied von Team Flare! Das sieht man mir doch an. Mein Stil ist unverkennbar! + $Du kannst definitiv ein Umstyling gebrauchen!` + }, + "victory": { + 1: "Stil ist wohl doch nicht alles…" + }, + }, + "rocket_boss_giovanni_1": { + "encounter": { + 1: `Ich bin beeindruckt, du hast es bis hierher geschafft! + $Ich bin Giovanni, der Anführer von Team Rocket! + $Wir regieren den Untergrund von Kanto! + $Und wir lassen sicherlich nicht zu, dass ein Kind uns aufhält!` + + }, + "victory": { + 1: "Ich ziehe mich zurück, aber ich werde zurückkehren! Team Rocket wird niemals besiegt werden!" + }, + "defeat": { + 1: `Merke dir meine Worte. Nicht in der Lage zu sein, + $deine eigene Stärke zu messen, zeigt, dass du immer noch ein Kind bist.` + } + }, + "rocket_boss_giovanni_2": { + "encounter": { + 1: "Du schon wieder… Wie hast du mich gefunden? Team Rocket wird dich endlich aus der Welt schaffen!" + }, + "victory": { + 1: "Wie ist das möglich...? Der kostbare Traum von Team Rocket ist nicht mehr als eine Illusion geworden..." + }, + "defeat": { + 1: "Team Rocket wird niemals besiegt werden! Ich werde zurückkehren!" + } + }, + "magma_boss_maxie_1": { + "encounter": { + 1: `Die Welt ist nicht perfekt. Ich werde sie verbessern, indem ich sie neu erschaffe! + $Wir brauchen mehr Landmassen um zu leben! Team Magma wird dieses Ziel mit aller Macht erreichen!` + }, + "victory": { + 1:"Ugh! Das entspricht nicht meinen Berechnungen! Wie konnte ich verlieren? Wir sehen uns wieder!" + }, + "defeat": { + 1: "Team Magma wird weiterhin die Welt verbessern!" + } + }, + "magma_boss_maxie_2": { + "encounter": { + 1: `Du bist das letzte Hindernis, das zwischen mir und meinen Zielen steht. + $Mach dich bereit durch die Macht von Team Magma besiegt zu werden!` + }, + "victory": { + 1: "Das... Das kann nicht sein...", + }, + "defeat": { + 1: "Und jetzt werde ich diesen Planeten terraformen, um ihn ideal für die Menschheit zu machen." + } + }, + "aqua_boss_archie_1": { + "encounter": { + 1: "Ich bin Adrian, der Anführer von Team Aqua! Wir werden die Welt mit Wasser überfluten!" + }, + "victory": { + 1: "Lass uns mal wieder treffen. Ich werde mir sicher sein, dass ich dieses Gesicht wiedererkenne." + }, + "defeat": { + 1: "Brilliant! Mein Team wird jetzt nicht zurückhalten!" + } + }, + "aqua_boss_archie_2": { + "encounter": { + 1: "Ich habe lange auf diesen Tag gewartet. Das ist die wahre Macht von Team Aqua!" + }, + "victory": { + 1: "So habe ich mir das nicht vorgestellt..." + }, + "defeat": { + 1: "Ich werde alles in dieser Welt in seinen ursprünglichen, reinen Zustand zurückversetzen!!" + } + }, + "galactic_boss_cyrus_1": { + "encounter": { + 1: `Du wurdest von leerer Gefühlsduselei hierher getrieben. + $Ich werde dich bereuen lassen, auf dein Herz gehört zu haben!` + }, + "victory": { + 1: "Interessant. Und ziemlich eigenartig." + }, + "defeat": { + 1: "Ich werde meine neue Welt erschaffen..." + } + }, + "galactic_boss_cyrus_2": { + "encounter": { + 1: `So sehen wir uns wieder. Es scheint, als wären unsere Schicksale miteinander verflochten. + $Aber hier und jetzt werde ich diese Verbindung brechen!` + }, + "victory": { + 1: "Wie? Wie? WIE?!" + }, + "defeat": { + 1: "Bis bald." + } + }, + "plasma_boss_ghetsis_1": { + "encounter": { + 1:"Ich werde nicht zulassen, dass mich jemand aufhält! Egal wer es auch sein mag!" + }, + "victory": { + 1: "Wie kann das sein? Ich bin der Schöpfer von Team Plasma! Ich bin perfekt!" + }, + "defeat": { + 1: "Ich bin der perfekte Herrscher einer perfekten neuen Welt! Mwa ha ha!" + } + }, + "plasma_boss_ghetsis_2": { + "encounter": { + 1: "Komm schon! Ich will dein Gesicht sehen, in dem Moment, in dem du alle Hoffnung verlierst!" + }, + "victory": { + 1: "Meine Berechnungen... Nein! Meine sorgfältigen Pläne! Die Welt sollte mir gehören!" + }, + "defeat": { + 1: "Kyurem! Verwende Absorptionsfusion!" + } + }, + "flare_boss_lysandre_1": { + "encounter": { + 1: "DU willst mich aufhalten? Dann zeig mir deine Stärke in einem Kampf!" + }, + "victory": { + 1: `Du bist hier, um mich aufzuhalten. Aber ich bitte dich zu warten. + $Ich bin so kurz davor, meine Vision zu verwirklichen.` + }, + "defeat": { + 1: "Pokémon... Sollten nicht mehr existieren." + } + }, + "flare_boss_lysandre_2": { + "encounter": { + 1: `Die Zukunft, die du willst, oder die Zukunft, die ich will... + $Lass uns sehen, welche mehr zu existieren verdient, sollen wir?` + }, + "victory": { + 1: "Die Zukunft, die ich erschaffen wollte... Es ist vorbei..." + }, + "defeat": { + 1: "Narren ohne Vision werden weiterhin diese wunderschöne Welt verunreinigen." + } + }, "brock": { "encounter": { 1: "Meine Expertise in Bezug auf Gesteins-Pokémon wird dich besiegen! Komm schon!", diff --git a/src/locales/de/egg.ts b/src/locales/de/egg.ts index 1551d832bfc..b55c3a229d0 100644 --- a/src/locales/de/egg.ts +++ b/src/locales/de/egg.ts @@ -10,10 +10,10 @@ export const egg: SimpleTranslationEntries = { "hatchWavesMessageClose": "Manchmal bewegt es sich! Es braucht wohl noch ein Weilchen.", "hatchWavesMessageNotClose": "Was wird da wohl schlüpfen? Es wird sicher noch lange dauern.", "hatchWavesMessageLongTime": "Dieses Ei braucht sicher noch sehr viel Zeit.", - "gachaTypeLegendary": "Erhöhte Chance auf legendäre Eier", - "gachaTypeMove": "Erhöhte Chance auf Eier mit seltenen Attacken", - "gachaTypeShiny": "Erhöhte Chance auf schillernde Eier", - "selectMachine": "Wähle eine Maschine", + "gachaTypeLegendary": "Erhöhte Chance auf legendäre Eier.", + "gachaTypeMove": "Erhöhte Chance auf Eier mit seltenen Attacken.", + "gachaTypeShiny": "Erhöhte Chance auf schillernde Eier.", + "selectMachine": "Wähle eine Maschine.", "notEnoughVouchers": "Du hast nicht genug Ei-Gutscheine!", "tooManyEggs": "Du hast schon zu viele Eier!", "pull": "Pull", diff --git a/src/locales/de/game-mode.ts b/src/locales/de/game-mode.ts new file mode 100644 index 00000000000..59058a6ab49 --- /dev/null +++ b/src/locales/de/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Klassik", + "endless": "Endlos", + "endlessSpliced": "Endlos (Fusion)", + "dailyRun": "Täglicher Run", + "unknown": "Unbekannt", + "challenge": "Challenge", +} as const; diff --git a/src/locales/de/menu.ts b/src/locales/de/menu.ts index e1e5db72b9c..d8987fcf77b 100644 --- a/src/locales/de/menu.ts +++ b/src/locales/de/menu.ts @@ -18,19 +18,19 @@ export const menu: SimpleTranslationEntries = { "password": "Passwort", "login": "Anmelden", "register": "Registrieren", - "emptyUsername": "Benutzername darf nicht leer sein", - "invalidLoginUsername": "Der eingegebene Benutzername ist ungültig", - "invalidRegisterUsername": "Benutzername darf nur Buchstaben, Zahlen oder Unterstriche enthalten", - "invalidLoginPassword": "Das eingegebene Passwort ist ungültig", - "invalidRegisterPassword": "Passwort muss 6 Zeichen oder länger sein", - "usernameAlreadyUsed": "Der eingegebene Benutzername wird bereits verwendet", - "accountNonExistent": "Der eingegebene Benutzer existiert nicht", - "unmatchingPassword": "Das eingegebene Passwort stimmt nicht überein", - "passwordNotMatchingConfirmPassword": "Passwort muss mit Bestätigungspasswort übereinstimmen", + "emptyUsername": "Benutzername darf nicht leer sein.", + "invalidLoginUsername": "Der eingegebene Benutzername ist ungültig.", + "invalidRegisterUsername": "Benutzername darf nur Buchstaben, Zahlen oder Unterstriche enthalten.", + "invalidLoginPassword": "Das eingegebene Passwort ist ungültig.", + "invalidRegisterPassword": "Passwort muss 6 Zeichen oder länger sein.", + "usernameAlreadyUsed": "Der eingegebene Benutzername wird bereits verwendet.", + "accountNonExistent": "Der eingegebene Benutzer existiert nicht.", + "unmatchingPassword": "Das eingegebene Passwort stimmt nicht überein.", + "passwordNotMatchingConfirmPassword": "Passwort muss mit Bestätigungspasswort übereinstimmen.", "confirmPassword": "Bestätige Passwort", "registrationAgeWarning": "Mit der Registrierung bestätigen Sie, dass Sie 13 Jahre oder älter sind.", "backToLogin": "Zurück zur Anmeldung", - "failedToLoadSaveData": "Speicherdaten konnten nicht geladen werden. Bitte laden Sie die Seite neu.\nÜberprüfe den #announcements-Kanal im Discord bei anhaltenden Problemen", + "failedToLoadSaveData": "Speicherdaten konnten nicht geladen werden. Bitte laden Sie die Seite neu.\nÜberprüfe den #announcements-Kanal im Discord bei anhaltenden Problemen.", "sessionSuccess": "Sitzung erfolgreich geladen.", "failedToLoadSession": "Ihre Sitzungsdaten konnten nicht geladen werden.\nSie könnten beschädigt sein.", "boyOrGirl": "Bist du ein Junge oder ein Mädchen?", @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Wöchentliche Rangliste", "noRankings": "Keine Rangliste", "loading": "Lade…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "Spieler Online", - "empty":"Leer", "yes":"Ja", "no":"Nein", "disclaimer": "DISCLAIMER", diff --git a/src/locales/de/modifier-type.ts b/src/locales/de/modifier-type.ts index ff9cf28632c..175c426143b 100644 --- a/src/locales/de/modifier-type.ts +++ b/src/locales/de/modifier-type.ts @@ -4,11 +4,11 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{modifierCount}}x {{pokeballName}}", - description: "Erhalte {{pokeballName}} x{{modifierCount}} (Inventar: {{pokeballAmount}}) \nFangrate: {{catchRate}}", + description: "Erhalte {{pokeballName}} x{{modifierCount}}. (Inventar: {{pokeballAmount}}) \nFangrate: {{catchRate}}", }, "AddVoucherModifierType": { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "Erhalte {{voucherTypeName}} x{{modifierCount}}", + description: "Erhalte {{voucherTypeName}} x{{modifierCount}}.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,32 +17,32 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "Füllt {{restorePoints}} KP oder {{restorePercent}}% der KP für ein Pokémon auf. Je nachdem, welcher Wert höher ist", + description: "Füllt {{restorePoints}} KP oder {{restorePercent}}% der KP für ein Pokémon auf. Je nachdem, welcher Wert höher ist.", extra: { "fully": "Füllt die KP eines Pokémon wieder vollständig auf.", - "fullyWithStatus": "Füllt die KP eines Pokémon wieder vollständig auf und behebt alle Statusprobleme", + "fullyWithStatus": "Füllt die KP eines Pokémon wieder vollständig auf und behebt alle Statusprobleme.", } }, "PokemonReviveModifierType": { - description: "Belebt ein kampunfähiges Pokémon wieder und stellt {{restorePercent}}% KP wieder her", + description: "Belebt ein kampunfähiges Pokémon wieder und stellt {{restorePercent}}% KP wieder her.", }, "PokemonStatusHealModifierType": { - description: "Behebt alle Statusprobleme eines Pokémon", + description: "Behebt alle Statusprobleme eines Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Füllt {{restorePoints}} AP der ausgewählten Attacke eines Pokémon auf", + description: "Füllt {{restorePoints}} AP der ausgewählten Attacke eines Pokémon auf.", extra: { - "fully": "Füllt alle AP der ausgewählten Attacke eines Pokémon auf", + "fully": "Füllt alle AP der ausgewählten Attacke eines Pokémon auf.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Stellt {{restorePoints}} AP für alle Attacken eines Pokémon auf", + description: "Stellt {{restorePoints}} AP für alle Attacken eines Pokémon auf.", extra: { - "fully": "Füllt alle AP für alle Attacken eines Pokémon auf", + "fully": "Füllt alle AP für alle Attacken eines Pokémon auf.", } }, "PokemonPpUpModifierType": { - description: "Erhöht die maximale Anzahl der AP der ausgewählten Attacke um {{upPoints}} für jede 5 maximale AP (maximal 3)", + description: "Erhöht die maximale Anzahl der AP der ausgewählten Attacke um {{upPoints}} für jede 5 maximale AP (maximal 3).", }, "PokemonNatureChangeModifierType": { name: "{{natureName}} Minze", @@ -52,28 +52,28 @@ export const modifierType: ModifierTypeTranslationEntries = { description: "Verdoppelt die Wahrscheinlichkeit, dass die nächsten {{battleCount}} Begegnungen mit wilden Pokémon ein Doppelkampf sind.", }, "TempBattleStatBoosterModifierType": { - description: "Erhöht die {{tempBattleStatName}} aller Teammitglieder für 5 Kämpfe um eine Stufe", + description: "Erhöht die {{tempBattleStatName}} aller Teammitglieder für 5 Kämpfe um eine Stufe.", }, "AttackTypeBoosterModifierType": { - description: "Erhöht die Stärke aller {{moveType}}-Attacken eines Pokémon um 20%", + description: "Erhöht die Stärke aller {{moveType}}-Attacken eines Pokémon um 20%.", }, "PokemonLevelIncrementModifierType": { - description: "Erhöht das Level eines Pokémon um 1", + description: "Erhöht das Level eines Pokémon um 1.", }, "AllPokemonLevelIncrementModifierType": { - description: "Erhöht das Level aller Teammitglieder um 1", + description: "Erhöht das Level aller Teammitglieder um 1.", }, "PokemonBaseStatBoosterModifierType": { description: "Erhöht den {{statName}} Basiswert des Trägers um 10%. Das Stapellimit erhöht sich, je höher dein IS-Wert ist.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Stellt 100% der KP aller Pokémon her", + description: "Stellt 100% der KP aller Pokémon her.", }, "AllPokemonFullReviveModifierType": { - description: "Belebt alle kampunfähigen Pokémon wieder und stellt ihre KP vollständig wieder her", + description: "Belebt alle kampunfähigen Pokémon wieder und stellt ihre KP vollständig wieder her.", }, "MoneyRewardModifierType": { - description:"Gewährt einen {{moneyMultiplier}} Geldbetrag von (₽{{moneyAmount}})", + description:"Gewährt einen {{moneyMultiplier}} Geldbetrag von (₽{{moneyAmount}}).", extra: { "small": "kleinen", "moderate": "moderaten", @@ -81,60 +81,60 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Erhöht die erhaltenen Erfahrungspunkte um {{boostPercent}}%", + description: "Erhöht die erhaltenen Erfahrungspunkte um {{boostPercent}}%.", }, "PokemonExpBoosterModifierType": { - description: "Erhöht die Menge der erhaltenen Erfahrungspunkte für den Träger um {{boostPercent}}%", + description: "Erhöht die Menge der erhaltenen Erfahrungspunkte für den Träger um {{boostPercent}}%.", }, "PokemonFriendshipBoosterModifierType": { description: "Erhöht den Freundschaftszuwachs pro Sieg um 50%.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Erhöht die Genauigkeit der Angriffe um {{accuracyAmount}} (maximal 100)", + description: "Erhöht die Genauigkeit der Angriffe um {{accuracyAmount}} (maximal 100).", }, "PokemonMultiHitModifierType": { - description: "Attacken treffen ein weiteres mal mit einer Reduktion von 60/75/82,5% der Stärke", + description: "Attacken treffen ein weiteres mal mit einer Reduktion von 60/75/82,5% der Stärke.", }, "TmModifierType": { name: "TM{{moveId}} - {{moveName}}", - description: "Bringt einem Pokémon {{moveName}} bei", + description: "Bringt einem Pokémon {{moveName}} bei.", }, "TmModifierTypeWithInfo": { name: "TM{{moveId}} - {{moveName}}", - description: "Bringt einem Pokémon {{moveName}} bei\n(Halte C oder Shift für mehr Infos)", + description: "Bringt einem Pokémon {{moveName}} bei\n(Halte C oder Shift für mehr Infos).", }, "EvolutionItemModifierType": { - description: "Erlaubt es bestimmten Pokémon sich zu entwickeln", + description: "Erlaubt es bestimmten Pokémon sich zu entwickeln.", }, "FormChangeItemModifierType": { - description: "Erlaubt es bestimmten Pokémon ihre Form zu ändern", + description: "Erlaubt es bestimmten Pokémon ihre Form zu ändern.", }, "FusePokemonModifierType": { - description: "Fusioniert zwei Pokémon (überträgt die Fähigkeit, teilt Basiswerte und Typ auf, gemeinsamer Attackenpool)", + description: "Fusioniert zwei Pokémon (überträgt die Fähigkeit, teilt Basiswerte und Typ auf, gemeinsamer Attackenpool).", }, "TerastallizeModifierType": { name: "{{teraType}} Terra-Stück", - description: "{{teraType}} Terakristallisiert den Träger für bis zu 10 Kämpfe", + description: "{{teraType}} Terakristallisiert den Träger für bis zu 10 Kämpfe.", }, "ContactHeldItemTransferChanceModifierType": { description:"Beim Angriff besteht eine {{chancePercent}}%ige Chance, dass das getragene Item des Gegners gestohlen wird." }, "TurnHeldItemTransferModifierType": { - description: "Jede Runde erhält der Träger ein getragenes Item des Gegners", + description: "Jede Runde erhält der Träger ein getragenes Item des Gegners.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Fügt Angriffen eine {{chancePercent}}%ige Chance hinzu, {{statusEffect}} zu verursachen", + description: "Fügt Angriffen eine {{chancePercent}}%ige Chance hinzu, {{statusEffect}} zu verursachen.", }, "EnemyEndureChanceModifierType": { - description: "Gibt den Träger eine {{chancePercent}}%ige Chance, einen Angriff zu überleben", + description: "Gibt den Träger eine {{chancePercent}}%ige Chance, einen Angriff zu überleben.", }, "RARE_CANDY": { name: "Sonderbonbon" }, "RARER_CANDY": { name: "Supersondererbonbon" }, - "MEGA_BRACELET": { name: "Mega-Armband", description: "Mega-Steine werden verfügbar" }, - "DYNAMAX_BAND": { name: "Dynamax-Band", description: "Dyna-Pilze werden verfügbar" }, - "TERA_ORB": { name: "Terakristall-Orb", description: "Tera-Stücke werden verfügbar" }, + "MEGA_BRACELET": { name: "Mega-Armband", description: "Mega-Steine werden verfügbar." }, + "DYNAMAX_BAND": { name: "Dynamax-Band", description: "Dyna-Pilze werden verfügbar."}, + "TERA_ORB": { name: "Terakristall-Orb", description: "Tera-Stücke werden verfügbar." }, "MAP": { name: "Karte", description: "Ermöglicht es dir, an einer Kreuzung dein Ziel zu wählen." }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Zauberasche" }, - "REVIVER_SEED": { name: "Belebersamen", description: "Belebt den Träger mit der Hälfte seiner KP wieder sollte er kampfunfähig werden" }, + "REVIVER_SEED": { name: "Belebersamen", description: "Belebt den Träger mit der Hälfte seiner KP wieder sollte er kampfunfähig werden." }, "ETHER": { name: "Äther" }, "MAX_ETHER": { name: "Top-Äther" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "Super-Lockparfüm" }, "MAX_LURE": { name: "Top-Lockparfüm" }, - "MEMORY_MUSHROOM": { name: "Erinnerungspilz", description: "Lässt ein Pokémon eine vergessene Attacke wiedererlernen" }, + "MEMORY_MUSHROOM": { name: "Erinnerungspilz", description: "Lässt ein Pokémon eine vergessene Attacke wiedererlernen." }, - "EXP_SHARE": { name: "EP-Teiler", description: "Pokémon, die nicht am Kampf teilgenommen haben, bekommen 20% der Erfahrungspunkte eines Kampfteilnehmers" }, + "EXP_SHARE": { name: "EP-Teiler", description: "Pokémon, die nicht am Kampf teilgenommen haben, bekommen 20% der Erfahrungspunkte eines Kampfteilnehmers." }, "EXP_BALANCE": { name: "EP-Ausgleicher", description: "Gewichtet die in Kämpfen erhaltenen Erfahrungspunkte auf niedrigstufigere Gruppenmitglieder." }, - "OVAL_CHARM": { name: "Ovalpin", description: "Wenn mehrere Pokémon am Kampf teilnehmen, erhählt jeder von ihnen 10% extra Erfahrungspunkte" }, + "OVAL_CHARM": { name: "Ovalpin", description: "Wenn mehrere Pokémon am Kampf teilnehmen, erhählt jeder von ihnen 10% extra Erfahrungspunkte." }, "EXP_CHARM": { name: "EP-Pin" }, "SUPER_EXP_CHARM": { name: "Super-EP-Pin" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Sanftglocke" }, - "SOUL_DEW": { name: "Seelentau", description: "Erhöht den Einfluss des Wesens eines Pokemon auf seine Werte um 10% (additiv)" }, + "SOUL_DEW": { name: "Seelentau", description: "Erhöht den Einfluss des Wesens eines Pokemon auf seine Werte um 10% (additiv)." }, "NUGGET": { name: "Nugget" }, "BIG_NUGGET": { name: "Riesennugget" }, "RELIC_GOLD": { name: "Alter Dukat" }, - "AMULET_COIN": { name: "Münzamulett", description: "Erhöht das Preisgeld um 20%" }, - "GOLDEN_PUNCH": { name: "Goldschlag", description: "Gewährt Geld in Höhe von 50% des zugefügten Schadens" }, - "COIN_CASE": { name: "Münzkorb", description: "Erhalte nach jedem 10ten Kampf 10% Zinsen auf dein Geld" }, + "AMULET_COIN": { name: "Münzamulett", description: "Erhöht das Preisgeld um 20%." }, + "GOLDEN_PUNCH": { name: "Goldschlag", description: "Gewährt Geld in Höhe von 50% des zugefügten Schadens." }, + "COIN_CASE": { name: "Münzkorb", description: "Erhalte nach jedem 10ten Kampf 10% Zinsen auf dein Geld." }, - "LOCK_CAPSULE": { name: "Tresorkapsel", description: "Erlaubt es die Seltenheitsstufe der Items festzusetzen wenn diese neu gerollt werden" }, + "LOCK_CAPSULE": { name: "Tresorkapsel", description: "Erlaubt es die Seltenheitsstufe der Items festzusetzen wenn diese neu gerollt werden." }, "GRIP_CLAW": { name: "Griffklaue" }, "WIDE_LENS": { name: "Großlinse" }, "MULTI_LENS": { name: "Mehrfachlinse" }, - "HEALING_CHARM": { name: "Heilungspin", description: "Erhöht die Effektivität von Heilungsattacken sowie Heilitems um 10% (Beleber ausgenommen)" }, - "CANDY_JAR": { name: "Bonbonglas", description: "Erhöht die Anzahl der Level die ein Sonderbonbon erhöht um 1" }, + "HEALING_CHARM": { name: "Heilungspin", description: "Erhöht die Effektivität von Heilungsattacken sowie Heilitems um 10% (Beleber ausgenommen)." }, + "CANDY_JAR": { name: "Bonbonglas", description: "Erhöht die Anzahl der Level die ein Sonderbonbon erhöht um 1." }, - "BERRY_POUCH": { name: "Beerentüte", description: "Fügt eine 30% Chance hinzu, dass Beeren nicht verbraucht werden" }, + "BERRY_POUCH": { name: "Beerentüte", description: "Fügt eine 30% Chance hinzu, dass Beeren nicht verbraucht werden." }, - "FOCUS_BAND": { name: "Fokusband", description: "Fügt eine 10% Chance hinzu, dass Angriffe die zur Kampfunfähigkeit führen mit 1 KP überlebt werden" }, + "FOCUS_BAND": { name: "Fokusband", description: "Fügt eine 10% Chance hinzu, dass Angriffe die zur Kampfunfähigkeit führen mit 1 KP überlebt werden." }, - "QUICK_CLAW": { name: "Quick Claw", description: "Fügt eine 10% Change hinzu als erster anzugreifen. (Nach Prioritätsangriffen)" }, + "QUICK_CLAW": { name: "Quick Claw", description: "Fügt eine 10% Change hinzu als erster anzugreifen. (Nach Prioritätsangriffen)." }, - "KINGS_ROCK": { name: "King-Stein", description: "Fügt eine 10% Chance hinzu, dass der Gegner nach einem Angriff zurückschreckt" }, + "KINGS_ROCK": { name: "King-Stein", description: "Fügt eine 10% Chance hinzu, dass der Gegner nach einem Angriff zurückschreckt." }, - "LEFTOVERS": { name: "Überreste", description: "Heilt 1/16 der maximalen KP eines Pokémon pro Runde" }, - "SHELL_BELL": { name: "Muschelglocke", description: "Heilt den Anwender um 1/8 des von ihm zugefügten Schadens" }, + "LEFTOVERS": { name: "Überreste", description: "Heilt 1/16 der maximalen KP eines Pokémon pro Runde." }, + "SHELL_BELL": { name: "Muschelglocke", description: "Heilt den Anwender um 1/8 des von ihm zugefügten Schadens." }, - "TOXIC_ORB": { name: "Toxik-Orb", description: "Dieser bizarre Orb vergiftet seinen Träger im Kampf schwer" }, - "FLAME_ORB": { name: "Heiß-Orb", description: "Dieser bizarre Orb fügt seinem Träger im Kampf Verbrennungen zu" }, + "TOXIC_ORB": { name: "Toxik-Orb", description: "Dieser bizarre Orb vergiftet seinen Träger im Kampf schwer." }, + "FLAME_ORB": { name: "Heiß-Orb", description: "Dieser bizarre Orb fügt seinem Träger im Kampf Verbrennungen zu." }, "BATON": { name: "Stab", description: "Ermöglicht das Weitergeben von Effekten beim Wechseln von Pokémon, wodurch auch Fallen umgangen werden." }, - "SHINY_CHARM": { name: "Schillerpin", description: "Erhöht die Chance deutlich, dass ein wildes Pokémon ein schillernd ist" }, - "ABILITY_CHARM": { name: "Ability Charm", description: "Erhöht die Chance deutlich, dass ein wildes Pokémon eine versteckte Fähigkeit hat" }, + "SHINY_CHARM": { name: "Schillerpin", description: "Erhöht die Chance deutlich, dass ein wildes Pokémon ein schillernd ist." }, + "ABILITY_CHARM": { name: "Ability Charm", description: "Erhöht die Chance deutlich, dass ein wildes Pokémon eine versteckte Fähigkeit hat." }, - "IV_SCANNER": { name: "IS-Scanner", description: "Erlaubt es die IS-Werte von wilden Pokémon zu scannen.\n(2 IS-Werte pro Staplung. Die besten IS-Werte zuerst)" }, + "IV_SCANNER": { name: "IS-Scanner", description: "Erlaubt es die IS-Werte von wilden Pokémon zu scannen.\n(2 IS-Werte pro Staplung. Die besten IS-Werte zuerst)." }, "DNA_SPLICERS": { name: "DNS-Keil" }, "MINI_BLACK_HOLE": { name: "Mini schwarzes Loch" }, - "GOLDEN_POKEBALL": { name: "Goldener Pokéball", description: "Fügt eine zusätzliche Item-Auswahlmöglichkeit nach jedem Kampf hinzu" }, + "GOLDEN_POKEBALL": { name: "Goldener Pokéball", description: "Fügt eine zusätzliche Item-Auswahlmöglichkeit nach jedem Kampf hinzu." }, - "ENEMY_DAMAGE_BOOSTER": { name: "Schadensmarke", description: "Erhöht den Schaden um 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Schutzmarke", description: "Verringert den erhaltenen Schaden um 2,5%" }, - "ENEMY_HEAL": { name: "Wiederherstellungsmarke", description: "Heilt 2% der maximalen KP pro Runde" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Schadensmarke", description: "Erhöht den Schaden um 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Schutzmarke", description: "Verringert den erhaltenen Schaden um 2,5%." }, + "ENEMY_HEAL": { name: "Wiederherstellungsmarke", description: "Heilt 2% der maximalen KP pro Runde." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "Giftmarke" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { "name": "Lähmungsmarke" }, "ENEMY_ATTACK_BURN_CHANCE": { "name": "Brandmarke" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { "name": "Vollheilungsmarke", "description": "Fügt eine 2,5%ige Chance hinzu, jede Runde einen Statuszustand zu heilen" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { "name": "Vollheilungsmarke", "description": "Fügt eine 2,5%ige Chance hinzu, jede Runde einen Statuszustand zu heilen." }, "ENEMY_ENDURE_CHANCE": { "name": "Ausdauer-Marke" }, - "ENEMY_FUSED_CHANCE": { "name": "Fusionsmarke", "description": "Fügt eine 1%ige Chance hinzu, dass ein wildes Pokémon eine Fusion ist" }, + "ENEMY_FUSED_CHANCE": { "name": "Fusionsmarke", "description": "Fügt eine 1%ige Chance hinzu, dass ein wildes Pokémon eine Fusion ist." }, }, TempBattleStatBoosterItem: { @@ -380,8 +380,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "N_SOLARIZER": "Necrosol", "RUSTED_SWORD": "Rostiges Schwert", "RUSTED_SHIELD": "Rostiges Schild", - "ICY_REINS_OF_UNITY": "eisige Zügel des Bundes", - "SHADOW_REINS_OF_UNITY": "schattige Zügel des Bundes", + "ICY_REINS_OF_UNITY": "Eisige Zügel des Bundes", + "SHADOW_REINS_OF_UNITY": "Schattige Zügel des Bundes", "WELLSPRING_MASK": "Brunnenmaske", "HEARTHFLAME_MASK": "Ofenmaske", "CORNERSTONE_MASK": "Fundamentmaske", @@ -389,5 +389,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "Flammenmodul", "CHILL_DRIVE": "Gefriermodul", "DOUSE_DRIVE": "Aquamodul", + + "FIST_PLATE": "Fausttafel", + "SKY_PLATE": "Wolkentafel", + "TOXIC_PLATE": "Gifttafel", + "EARTH_PLATE": "Erdtafel", + "STONE_PLATE": "Steintafel", + "INSECT_PLATE": "Käfertafel", + "SPOOKY_PLATE": "Spuktafel", + "IRON_PLATE": "Eisentafel", + "FLAME_PLATE": "Feuertafel", + "SPLASH_PLATE": "Wassertafel", + "MEADOW_PLATE": "Wiesentafel", + "ZAP_PLATE": "Blitztafel", + "MIND_PLATE": "Hirntafel", + "ICICLE_PLATE": "Frosttafel", + "DRACO_PLATE": "Dracotafel", + "DREAD_PLATE": "Furchttafel", + "PIXIE_PLATE": "Feentafel", + "BLANK_PLATE": "Neutraltafel", + "LEGEND_PLATE": "Legendentafel", + "FIGHTING_MEMORY": "Kampf-Disc", + "FLYING_MEMORY": "Flug-Disc", + "POISON_MEMORY": "Gift-Disc", + "GROUND_MEMORY": "Boden-Disc", + "ROCK_MEMORY": "Gesteins-Disc", + "BUG_MEMORY": "Käfer-Disc", + "GHOST_MEMORY": "Geister-Disc", + "STEEL_MEMORY": "Stahl-Disc", + "FIRE_MEMORY": "Feuer-Disc", + "WATER_MEMORY": "Wasser-Disc", + "GRASS_MEMORY": "Pflanzen-Disc", + "ELECTRIC_MEMORY": "Elektro-Disc", + "PSYCHIC_MEMORY": "Psycho-Disc", + "ICE_MEMORY": "Eis-Disc", + "DRAGON_MEMORY": "Drachen-Disc", + "DARK_MEMORY": "Unlicht-Disc", + "FAIRY_MEMORY": "Feen-Disc", + "BLANK_MEMORY": "Leere-Disc", }, } as const; diff --git a/src/locales/de/save-slot-select-ui-handler.ts b/src/locales/de/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..fbbfebae6ee --- /dev/null +++ b/src/locales/de/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Den ausgewählten Speicherstand überschreiben?", + "loading": "Läd...", + "wave": "Welle", + "lv": "Lvl", + "empty": "Leer", +} as const; diff --git a/src/locales/de/starter-select-ui-handler.ts b/src/locales/de/starter-select-ui-handler.ts index bae094563cb..a448dcedad8 100644 --- a/src/locales/de/starter-select-ui-handler.ts +++ b/src/locales/de/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Wähle die gewünschte Attacke.", "unlockPassive": "Passiv-Skill freischalten", "reduceCost": "Preis reduzieren", - "cycleShiny": "R: Schillernd Ja/Nein", - "cycleForm": "F: Form ändern", - "cycleGender": "G: Geschlecht ändern", - "cycleAbility": "E: Fähigkeit ändern", - "cycleNature": "N: Wesen Ändern", - "cycleVariant": "V: Seltenheit ändern", + "cycleShiny": ": Schillernd", + "cycleForm": ": Form", + "cycleGender": ": Geschlecht", + "cycleAbility": ": Fähigkeit", + "cycleNature": ": Wesen", + "cycleVariant": ": Seltenheit", "enablePassive": "Passiv-Skill aktivieren", "disablePassive": "Passiv-Skill deaktivieren", "locked": "Gesperrt", diff --git a/src/locales/de/trainers.ts b/src/locales/de/trainers.ts index b7d7ec01617..b473bb94094 100644 --- a/src/locales/de/trainers.ts +++ b/src/locales/de/trainers.ts @@ -13,6 +13,12 @@ export const titles: SimpleTranslationEntries = { "rival": "Rivale", "professor": "Professor", "frontier_brain": "Kampfkoryphäen", + "rocket_boss": "Rocket-Boss", + "magma_boss": "Magma-Boss", + "aqua_boss": "Aqua-Boss", + "galactic_boss": "Galaktik-Boss", + "plasma_boss": "Weiser von Team Plasma", // This is on purpose, since "Ghetsis" is never mentioned as the boss of team plasma in the game but as "Weiser" + "flare_boss": "Flare-Boss", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -118,7 +124,25 @@ export const trainerClasses: SimpleTranslationEntries = { "worker": "Arbeiter", "worker_female": "Arbeiterin", "workers": "Arbeiter", - "youngster": "Knirps" + "youngster": "Knirps", + "rocket_grunt": "Rüpel von Team Rocket", + "rocket_grunt_female": "Rüpel von Team Rocket", + "rocket_grunts": "Rüpel von Team Rocket", + "magma_grunt": "Rüpel von Team Magma", + "magma_grunt_female": "Rüpel von Team Magma", + "magma_grunts": "Rüpel von Team Magma", + "aqua_grunt": "Rüpel von Team Aqua", + "aqua_grunt_female": "Rüpel von Team Aqua", + "aqua_grunts": "Rüpel von Team Aqua", + "galactic_grunt": "Rüpel von Team Galaktik", + "galactic_grunt_female": "Rüpel von Team Galaktik", + "galactic_grunts": "Rüpel von Team Galaktik", + "plasma_grunt": "Rüpel von Team Plasma", + "plasma_grunt_female": "Rüpel von Team Plasma", + "plasma_grunts": "Rüpel von Team Plasma", + "flare_grunt": "Rüpel von Team Flare", + "flare_grunt_female": "Rüpel von Team Flare", + "flare_grunts": "Rüpel von Team Flare", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -247,6 +271,11 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Delion", "rival": "Finn", "rival_female": "Ivy", + "maxie": "Marc", + "archie": "Adrian", + "cyrus": "Zyrus", + "ghetsis": "G-Cis", + "lysandre": "Flordelis", // Double Names "blue_red_double": "Blau & Rot", diff --git a/src/locales/en/achv.ts b/src/locales/en/achv.ts index 42b1995bcde..571935aaddf 100644 --- a/src/locales/en/achv.ts +++ b/src/locales/en/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Achievements", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Extra Ordinary", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Angry Birds", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Forecast: Earthquakes", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "You Like Jazz?", + }, + "MONO_GHOST": { + name: "Who You Gonna Call?", + }, + "MONO_STEEL": { + name: "Iron Giant", + }, + "MONO_FIRE": { + name: "I Cast Fireball!", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Can't Touch This", + }, + "MONO_ELECTRIC": { + name: "Aim For The Horn!", + }, + "MONO_PSYCHIC": { + name: "Big Brain Energy", + }, + "MONO_ICE": { + name: "Walking On Thin Ice", + }, + "MONO_DRAGON": { + name: "Pseudo-Legend Club", + }, + "MONO_DARK": { + name: "It's Just A Phase", + }, + "MONO_FAIRY": { + name: "Hey! Listen!", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/en/challenges.ts b/src/locales/en/challenges.ts new file mode 100644 index 00000000000..7401104e1a3 --- /dev/null +++ b/src/locales/en/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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.", +} as const; diff --git a/src/locales/en/config.ts b/src/locales/en/config.ts index 383b52d4c19..89f809b266d 100644 --- a/src/locales/en/config.ts +++ b/src/locales/en/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const enConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const enConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const enConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index 601e6363f3a..abf95193bc9 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -383,6 +383,186 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + "rocket_grunt": { + "encounter": { + 1: "Prepare for trouble!" + }, + "victory": { + 1: "Team Rocket blasting off again!" + }, + }, + "magma_grunt": { + "encounter": { + 1: " If you get in the way of Team Magma, don’t expect any mercy!" + }, + "victory": { + 1: "Huh? I lost?!" + }, + }, + "aqua_grunt": { + "encounter": { + 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + }, + "victory": { + 1: "You're kidding me!" + }, + }, + "galactic_grunt": { + "encounter": { + 1: "Don't mess with Team Galactic!" + }, + "victory": { + 1: "Shut down..." + }, + }, + "plasma_grunt": { + "encounter": { + 1: "We won't tolerate people who have different ideas!" + }, + "victory": { + 1: "Plasmaaaaaaaaa!" + }, + }, + "flare_grunt": { + "encounter": { + 1: "Fashion is most important to us!" + }, + "victory": { + 1: "The future doesn't look bright for me." + }, + }, + "rocket_boss_giovanni_1": { + "encounter": { + 1: "So! I must say, I am impressed you got here!" + }, + "victory": { + 1: "WHAT! This cannot be!" + }, + "defeat": { + 1: "Mark my words. Not being able to measure your own strength shows that you are still a child." + } + }, + "rocket_boss_giovanni_2": { + "encounter": { + 1: "My old associates need me... Are you going to get in my way?" + }, + "victory": { + 1: "How is this possible...?\nThe precious dream of Team Rocket has become little more than an illusion..." + }, + "defeat": { + 1: "Team Rocket will be reborn again, and I will rule the world!" + } + }, + "magma_boss_maxie_1": { + "encounter": { + 1: "I will bury you by my own hand. I hope you appreciate this honor!" + }, + "victory": { + 1: "Ugh! You are... quite capable...\nI fell behind, but only by an inch..." + }, + "defeat": { + 1: "Team Magma will prevail!" + } + }, + "magma_boss_maxie_2": { + "encounter": { + 1: "You are the final obstacle remaining between me and my goals.\nBrace yourself for my ultimate attack! Fuhahaha!" + }, + "victory": { + 1: "This... This is not.. Ngh..." + }, + "defeat": { + 1: "And now... I will transform this planet to a land ideal for humanity." + } + }, + "aqua_boss_archie_1": { + "encounter": { + 1: "I'm leader of Team Aqua, so I'm afraid it's the rope's end for you." + }, + "victory": { + 1: "Let's meet again somewhere. I'll be sure to remember that face." + }, + "defeat": { + 1: "Brilliant! My team won't hold back now!" + } + }, + "aqua_boss_archie_2": { + "encounter": { + 1: "I've been waiting so long for this day to come.\nThis is the true power of my team!" + }, + "victory": { + 1: "Like I figured..." + }, + "defeat": { + 1: "I'll return everything in this world to its original, pure state!!" + } + }, + "galactic_boss_cyrus_1": { + "encounter": { + 1: "You were compelled to come here by such vacuous sentimentality\nI will make you regret paying heed to your heart!" + }, + "victory": { + 1: "Interesting. And quite curious." + }, + "defeat": { + 1: "I will create my new world..." + } + }, + "galactic_boss_cyrus_2": { + "encounter": { + 1: "So we meet again. It seems our fates have become intertwined.\nBut here and now, I will finally break that bond!" + }, + "victory": { + 1: "How? How? HOW?!" + }, + "defeat": { + 1: "Farewell." + } + }, + "plasma_boss_ghetsis_1": { + "encounter": { + 1: "I won't allow anyone to stop me! No matter who does what!" + }, + "victory": { + 1: "How can this be? I'm the creator of Team Plasma! I'm perfect!" + }, + "defeat": { + 1: "I am the perfect ruler of a perfect new world! Mwa ha ha!" + } + }, + "plasma_boss_ghetsis_2": { + "encounter": { + 1: "Come now! I want to see your face at the moment you lose all hope!" + }, + "victory": { + 1: "My calculations... No! My careful schemes! The world should be mine!" + }, + "defeat": { + 1: "Kyurem! Use Absofusion!" + } + }, + "flare_boss_lysandre_1": { + "encounter": { + 1: "Do you want to stop me? Show me in battle." + }, + "victory": { + 1: "You are here to stop me. But I ask you to wait. " + }, + "defeat": { + 1: "Pokemon...Shall no longer exist." + } + }, + "flare_boss_lysandre_2": { + "encounter": { + 1: "The future you want, or the future I want... Let us see which one is more deserving, shall we?" + }, + "victory": { + 1: "Whaugh!" + }, + "defeat": { + 1: "Fools with no vision will continue to befoul this beautiful world." + } + }, "brock": { "encounter": { 1: "My expertise on Rock-type Pokémon will take you down! Come on!", @@ -2372,7 +2552,7 @@ export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { }, "tate_liza_double": { "encounter": { - 1: `Tate: Are you suprised? + 1: `Tate: Are you surprised? $Liza: We are two gym leaders at once! $Tate: We are twins! $Liza: We dont need to talk to understand each other! @@ -2386,7 +2566,7 @@ export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { }, "liza_tate_double": { "encounter": { - 1: `Liza: Hihihi... Are you suprised? + 1: `Liza: Hihihi... Are you surprised? $Tate: Yes, we are really two gym leaders at once! $Liza: This is my twin brother Tate! $Tate: And this is my twin sister Liza! diff --git a/src/locales/en/game-mode.ts b/src/locales/en/game-mode.ts new file mode 100644 index 00000000000..be342b4c390 --- /dev/null +++ b/src/locales/en/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classic", + "endless": "Endless", + "endlessSpliced": "Endless (Spliced)", + "dailyRun": "Daily Run", + "unknown": "Unknown", + "challenge": "Challenge", +} as const; diff --git a/src/locales/en/menu.ts b/src/locales/en/menu.ts index d43ac0983f4..03b8f22332d 100644 --- a/src/locales/en/menu.ts +++ b/src/locales/en/menu.ts @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "Players Online", - "empty":"Empty", "yes":"Yes", "no":"No", "disclaimer": "DISCLAIMER", diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts index 0f7b83d2b3e..87d4a0ccf4f 100644 --- a/src/locales/en/modifier-type.ts +++ b/src/locales/en/modifier-type.ts @@ -8,7 +8,7 @@ export const modifierType: ModifierTypeTranslationEntries = { }, "AddVoucherModifierType": { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "Receive {{voucherTypeName}} x{{modifierCount}}", + description: "Receive {{voucherTypeName}} x{{modifierCount}}.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "Restores {{restorePoints}} HP or {{restorePercent}}% HP for one Pokémon, whichever is higher", + description: "Restores {{restorePoints}} HP or {{restorePercent}}% HP for one Pokémon, whichever is higher.", extra: { - "fully": "Fully restores HP for one Pokémon", - "fullyWithStatus": "Fully restores HP for one Pokémon and heals any status ailment", + "fully": "Fully restores HP for one Pokémon.", + "fullyWithStatus": "Fully restores HP for one Pokémon and heals any status ailment.", } }, "PokemonReviveModifierType": { - description: "Revives one Pokémon and restores {{restorePercent}}% HP", + description: "Revives one Pokémon and restores {{restorePercent}}% HP.", }, "PokemonStatusHealModifierType": { - description: "Heals any status ailment for one Pokémon", + description: "Heals any status ailment for one Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Restores {{restorePoints}} PP for one Pokémon move", + description: "Restores {{restorePoints}} PP for one Pokémon move.", extra: { - "fully": "Restores all PP for one Pokémon move", + "fully": "Restores all PP for one Pokémon move.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Restores {{restorePoints}} PP for all of one Pokémon's moves", + description: "Restores {{restorePoints}} PP for all of one Pokémon's moves.", extra: { - "fully": "Restores all PP for all of one Pokémon's moves", + "fully": "Restores all PP for all of one Pokémon's moves.", } }, "PokemonPpUpModifierType": { - description: "Permanently increases PP for one Pokémon move by {{upPoints}} for every 5 maximum PP (maximum 3)", + description: "Permanently increases PP for one Pokémon move by {{upPoints}} for every 5 maximum PP (maximum 3).", }, "PokemonNatureChangeModifierType": { name: "{{natureName}} Mint", description: "Changes a Pokémon's nature to {{natureName}} and permanently unlocks the nature for the starter.", }, "DoubleBattleChanceBoosterModifierType": { - description: "Doubles the chance of an encounter being a double battle for {{battleCount}} battles", + description: "Doubles the chance of an encounter being a double battle for {{battleCount}} battles.", }, "TempBattleStatBoosterModifierType": { - description: "Increases the {{tempBattleStatName}} of all party members by 1 stage for 5 battles", + description: "Increases the {{tempBattleStatName}} of all party members by 1 stage for 5 battles.", }, "AttackTypeBoosterModifierType": { - description: "Increases the power of a Pokémon's {{moveType}}-type moves by 20%", + description: "Increases the power of a Pokémon's {{moveType}}-type moves by 20%.", }, "PokemonLevelIncrementModifierType": { - description: "Increases a Pokémon's level by 1", + description: "Increases a Pokémon's level by 1.", }, "AllPokemonLevelIncrementModifierType": { - description: "Increases all party members' level by 1", + description: "Increases all party members' level by 1.", }, "PokemonBaseStatBoosterModifierType": { description: "Increases the holder's base {{statName}} by 10%. The higher your IVs, the higher the stack limit.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Restores 100% HP for all Pokémon", + description: "Restores 100% HP for all Pokémon.", }, "AllPokemonFullReviveModifierType": { - description: "Revives all fainted Pokémon, fully restoring HP", + description: "Revives all fainted Pokémon, fully restoring HP.", }, "MoneyRewardModifierType": { - description: "Grants a {{moneyMultiplier}} amount of money (₽{{moneyAmount}})", + description: "Grants a {{moneyMultiplier}} amount of money (₽{{moneyAmount}}).", extra: { "small": "small", "moderate": "moderate", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Increases gain of EXP. Points by {{boostPercent}}%", + description: "Increases gain of EXP. Points by {{boostPercent}}%.", }, "PokemonExpBoosterModifierType": { - description: "Increases the holder's gain of EXP. Points by {{boostPercent}}%", + description: "Increases the holder's gain of EXP. Points by {{boostPercent}}%.", }, "PokemonFriendshipBoosterModifierType": { - description: "Increases friendship gain per victory by 50%", + description: "Increases friendship gain per victory by 50%.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Increases move accuracy by {{accuracyAmount}} (maximum 100)", + description: "Increases move accuracy by {{accuracyAmount}} (maximum 100).", }, "PokemonMultiHitModifierType": { - description: "Attacks hit one additional time at the cost of a 60/75/82.5% power reduction per stack respectively", + description: "Attacks hit one additional time at the cost of a 60/75/82.5% power reduction per stack respectively.", }, "TmModifierType": { name: "TM{{moveId}} - {{moveName}}", - description: "Teach {{moveName}} to a Pokémon", + description: "Teach {{moveName}} to a Pokémon.", }, "TmModifierTypeWithInfo": { name: "TM{{moveId}} - {{moveName}}", - description: "Teach {{moveName}} to a Pokémon\n(Hold C or Shift for more info)", + description: "Teach {{moveName}} to a Pokémon\n(Hold C or Shift for more info).", }, "EvolutionItemModifierType": { - description: "Causes certain Pokémon to evolve", + description: "Causes certain Pokémon to evolve.", }, "FormChangeItemModifierType": { - description: "Causes certain Pokémon to change form", + description: "Causes certain Pokémon to change form.", }, "FusePokemonModifierType": { - description: "Combines two Pokémon (transfers Ability, splits base stats and types, shares move pool)", + description: "Combines two Pokémon (transfers Ability, splits base stats and types, shares move pool).", }, "TerastallizeModifierType": { name: "{{teraType}} Tera Shard", - description: "{{teraType}} Terastallizes the holder for up to 10 battles", + description: "{{teraType}} Terastallizes the holder for up to 10 battles.", }, "ContactHeldItemTransferChanceModifierType": { - description: "Upon attacking, there is a {{chancePercent}}% chance the foe's held item will be stolen", + description: "Upon attacking, there is a {{chancePercent}}% chance the foe's held item will be stolen.", }, "TurnHeldItemTransferModifierType": { - description: "Every turn, the holder acquires one held item from the foe", + description: "Every turn, the holder acquires one held item from the foe.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Adds a {{chancePercent}}% chance to inflict {{statusEffect}} with attack moves", + description: "Adds a {{chancePercent}}% chance to inflict {{statusEffect}} with attack moves.", }, "EnemyEndureChanceModifierType": { - description: "Adds a {{chancePercent}}% chance of enduring a hit", + description: "Adds a {{chancePercent}}% chance of enduring a hit.", }, "RARE_CANDY": { name: "Rare Candy" }, "RARER_CANDY": { name: "Rarer Candy" }, - "MEGA_BRACELET": { name: "Mega Bracelet", description: "Mega Stones become available" }, - "DYNAMAX_BAND": { name: "Dynamax Band", description: "Max Mushrooms become available" }, - "TERA_ORB": { name: "Tera Orb", description: "Tera Shards become available" }, + "MEGA_BRACELET": { name: "Mega Bracelet", description: "Mega Stones become available." }, + "DYNAMAX_BAND": { name: "Dynamax Band", description: "Max Mushrooms become available." }, + "TERA_ORB": { name: "Tera Orb", description: "Tera Shards become available." }, - "MAP": { name: "Map", description: "Allows you to choose your destination at a crossroads" }, + "MAP": { name: "Map", description: "Allows you to choose your destination at a crossroads." }, "POTION": { name: "Potion" }, "SUPER_POTION": { name: "Super Potion" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Sacred Ash" }, - "REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting" }, + "REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting." }, "ETHER": { name: "Ether" }, "MAX_ETHER": { name: "Max Ether" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "Super Lure" }, "MAX_LURE": { name: "Max Lure" }, - "MEMORY_MUSHROOM": { name: "Memory Mushroom", description: "Recall one Pokémon's forgotten move" }, + "MEMORY_MUSHROOM": { name: "Memory Mushroom", description: "Recall one Pokémon's forgotten move." }, - "EXP_SHARE": { name: "EXP. All", description: "Non-participants receive 20% of a single participant's EXP. Points" }, - "EXP_BALANCE": { name: "EXP. Balance", description: "Weighs EXP. Points received from battles towards lower-leveled party members" }, + "EXP_SHARE": { name: "EXP. All", description: "Non-participants receive 20% of a single participant's EXP. Points." }, + "EXP_BALANCE": { name: "EXP. Balance", description: "Weighs EXP. Points received from battles towards lower-leveled party members." }, - "OVAL_CHARM": { name: "Oval Charm", description: "When multiple Pokémon participate in a battle, each gets an extra 10% of the total EXP" }, + "OVAL_CHARM": { name: "Oval Charm", description: "When multiple Pokémon participate in a battle, each gets an extra 10% of the total EXP." }, "EXP_CHARM": { name: "EXP. Charm" }, "SUPER_EXP_CHARM": { name: "Super EXP. Charm" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Soothe Bell" }, - "SOUL_DEW": { name: "Soul Dew", description: "Increases the influence of a Pokémon's nature on its stats by 10% (additive)" }, + "SOUL_DEW": { name: "Soul Dew", description: "Increases the influence of a Pokémon's nature on its stats by 10% (additive)." }, "NUGGET": { name: "Nugget" }, "BIG_NUGGET": { name: "Big Nugget" }, "RELIC_GOLD": { name: "Relic Gold" }, - "AMULET_COIN": { name: "Amulet Coin", description: "Increases money rewards by 20%" }, - "GOLDEN_PUNCH": { name: "Golden Punch", description: "Grants 50% of direct damage inflicted as money" }, - "COIN_CASE": { name: "Coin Case", description: "After every 10th battle, receive 10% of your money in interest" }, + "AMULET_COIN": { name: "Amulet Coin", description: "Increases money rewards by 20%." }, + "GOLDEN_PUNCH": { name: "Golden Punch", description: "Grants 50% of direct damage inflicted as money." }, + "COIN_CASE": { name: "Coin Case", description: "After every 10th battle, receive 10% of your money in interest." }, - "LOCK_CAPSULE": { name: "Lock Capsule", description: "Allows you to lock item rarities when rerolling items" }, + "LOCK_CAPSULE": { name: "Lock Capsule", description: "Allows you to lock item rarities when rerolling items." }, "GRIP_CLAW": { name: "Grip Claw" }, "WIDE_LENS": { name: "Wide Lens" }, "MULTI_LENS": { name: "Multi Lens" }, - "HEALING_CHARM": { name: "Healing Charm", description: "Increases the effectiveness of HP restoring moves and items by 10% (excludes Revives)" }, - "CANDY_JAR": { name: "Candy Jar", description: "Increases the number of levels added by Rare Candy items by 1" }, + "HEALING_CHARM": { name: "Healing Charm", description: "Increases the effectiveness of HP restoring moves and items by 10% (excludes Revives)." }, + "CANDY_JAR": { name: "Candy Jar", description: "Increases the number of levels added by Rare Candy items by 1." }, - "BERRY_POUCH": { name: "Berry Pouch", description: "Adds a 30% chance that a used berry will not be consumed" }, + "BERRY_POUCH": { name: "Berry Pouch", description: "Adds a 30% chance that a used berry will not be consumed." }, - "FOCUS_BAND": { name: "Focus Band", description: "Adds a 10% chance to survive with 1 HP after being damaged enough to faint" }, + "FOCUS_BAND": { name: "Focus Band", description: "Adds a 10% chance to survive with 1 HP after being damaged enough to faint." }, - "QUICK_CLAW": { name: "Quick Claw", description: "Adds a 10% chance to move first regardless of speed (after priority)" }, + "QUICK_CLAW": { name: "Quick Claw", description: "Adds a 10% chance to move first regardless of speed (after priority)." }, - "KINGS_ROCK": { name: "King's Rock", description: "Adds a 10% chance an attack move will cause the opponent to flinch" }, + "KINGS_ROCK": { name: "King's Rock", description: "Adds a 10% chance an attack move will cause the opponent to flinch." }, - "LEFTOVERS": { name: "Leftovers", description: "Heals 1/16 of a Pokémon's maximum HP every turn" }, - "SHELL_BELL": { name: "Shell Bell", description: "Heals 1/8 of a Pokémon's dealt damage" }, + "LEFTOVERS": { name: "Leftovers", description: "Heals 1/16 of a Pokémon's maximum HP every turn." }, + "SHELL_BELL": { name: "Shell Bell", description: "Heals 1/8 of a Pokémon's dealt damage." }, - "TOXIC_ORB": { name: "Toxic Orb", description: "Badly poisons its holder at the end of the turn if they do not have a status condition already" }, - "FLAME_ORB": { name: "Flame Orb", description: "Burns its holder at the end of the turn if they do not have a status condition already" }, + "TOXIC_ORB": { name: "Toxic Orb", description: "It's a bizarre orb that exudes toxins when touched and will badly poison the holder during battle." }, + "FLAME_ORB": { name: "Flame Orb", description: "It's a bizarre orb that gives off heat when touched and will affect the holder with a burn during battle." }, - "BATON": { name: "Baton", description: "Allows passing along effects when switching Pokémon, which also bypasses traps" }, + "BATON": { name: "Baton", description: "Allows passing along effects when switching Pokémon, which also bypasses traps." }, - "SHINY_CHARM": { name: "Shiny Charm", description: "Dramatically increases the chance of a wild Pokémon being Shiny" }, - "ABILITY_CHARM": { name: "Ability Charm", description: "Dramatically increases the chance of a wild Pokémon having a Hidden Ability" }, + "SHINY_CHARM": { name: "Shiny Charm", description: "Dramatically increases the chance of a wild Pokémon being Shiny." }, + "ABILITY_CHARM": { name: "Ability Charm", description: "Dramatically increases the chance of a wild Pokémon having a Hidden Ability." }, - "IV_SCANNER": { name: "IV Scanner", description: "Allows scanning the IVs of wild Pokémon. 2 IVs are revealed per stack. The best IVs are shown first" }, + "IV_SCANNER": { name: "IV Scanner", description: "Allows scanning the IVs of wild Pokémon. 2 IVs are revealed per stack. The best IVs are shown first." }, "DNA_SPLICERS": { name: "DNA Splicers" }, "MINI_BLACK_HOLE": { name: "Mini Black Hole" }, - "GOLDEN_POKEBALL": { name: "Golden Poké Ball", description: "Adds 1 extra item option at the end of every battle" }, + "GOLDEN_POKEBALL": { name: "Golden Poké Ball", description: "Adds 1 extra item option at the end of every battle." }, - "ENEMY_DAMAGE_BOOSTER": { name: "Damage Token", description: "Increases damage by 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Protection Token", description: "Reduces incoming damage by 2.5%" }, - "ENEMY_HEAL": { name: "Recovery Token", description: "Heals 2% of max HP every turn" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Damage Token", description: "Increases damage by 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Protection Token", description: "Reduces incoming damage by 2.5%." }, + "ENEMY_HEAL": { name: "Recovery Token", description: "Heals 2% of max HP every turn." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "Poison Token" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Paralyze Token" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "Burn Token" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Full Heal Token", description: "Adds a 2.5% chance every turn to heal a status condition" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Full Heal Token", description: "Adds a 2.5% chance every turn to heal a status condition." }, "ENEMY_ENDURE_CHANCE": { name: "Endure Token" }, - "ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Adds a 1% chance that a wild Pokémon will be a fusion" }, + "ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Adds a 1% chance that a wild Pokémon will be a fusion." }, }, TempBattleStatBoosterItem: { "x_attack": "X Attack", @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "Burn Drive", "CHILL_DRIVE": "Chill Drive", "DOUSE_DRIVE": "Douse Drive", + + "FIST_PLATE": "Fist Plate", + "SKY_PLATE": "Sky Plate", + "TOXIC_PLATE": "Toxic Plate", + "EARTH_PLATE": "Earth Plate", + "STONE_PLATE": "Stone Plate", + "INSECT_PLATE": "Insect Plate", + "SPOOKY_PLATE": "Spooky Plate", + "IRON_PLATE": "Iron Plate", + "FLAME_PLATE": "Flame Plate", + "SPLASH_PLATE": "Splash Plate", + "MEADOW_PLATE": "Meadow Plate", + "ZAP_PLATE": "Zap Plate", + "MIND_PLATE": "Mind Plate", + "ICICLE_PLATE": "Icicle Plate", + "DRACO_PLATE": "Draco Plate", + "DREAD_PLATE": "Dread Plate", + "PIXIE_PLATE": "Pixie Plate", + "BLANK_PLATE": "Blank Plate", + "LEGEND_PLATE": "Legend Plate", + "FIGHTING_MEMORY": "Fighting Memory", + "FLYING_MEMORY": "Flying Memory", + "POISON_MEMORY": "Poison Memory", + "GROUND_MEMORY": "Ground Memory", + "ROCK_MEMORY": "Rock Memory", + "BUG_MEMORY": "Bug Memory", + "GHOST_MEMORY": "Ghost Memory", + "STEEL_MEMORY": "Steel Memory", + "FIRE_MEMORY": "Fire Memory", + "WATER_MEMORY": "Water Memory", + "GRASS_MEMORY": "Grass Memory", + "ELECTRIC_MEMORY": "Electric Memory", + "PSYCHIC_MEMORY": "Psychic Memory", + "ICE_MEMORY": "Ice Memory", + "DRAGON_MEMORY": "Dragon Memory", + "DARK_MEMORY": "Dark Memory", + "FAIRY_MEMORY": "Fairy Memory", + "BLANK_MEMORY": "Blank Memory", }, } as const; diff --git a/src/locales/en/pokemon-info-container.ts b/src/locales/en/pokemon-info-container.ts index 068c9ebb431..6b3ef954f58 100644 --- a/src/locales/en/pokemon-info-container.ts +++ b/src/locales/en/pokemon-info-container.ts @@ -7,5 +7,6 @@ export const pokemonInfoContainer: SimpleTranslationEntries = { "nature": "Nature:", "epic": "Epic", "rare": "Rare", - "common": "Common" + "common": "Common", + "form": "Form:" } as const; diff --git a/src/locales/en/save-slot-select-ui-handler.ts b/src/locales/en/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..5aaa675fc4d --- /dev/null +++ b/src/locales/en/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Overwrite the data in the selected slot?", + "loading": "Loading...", + "wave": "Wave", + "lv": "Lv", + "empty": "Empty", +} as const; diff --git a/src/locales/en/starter-select-ui-handler.ts b/src/locales/en/starter-select-ui-handler.ts index 857ba4d805c..fd2eb6c40df 100644 --- a/src/locales/en/starter-select-ui-handler.ts +++ b/src/locales/en/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Select a move to swap with", "unlockPassive": "Unlock Passive", "reduceCost": "Reduce Cost", - "cycleShiny": "R: Cycle Shiny", - "cycleForm": "F: Cycle Form", - "cycleGender": "G: Cycle Gender", - "cycleAbility": "E: Cycle Ability", - "cycleNature": "N: Cycle Nature", - "cycleVariant": "V: Cycle Variant", + "cycleShiny": ": Shiny", + "cycleForm": ": Form", + "cycleGender": ": Gender", + "cycleAbility": ": Ability", + "cycleNature": ": Nature", + "cycleVariant": ": Variant", "enablePassive": "Enable Passive", "disablePassive": "Disable Passive", "locked": "Locked", diff --git a/src/locales/en/trainers.ts b/src/locales/en/trainers.ts index 701980f8d37..39ca5f7512c 100644 --- a/src/locales/en/trainers.ts +++ b/src/locales/en/trainers.ts @@ -13,6 +13,12 @@ export const titles: SimpleTranslationEntries = { "rival": "Rival", "professor": "Professor", "frontier_brain": "Frontier Brain", + "rocket_boss": "Team Rocket Boss", + "magma_boss": "Team Magma Boss", + "aqua_boss": "Team Aqua Boss", + "galactic_boss": "Team Galactic Boss", + "plasma_boss": "Team Plasma Boss", + "flare_boss": "Team Flare Boss", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -118,7 +124,19 @@ export const trainerClasses: SimpleTranslationEntries = { "worker": "Worker", "worker_female": "Worker", "workers": "Workers", - "youngster": "Youngster" + "youngster": "Youngster", + "rocket_grunt": "Rocket Grunt", + "rocket_grunt_female": "Rocket Grunt", + "magma_grunt": "Magma Grunt", + "magma_grunt_female": "Magma Grunt", + "aqua_grunt": "Aqua Grunt", + "aqua_grunt_female": "Aqua Grunt", + "galactic_grunt": "Galactic Grunt", + "galactic_grunt_female": "Galactic Grunt", + "plasma_grunt": "Plasma Grunt", + "plasma_grunt_female": "Plasma Grunt", + "flare_grunt": "Flare Grunt", + "flare_grunt_female": "Flare Grunt", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -247,6 +265,11 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Leon", "rival": "Finn", "rival_female": "Ivy", + "maxie": "Maxie", + "archie": "Archie", + "cyrus": "Cyrus", + "ghetsis": "Ghetsis", + "lysandre": "Lysandre", // Double Names "blue_red_double": "Blue & Red", diff --git a/src/locales/es/ability-trigger.ts b/src/locales/es/ability-trigger.ts index 3ede2cd9cf3..e6dde7ad79f 100644 --- a/src/locales/es/ability-trigger.ts +++ b/src/locales/es/ability-trigger.ts @@ -4,5 +4,5 @@ export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!", "badDreams": "¡{{pokemonName}} está atormentado!", "windPowerCharged": "¡{{pokemonName}} se ha cargado de electricidad gracias a {{moveName}}!", - "iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!" + "iceFaceAvoidedDamage": "¡{{pokemonNameWithAffix}} evitó\ndaño con {{abilityName}}!" } as const; diff --git a/src/locales/es/achv.ts b/src/locales/es/achv.ts index 071c0cbb860..8d9ebc7d457 100644 --- a/src/locales/es/achv.ts +++ b/src/locales/es/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Logros", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "Imbatible", description: "Completa el juego en modo clásico.", }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Mono NORMAL", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Mono FLYING", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Mono GROUND", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "Sting Like A Beedrill", + }, + "MONO_GHOST": { + name: "Who you gonna call?", + }, + "MONO_STEEL": { + name: "Mono STEEL", + }, + "MONO_FIRE": { + name: "Mono FIRE", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Mono GRASS", + }, + "MONO_ELECTRIC": { + name: "Mono ELECTRIC", + }, + "MONO_PSYCHIC": { + name: "Mono PSYCHIC", + }, + "MONO_ICE": { + name: "Mono ICE", + }, + "MONO_DRAGON": { + name: "Mono DRAGON", + }, + "MONO_DARK": { + name: "It's just a phase", + }, + "MONO_FAIRY": { + name: "Mono FAIRY", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts index c4d79cfdb93..4f60ab28d8a 100644 --- a/src/locales/es/battle.ts +++ b/src/locales/es/battle.ts @@ -18,11 +18,11 @@ export const battle: SimpleTranslationEntries = { "partyFull": "Tu equipo esta completo.\n¿Quieres liberar un Pokémon para meter a {{pokemonName}}?", "pokemon": "Pokémon", "sendOutPokemon": "¡Adelante, {{pokemonName}}!", - "hitResultCriticalHit": "!Un golpe crítico!", - "hitResultSuperEffective": "!Es supereficaz!", + "hitResultCriticalHit": "¡Un golpe crítico!", + "hitResultSuperEffective": "¡Es supereficaz!", "hitResultNotVeryEffective": "No es muy eficaz…", "hitResultNoEffect": "No afecta a {{pokemonName}}!", - "hitResultOneHitKO": "!KO en 1 golpe!", + "hitResultOneHitKO": "¡KO en 1 golpe!", "attackFailed": "¡Pero ha fallado!", "attackHitsCount": "N.º de golpes: {{count}}.", "expGain": "{{pokemonName}} ha ganado\n{{exp}} puntos de experiencia.", @@ -56,9 +56,9 @@ export const battle: SimpleTranslationEntries = { "skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?", "eggHatching": "¿Y esto?", "ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?", - "wildPokemonWithAffix": "Wild {{pokemonName}}", - "foePokemonWithAffix": "Foe {{pokemonName}}", - "useMove": "{{pokemonNameWithAffix}} used {{moveName}}!", - "drainMessage": "{{pokemonName}} had its\nenergy drained!", - "regainHealth": "{{pokemonName}} regained\nhealth!" + "wildPokemonWithAffix": "El {{pokemonName}} salvaje", + "foePokemonWithAffix": "El {{pokemonName}} enemigo", + "useMove": "¡{{pokemonNameWithAffix}} usó {{moveName}}!", + "drainMessage": "¡{{pokemonName}} tuvo su\nenergía absorbida!", + "regainHealth": "¡{{pokemonName}} recuperó\nPS!" } as const; diff --git a/src/locales/es/challenges.ts b/src/locales/es/challenges.ts new file mode 100644 index 00000000000..6c994e5f4b3 --- /dev/null +++ b/src/locales/es/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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.", +} as const; diff --git a/src/locales/es/config.ts b/src/locales/es/config.ts index f6d1ac0f1c1..8b482de5c78 100644 --- a/src/locales/es/config.ts +++ b/src/locales/es/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const esConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const esConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const esConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/es/game-mode.ts b/src/locales/es/game-mode.ts new file mode 100644 index 00000000000..dcff983791f --- /dev/null +++ b/src/locales/es/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Clásica", + "endless": "Infinita", + "endlessSpliced": "Infinita (Fusión)", + "dailyRun": "Diaria", + "unknown": "Desconicido", + "challenge": "Desafío", +} as const; diff --git a/src/locales/es/menu.ts b/src/locales/es/menu.ts index 517569ff40b..4bd6d750d69 100644 --- a/src/locales/es/menu.ts +++ b/src/locales/es/menu.ts @@ -45,10 +45,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Rankings Semanales", "noRankings": "Sin Rankings", "loading": "Cargando…", + "loadingAsset": "Cargando recurso: {{assetName}}", "playersOnline": "Jugadores en Línea", - "empty":"Vacío", "yes":"Sí", "no":"No", - "disclaimer": "DISCLAIMER", - "disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed." + "disclaimer": "AVISO", + "disclaimerDescription": "Este juego es un producto inacabado; puede tener problemas de jugabilidad (incluyendo la posible pérdida de datos de guardado),\ncambiar sin avisar, y puede o no puede ser actualizado hasta ser completado." } as const; diff --git a/src/locales/es/modifier-type.ts b/src/locales/es/modifier-type.ts index f6565486bb1..3c1925eaa67 100644 --- a/src/locales/es/modifier-type.ts +++ b/src/locales/es/modifier-type.ts @@ -4,11 +4,11 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{modifierCount}}x {{pokeballName}}", - description: "Recibes {{modifierCount}}x {{pokeballName}} (En inventario: {{pokeballAmount}}) \nRatio de captura: {{catchRate}}", + description: "Recibes {{modifierCount}}x {{pokeballName}} (En inventario: {{pokeballAmount}}) \nRatio de captura: {{catchRate}}.", }, "AddVoucherModifierType": { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "Recibes {{modifierCount}}x {{voucherTypeName}}", + description: "Recibes {{modifierCount}}x {{voucherTypeName}}.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "Restaura {{restorePoints}} PS o, al menos, un {{restorePercent}}% PS de un Pokémon", + description: "Restaura {{restorePoints}} PS o, al menos, un {{restorePercent}}% PS de un Pokémon.", extra: { - "fully": "Restaura todos los PS de un Pokémon", - "fullyWithStatus": "Restaura todos los PS de un Pokémon y cura todos los problemas de estados", + "fully": "Restaura todos los PS de un Pokémon.", + "fullyWithStatus": "Restaura todos los PS de un Pokémon y cura todos los problemas de estados.", } }, "PokemonReviveModifierType": { - description: "Revive a un Pokémon y restaura {{restorePercent}}% PS", + description: "Revive a un Pokémon y restaura {{restorePercent}}% PS.", }, "PokemonStatusHealModifierType": { - description: "Cura todos los problemas de estados de un Pokémon", + description: "Cura todos los problemas de estados de un Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Restaura {{restorePoints}} PP del movimiento que elijas de un Pokémon", + description: "Restaura {{restorePoints}} PP del movimiento que elijas de un Pokémon.", extra: { - "fully": "Restaura todos los PP del movimiento que elijas de un Pokémon", + "fully": "Restaura todos los PP del movimiento que elijas de un Pokémon.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Restaura {{restorePoints}} PP de todos los movimientos de un Pokémon", + description: "Restaura {{restorePoints}} PP de todos los movimientos de un Pokémon.", extra: { - "fully": "Restaura todos los PP de todos los movimientos de un Pokémon", + "fully": "Restaura todos los PP de todos los movimientos de un Pokémon.", } }, "PokemonPpUpModifierType": { - description: "Aumenta permanentemente los PP para un movimiento de un Pokémon en {{upPoints}} por cada 5 PP máximo (máximo 3)", + description: "Aumenta permanentemente los PP para un movimiento de un Pokémon en {{upPoints}} por cada 5 PP máximo (máximo 3).", }, "PokemonNatureChangeModifierType": { name: "Menta {{natureName}}", - description: "Cambia la naturaleza de un Pokémon a {{natureName}} y desbloquea permanentemente dicha naturaleza para el inicial", + description: "Cambia la naturaleza de un Pokémon a {{natureName}} y desbloquea permanentemente dicha naturaleza para el inicial.", }, "DoubleBattleChanceBoosterModifierType": { - description: "Duplica la posibilidad de que un encuentro sea una combate doble durante {{battleCount}} combates", + description: "Duplica la posibilidad de que un encuentro sea una combate doble durante {{battleCount}} combates.", }, "TempBattleStatBoosterModifierType": { - description: "Aumenta la est. {{tempBattleStatName}} de todos los miembros del equipo en 1 nivel durante 5 combates", + description: "Aumenta la est. {{tempBattleStatName}} de todos los miembros del equipo en 1 nivel durante 5 combates.", }, "AttackTypeBoosterModifierType": { - description: "Aumenta la potencia de los movimientos de tipo {{moveType}} de un Pokémon en un 20%", + description: "Aumenta la potencia de los movimientos de tipo {{moveType}} de un Pokémon en un 20%.", }, "PokemonLevelIncrementModifierType": { - description: "Aumenta el nivel de un Pokémon en 1", + description: "Aumenta el nivel de un Pokémon en 1.", }, "AllPokemonLevelIncrementModifierType": { - description: "Aumenta el nivel de todos los miembros del equipo en 1", + description: "Aumenta el nivel de todos los miembros del equipo en 1.", }, "PokemonBaseStatBoosterModifierType": { - description: "Aumenta la est. {{statName}} base del portador en un 10%.\nCuanto mayores sean tus IVs, mayor será el límite de acumulación", + description: "Aumenta la est. {{statName}} base del portador en un 10%.\nCuanto mayores sean tus IVs, mayor será el límite de acumulación.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Restaura el 100% de los PS de todos los Pokémon", + description: "Restaura el 100% de los PS de todos los Pokémon.", }, "AllPokemonFullReviveModifierType": { - description: "Revive a todos los Pokémon debilitados y restaura completamente sus PS", + description: "Revive a todos los Pokémon debilitados y restaura completamente sus PS.", }, "MoneyRewardModifierType": { - description: "Otorga una {{moneyMultiplier}} cantidad de dinero (₽{{moneyAmount}})", + description: "Otorga una {{moneyMultiplier}} cantidad de dinero (₽{{moneyAmount}}).", extra: { "small": "pequeña", "moderate": "moderada", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Aumenta la ganancia de EXP en un {{boostPercent}}%", + description: "Aumenta la ganancia de EXP en un {{boostPercent}}%.", }, "PokemonExpBoosterModifierType": { - description: "Aumenta la ganancia de EXP del portador en un {{boostPercent}}%", + description: "Aumenta la ganancia de EXP del portador en un {{boostPercent}}%.", }, "PokemonFriendshipBoosterModifierType": { - description: "Aumenta la ganancia de amistad por victoria en un 50%", + description: "Aumenta la ganancia de amistad por victoria en un 50%.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Aumenta la precisión de los movimiento en un {{accuracyAmount}} (máximo 100)", + description: "Aumenta la precisión de los movimiento en un {{accuracyAmount}} (máximo 100).", }, "PokemonMultiHitModifierType": { - description: "Los ataques golpean una vez más a costa de una reducción de poder del 60/75/82,5% por cada objeto", + description: "Los ataques golpean una vez más a costa de una reducción de poder del 60/75/82,5% por cada objeto.", }, "TmModifierType": { name: "MT{{moveId}} - {{moveName}}", - description: "Enseña {{moveName}} a un Pokémon", + description: "Enseña {{moveName}} a un Pokémon.", }, "TmModifierTypeWithInfo": { name: "MT{{moveId}} - {{moveName}}", - description: "Enseña {{moveName}} a un Pokémon\n(Hold C or Shift for more info)", + description: "Enseña {{moveName}} a un Pokémon\n(Hold C or Shift for more info).", }, "EvolutionItemModifierType": { - description: "Hace que ciertos Pokémon evolucionen", + description: "Hace que ciertos Pokémon evolucionen.", }, "FormChangeItemModifierType": { - description: "Hace que ciertos Pokémon cambien de forma", + description: "Hace que ciertos Pokémon cambien de forma.", }, "FusePokemonModifierType": { - description: "Fusiona dos Pokémon (transfiere habilidades, divide estadísticas bases y tipos, comparte movimientos)", + description: "Fusiona dos Pokémon (transfiere habilidades, divide estadísticas bases y tipos, comparte movimientos).", }, "TerastallizeModifierType": { name: "Teralito {{teraType}}", - description: "Teracristaliza al portador al tipo {{teraType}} durante 10 combates", + description: "Teracristaliza al portador al tipo {{teraType}} durante 10 combates.", }, "ContactHeldItemTransferChanceModifierType": { - description: "Al atacar, hay un {{chancePercent}}% de posibilidades de que robes el objeto que tiene el enemigo", + description: "Al atacar, hay un {{chancePercent}}% de posibilidades de que robes el objeto que tiene el enemigo.", }, "TurnHeldItemTransferModifierType": { - description: "Cada turno, el portador roba un objeto del enemigo", + description: "Cada turno, el portador roba un objeto del enemigo.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Agrega un {{chancePercent}}% de probabilidad de infligir {{statusEffect}} con movimientos de ataque", + description: "Agrega un {{chancePercent}}% de probabilidad de infligir {{statusEffect}} con movimientos de ataque.", }, "EnemyEndureChanceModifierType": { - description: "Agrega un {{chancePercent}}% de probabilidad de resistir un ataque que lo debilitaría", + description: "Agrega un {{chancePercent}}% de probabilidad de resistir un ataque que lo debilitaría.", }, "RARE_CANDY": { name: "Carameloraro" }, - "RARER_CANDY": { name: "Rarer Candy" }, + "RARER_CANDY": { name: "Caramelorarísimo" }, - "MEGA_BRACELET": { name: "Mega-aro", description: "Las Megapiedras están disponibles" }, - "DYNAMAX_BAND": { name: "Maximuñequera", description: "Las Maxisetas están disponibles" }, - "TERA_ORB": { name: "Orbe Teracristal", description: "Los Teralitos están disponibles" }, + "MEGA_BRACELET": { name: "Mega-aro", description: "Las Megapiedras están disponibles." }, + "DYNAMAX_BAND": { name: "Maximuñequera", description: "Las Maxisetas están disponibles." }, + "TERA_ORB": { name: "Orbe Teracristal", description: "Los Teralitos están disponibles." }, - "MAP": { name: "Mapa", description: "Te permite elegir tu camino al final del bioma" }, + "MAP": { name: "Mapa", description: "Te permite elegir tu camino al final del bioma." }, "POTION": { name: "Poción" }, "SUPER_POTION": { name: "Superpoción" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cen. Sagrada" }, - "REVIVER_SEED": { name: "Semilla Revivir", description: "Revive al portador con la mitad de sus PS al debilitarse" }, + "REVIVER_SEED": { name: "Semilla Revivir", description: "Revive al portador con la mitad de sus PS al debilitarse." }, "ETHER": { name: "Éter" }, "MAX_ETHER": { name: "Éter Máx." }, @@ -162,16 +162,16 @@ export const modifierType: ModifierTypeTranslationEntries = { "PP_UP": { name: "Más PP" }, "PP_MAX": { name: "Máx PP" }, - "LURE": { name: "Lure" }, - "SUPER_LURE": { name: "Super Lure" }, - "MAX_LURE": { name: "Max Lure" }, + "LURE": { name: "Incienso" }, + "SUPER_LURE": { name: "Superincienso" }, + "MAX_LURE": { name: "Incienso Máximo" }, - "MEMORY_MUSHROOM": { name: "Memory Mushroom", description: "Recall one Pokémon's forgotten move" }, + "MEMORY_MUSHROOM": { name: "Seta Recuerdo", description: "Recuerda un movimiento olvidado de un Pokémon." }, - "EXP_SHARE": { name: "Repartir EXP", description: "Los que no combatan reciben el 20% de la EXP" }, - "EXP_BALANCE": { name: "EXP. Balance", description: "Da mayor parte de la EXP recibida a los miembros del equipo que tengan menos nivel" }, + "EXP_SHARE": { name: "Repartir EXP", description: "Los que no combatan reciben el 20% de la EXP." }, + "EXP_BALANCE": { name: "Equilibrar EXP", description: "Da mayor parte de la EXP recibida a los miembros del equipo que tengan menos nivel." }, - "OVAL_CHARM": { name: "Amuleto Oval", description: "Cada Pokémon combatiente recibe un 10% adicional de la EXP total" }, + "OVAL_CHARM": { name: "Amuleto Oval", description: "Cada Pokémon combatiente recibe un 10% adicional de la EXP total." }, "EXP_CHARM": { name: "Amuleto EXP" }, "SUPER_EXP_CHARM": { name: "Super Amuleto EXP" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Camp. Alivio" }, - "SOUL_DEW": { name: "Rocío bondad", description: "Aumenta la influencia de la naturaleza de un Pokémon en sus estadísticas en un 10% (aditivo)" }, + "SOUL_DEW": { name: "Rocío bondad", description: "Aumenta la influencia de la naturaleza de un Pokémon en sus estadísticas en un 10% (aditivo)." }, "NUGGET": { name: "Pepita" }, "BIG_NUGGET": { name: "Maxipepita" }, "RELIC_GOLD": { name: "Real de oro" }, - "AMULET_COIN": { name: "Moneda Amuleto", description: "Aumenta el dinero ganado en un 20%" }, - "GOLDEN_PUNCH": { name: "Puño Dorado", description: "Otorga el 50% del daño infligido como dinero" }, - "COIN_CASE": { name: "Monedero", description: "Después de cada 10 combates, recibe el 10% de tu dinero en intereses" }, + "AMULET_COIN": { name: "Moneda Amuleto", description: "Aumenta el dinero ganado en un 20%." }, + "GOLDEN_PUNCH": { name: "Puño Dorado", description: "Otorga el 50% del daño infligido como dinero." }, + "COIN_CASE": { name: "Monedero", description: "Después de cada 10 combates, recibe el 10% de tu dinero en intereses." }, - "LOCK_CAPSULE": { name: "Cápsula candado", description: "Le permite bloquear las rarezas de los objetos al cambiar de objetos" }, + "LOCK_CAPSULE": { name: "Cápsula candado", description: "Le permite bloquear las rarezas de los objetos al cambiar de objetos." }, "GRIP_CLAW": { name: "Garra Garfio" }, "WIDE_LENS": { name: "Lupa" }, - "MULTI_LENS": { name: "Multi Lens" }, + "MULTI_LENS": { name: "Multilupa" }, - "HEALING_CHARM": { name: "Amuleto curación", description: "Aumenta la efectividad de los movimientos y objetos de curacion de PS en un 10% (excepto revivir)" }, - "CANDY_JAR": { name: "Candy Jar", description: "Aumenta en 1 el número de niveles añadidos por los carameloraros" }, + "HEALING_CHARM": { name: "Amuleto curación", description: "Aumenta la efectividad de los movimientos y objetos de curacion de PS en un 10% (excepto revivir)." }, + "CANDY_JAR": { name: "Candy Jar", description: "Aumenta en 1 el número de niveles añadidos por los carameloraros." }, - "BERRY_POUCH": { name: "Saco Bayas", description: "Agrega un 30% de posibilidades de que una baya usada no se consuma" }, + "BERRY_POUCH": { name: "Saco Bayas", description: "Agrega un 30% de posibilidades de que una baya usada no se consuma." }, - "FOCUS_BAND": { name: "Cinta Focus", description: "Agrega un 10% de probabilidad de resistir un ataque que lo debilitaría" }, + "FOCUS_BAND": { name: "Cinta Focus", description: "Agrega un 10% de probabilidad de resistir un ataque que lo debilitaría." }, - "QUICK_CLAW": { name: "Garra Rápida", description: "Agrega un 10% de probabilidad de atacar primero independientemente de la velocidad (después de la prioridad)" }, + "QUICK_CLAW": { name: "Garra Rápida", description: "Agrega un 10% de probabilidad de atacar primero independientemente de la velocidad (después de la prioridad)." }, - "KINGS_ROCK": { name: "Roca del Rey", description: "Agrega un 10% de probabilidad de que un ataque haga que el oponente retroceda" }, + "KINGS_ROCK": { name: "Roca del Rey", description: "Agrega un 10% de probabilidad de que un ataque haga que el oponente retroceda." }, - "LEFTOVERS": { name: "Restos", description: "Cura 1/16 de los PS máximo de un Pokémon cada turno" }, - "SHELL_BELL": { name: "Camp Concha", description: "Cura 1/8 del daño infligido por un Pokémon" }, + "LEFTOVERS": { name: "Restos", description: "Cura 1/16 de los PS máximo de un Pokémon cada turno." }, + "SHELL_BELL": { name: "Camp Concha", description: "Cura 1/8 del daño infligido por un Pokémon." }, - "TOXIC_ORB": { name: "Toxiesfera", description: "Extraña esfera que envenena gravemente a quien la usa en combate" }, - "FLAME_ORB": { name: "Llamasfera", description: "Extraña esfera que causa quemaduras a quien la usa en combate" }, + "TOXIC_ORB": { name: "Toxiesfera", description: "Extraña esfera que envenena gravemente a quien la usa en combate." }, + "FLAME_ORB": { name: "Llamasfera", description: "Extraña esfera que causa quemaduras a quien la usa en combate." }, - "BATON": { name: "Baton", description: "Permite pasar los efectos al cambiar de Pokémon, también evita las trampas" }, + "BATON": { name: "Relevo", description: "Permite pasar los efectos al cambiar de Pokémon, también evita las trampas." }, - "SHINY_CHARM": { name: "Amuleto Iris", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje sea Shiny" }, - "ABILITY_CHARM": { name: "Amuleto Habilidad", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje tenga una habilidad oculta" }, + "SHINY_CHARM": { name: "Amuleto Iris", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje sea Shiny." }, + "ABILITY_CHARM": { name: "Amuleto Habilidad", description: "Aumenta drásticamente la posibilidad de que un Pokémon salvaje tenga una habilidad oculta." }, - "IV_SCANNER": { name: "Escáner IV", description: "Permite escanear los IVs de Pokémon salvajes. Se revelan 2 IVs por cada objeto.\nLos mejores IVs se muestran primero" }, + "IV_SCANNER": { name: "Escáner IV", description: "Permite escanear los IVs de Pokémon salvajes. Se revelan 2 IVs por cada objeto.\nLos mejores IVs se muestran primero." }, "DNA_SPLICERS": { name: "Punta ADN" }, "MINI_BLACK_HOLE": { name: "Mini Agujero Negro" }, - "GOLDEN_POKEBALL": { name: "Poké Ball Dorada", description: "Agrega 1 opción de objeto extra al final de cada combate" }, + "GOLDEN_POKEBALL": { name: "Poké Ball Dorada", description: "Agrega 1 opción de objeto extra al final de cada combate." }, - "ENEMY_DAMAGE_BOOSTER": { name: "Damage Token", description: "Aumenta el daño en un 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Protection Token", description: "Reduce el daño recibido en un 2,5%" }, - "ENEMY_HEAL": { name: "Recovery Token", description: "Cura el 2% de los PS máximo en cada turno" }, - "ENEMY_ATTACK_POISON_CHANCE": { name: "Poison Token" }, - "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Paralyze Token" }, - "ENEMY_ATTACK_BURN_CHANCE": { name: "Burn Token" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Full Heal Token", description: "Agrega un 2.5% de probabilidad cada turno de curar un problema de estado" }, - "ENEMY_ENDURE_CHANCE": { name: "Endure Token" }, - "ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Agrega un 1% de probabilidad de que un Pokémon salvaje sea una fusión" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Ficha Daño", description: "Aumenta el daño en un 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Ficha Protección", description: "Reduce el daño recibido en un 2,5%." }, + "ENEMY_HEAL": { name: "Ficha Curación", description: "Cura el 2% de los PS máximo en cada turno." }, + "ENEMY_ATTACK_POISON_CHANCE": { name: "Ficha Veneno" }, + "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Ficha Parálisis" }, + "ENEMY_ATTACK_BURN_CHANCE": { name: "Ficha Quemadura" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Ficha Cura Total", description: "Agrega un 2.5% de probabilidad cada turno de curar un problema de estado." }, + "ENEMY_ENDURE_CHANCE": { name: "Ficha Aguante" }, + "ENEMY_FUSED_CHANCE": { name: "Ficha Fusión", description: "Agrega un 1% de probabilidad de que un Pokémon salvaje sea una fusión." }, }, TempBattleStatBoosterItem: { "x_attack": "Ataque X", @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "PiroROM", "CHILL_DRIVE": "CrioROM", "DOUSE_DRIVE": "HidroROM", + + "FIST_PLATE": "Tabla Fuerte", + "SKY_PLATE": "Tabla Cielo", + "TOXIC_PLATE": "Tabla Tóxica", + "EARTH_PLATE": "Tabla Terrax", + "STONE_PLATE": "Tabla Pétrea", + "INSECT_PLATE": "Tabla Bicho", + "SPOOKY_PLATE": "Tabla Terror", + "IRON_PLATE": "Tabla Acero", + "FLAME_PLATE": "Tabla Llama", + "SPLASH_PLATE": "Tabla Linfa", + "MEADOW_PLATE": "Tabla Pradal", + "ZAP_PLATE": "Tabla Trueno", + "MIND_PLATE": "Tabla Mental", + "ICICLE_PLATE": "Tabla Helada", + "DRACO_PLATE": "Tabla Draco", + "DREAD_PLATE": "Tabla Oscura", + "PIXIE_PLATE": "Tabla Duende", + "BLANK_PLATE": "Tabla Neutra", + "LEGEND_PLATE": "Tabla Legendaria", + "FIGHTING_MEMORY": "Disco Lucha", + "FLYING_MEMORY": "Disco Volador", + "POISON_MEMORY": "Disco Veneno", + "GROUND_MEMORY": "Disco Tierra", + "ROCK_MEMORY": "Disco Roca", + "BUG_MEMORY": "Disco Bicho", + "GHOST_MEMORY": "Disco Fantasma", + "STEEL_MEMORY": "Disco Acero", + "FIRE_MEMORY": "Disco Fuego", + "WATER_MEMORY": "Disco Agua", + "GRASS_MEMORY": "Disco Planta", + "ELECTRIC_MEMORY": "Disco Eléctrico", + "PSYCHIC_MEMORY": "Disco Psíquico", + "ICE_MEMORY": "Disco Hielo", + "DRAGON_MEMORY": "Disco Dragón", + "DARK_MEMORY": "Disco Siniestro", + "FAIRY_MEMORY": "Disco Hada", + "BLANK_MEMORY": "Disco Blanco", }, } as const; diff --git a/src/locales/es/save-slot-select-ui-handler.ts b/src/locales/es/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..7939518ceed --- /dev/null +++ b/src/locales/es/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "¿Sobrescribir los datos en la ranura seleccionada?", + "loading": "Cargando...", + "wave": "Oleada", + "lv": "Nv", + "empty": "Vacío", +} as const; diff --git a/src/locales/es/starter-select-ui-handler.ts b/src/locales/es/starter-select-ui-handler.ts index 81455418c7d..4d025820260 100644 --- a/src/locales/es/starter-select-ui-handler.ts +++ b/src/locales/es/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Elige el movimiento que sustituirá a", "unlockPassive": "Añadir Pasiva", "reduceCost": "Reducir Coste", - "cycleShiny": "R: Cambiar Shiny", - "cycleForm": "F: Cambiar Forma", - "cycleGender": "G: Cambiar Género", - "cycleAbility": "E: Cambiar Habilidad", - "cycleNature": "N: Cambiar Naturaleza", - "cycleVariant": "V: Cambiar Variante", + "cycleShiny": ": Shiny", + "cycleForm": ": Forma", + "cycleGender": ": Género", + "cycleAbility": ": Habilidad", + "cycleNature": ": Naturaleza", + "cycleVariant": ": Variante", "enablePassive": "Activar Pasiva", "disablePassive": "Desactivar Pasiva", "locked": "Bloqueado", diff --git a/src/locales/fr/ability.ts b/src/locales/fr/ability.ts index 83bb46c7408..f984c8843de 100644 --- a/src/locales/fr/ability.ts +++ b/src/locales/fr/ability.ts @@ -897,7 +897,7 @@ export const ability: AbilityTranslationEntries = { name: "Boost Chimère", description: "Augmente la stat la plus élevée du Pokémon quand il met K.O. un autre Pokémon.", }, - rKSSystem: { + rksSystem: { name: "Système Alpha", description: "Change le type du Pokémon en fonction de la ROM équipée.", }, diff --git a/src/locales/fr/achv.ts b/src/locales/fr/achv.ts index 6383c6817c0..ddec9086892 100644 --- a/src/locales/fr/achv.ts +++ b/src/locales/fr/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Succès", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "Invaincu·e", description: "Terminer le jeu en mode classique", }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Mono NORMAL", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Mono FLYING", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Mono GROUND", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "Sting Like A Beedrill", + }, + "MONO_GHOST": { + name: "Who you gonna call?", + }, + "MONO_STEEL": { + name: "Mono STEEL", + }, + "MONO_FIRE": { + name: "Mono FIRE", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Mono GRASS", + }, + "MONO_ELECTRIC": { + name: "Mono ELECTRIC", + }, + "MONO_PSYCHIC": { + name: "Mono PSYCHIC", + }, + "MONO_ICE": { + name: "Mono ICE", + }, + "MONO_DRAGON": { + name: "Mono DRAGON", + }, + "MONO_DARK": { + name: "It's just a phase", + }, + "MONO_FAIRY": { + name: "Mono FAIRY", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/fr/biome.ts b/src/locales/fr/biome.ts index bc9fa4239e6..2f3dffb28f6 100644 --- a/src/locales/fr/biome.ts +++ b/src/locales/fr/biome.ts @@ -16,7 +16,7 @@ export const biome: SimpleTranslationEntries = { "MOUNTAIN": "Montagne", "BADLANDS": "Terres Sauvages", "CAVE": "Grotte", - "DESERT": "Desert", + "DESERT": "Désert", "ICE_CAVE": "Caverne Gelée", "MEADOW": "Prairie", "POWER_PLANT": "Centrale", diff --git a/src/locales/fr/challenges.ts b/src/locales/fr/challenges.ts new file mode 100644 index 00000000000..f655caf4807 --- /dev/null +++ b/src/locales/fr/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "title": "Paramètres du Challenge", + "points": "Bad Ideas", + "confirm_start": "Continuer avec ces paramètres ?", + "singleGeneration.name": "Mono-génération", + "singleGeneration.value.0": "Désactivé", + "singleGeneration.desc.0": "Vous ne pouvez choisir que des Pokémon de la génération sélectionnée.", + "singleGeneration.value.1": "1G", + "singleGeneration.desc.1": "Vous ne pouvez choisir que des Pokémon de 1re génération.", + "singleGeneration.value.2": "2G", + "singleGeneration.desc.2": "Vous ne pouvez choisir que des Pokémon de 2e génération.", + "singleGeneration.value.3": "3G", + "singleGeneration.desc.3": "Vous ne pouvez choisir que des Pokémon de 3e génération.", + "singleGeneration.value.4": "4G", + "singleGeneration.desc.4": "Vous ne pouvez choisir que des Pokémon de 4e génération.", + "singleGeneration.value.5": "5G", + "singleGeneration.desc.5": "Vous ne pouvez choisir que des Pokémon de 5e génération.", + "singleGeneration.value.6": "6G", + "singleGeneration.desc.6": "Vous ne pouvez choisir que des Pokémon de 6e génération.", + "singleGeneration.value.7": "7G", + "singleGeneration.desc.7": "Vous ne pouvez choisir que des Pokémon de 7e génération.", + "singleGeneration.value.8": "8G", + "singleGeneration.desc.8": "Vous ne pouvez choisir que des Pokémon de 8e génération.", + "singleGeneration.value.9": "9G", + "singleGeneration.desc.9": "Vous ne pouvez choisir que des Pokémon de 9e génération.", + "singleType.name": "Mono-type", + "singleType.value.0": "Désactivé", + "singleType.desc.0": "Vous ne pouvez choisir que des Pokémon du type sélectionné.", + "singleType.value.1": "Normal", + "singleType.desc.1": "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.", +} as const; diff --git a/src/locales/fr/config.ts b/src/locales/fr/config.ts index d523d35bb87..f7b7467c4bc 100644 --- a/src/locales/fr/config.ts +++ b/src/locales/fr/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const frConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const frConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const frConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/fr/game-mode.ts b/src/locales/fr/game-mode.ts new file mode 100644 index 00000000000..28858e46bfa --- /dev/null +++ b/src/locales/fr/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classique", + "endless": "Infini", + "endlessSpliced": "Infini (Fusions)", + "dailyRun": "Défi du jour", + "unknown": "Inconnu", + "challenge": "Challenge", +} as const; diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index e955d4970c0..f9538e9d26c 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -40,10 +40,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classement de la Semaine", "noRankings": "Pas de Classement", "loading": "Chargement…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "Joueurs Connectés", - "empty":"Vide", "yes":"Oui", "no":"Non", - "disclaimer": "DISCLAIMER", - "disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed." + "disclaimer": "AVERTISSEMENT", + "disclaimerDescription": "Ce jeu n’est pas un produit fini et peut contenir des problèmes de jouabilité, dont de possibles pertes de sauvegardes,\ndes modifications sans avertissement et pourrait ou non encore être mis à jour ou terminé." } as const; diff --git a/src/locales/fr/modifier-type.ts b/src/locales/fr/modifier-type.ts index dd70fd9205e..766629b88d8 100644 --- a/src/locales/fr/modifier-type.ts +++ b/src/locales/fr/modifier-type.ts @@ -4,76 +4,76 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{pokeballName}} x{{modifierCount}}", - description: "Recevez {{modifierCount}} {{pokeballName}}s (Inventaire : {{pokeballAmount}}) \nTaux de capture : {{catchRate}}", + description: "Recevez {{modifierCount}} {{pokeballName}}s (Inventaire : {{pokeballAmount}}) \nTaux de capture : {{catchRate}}.", }, "AddVoucherModifierType": { name: "{{voucherTypeName}} x{{modifierCount}}", - description: "Recevez {{modifierCount}} {{voucherTypeName}}", + description: "Recevez {{modifierCount}} {{voucherTypeName}}.", }, "PokemonHeldItemModifierType": { extra: { - "inoperable": "{{pokemonName}} ne peut pas\nporter cet objet !", - "tooMany": "{{pokemonName}} possède trop\nd’exemplaires de cet objet !", + "inoperable": "{{pokemonName}} ne peut pas\nporter cet objet !", + "tooMany": "{{pokemonName}} possède trop\nd’exemplaires de cet objet !", } }, "PokemonHpRestoreModifierType": { description: "Restaure {{restorePoints}} PV ou {{restorePercent}}% des PV totaux d’un Pokémon, en fonction duquel des deux est le plus élevé", extra: { - "fully": "Restaure tous les PV d’un Pokémon", - "fullyWithStatus": "Restaure tous les PV d’un Pokémon et soigne tous ses problèmes de statut", + "fully": "Restaure tous les PV d’un Pokémon.", + "fullyWithStatus": "Restaure tous les PV d’un Pokémon et soigne tous ses problèmes de statut.", } }, "PokemonReviveModifierType": { - description: "Réanime un Pokémon et restaure {{restorePercent}}% de ses PV", + description: "Réanime un Pokémon et restaure {{restorePercent}}% de ses PV.", }, "PokemonStatusHealModifierType": { - description: "Soigne tous les problèmes de statut d’un Pokémon", + description: "Soigne tous les problèmes de statut d’un Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Restaure {{restorePoints}} PP à une capacité d’un Pokémon", + description: "Restaure {{restorePoints}} PP à une capacité d’un Pokémon.", extra: { - "fully": "Restaure tous les PP à une capacité d’un Pokémon", + "fully": "Restaure tous les PP à une capacité d’un Pokémon.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Restaure {{restorePoints}} PP à toutes les capacités d’un Pokémon", + description: "Restaure {{restorePoints}} PP à toutes les capacités d’un Pokémon.", extra: { - "fully": "Restaure tous les PP à toutes les capacités d’un Pokémon", + "fully": "Restaure tous les PP à toutes les capacités d’un Pokémon.", } }, "PokemonPpUpModifierType": { - description: "Augmente le max de PP de {{upPoints}} à une capacité d’un Pokémon pour chaque 5 PP max (max : 3)", + description: "Augmente le max de PP de {{upPoints}} à une capacité d’un Pokémon pour chaque 5 PP max (max : 3).", }, "PokemonNatureChangeModifierType": { name: "Aromate {{natureName}}", description: "Donne la nature {{natureName}} à un Pokémon et la débloque pour le starter lui étant lié.", }, "DoubleBattleChanceBoosterModifierType": { - description: "Double les chances de tomber sur un combat double pendant {{battleCount}} combats", + description: "Double les chances de tomber sur un combat double pendant {{battleCount}} combats.", }, "TempBattleStatBoosterModifierType": { - description: "Augmente d’un cran {{tempBattleStatName}} pour toute l’équipe pendant 5 combats", + description: "Augmente d’un cran {{tempBattleStatName}} pour toute l’équipe pendant 5 combats.", }, "AttackTypeBoosterModifierType": { - description: "Augmente de 20% la puissance des capacités de type {{moveType}} d’un Pokémon", + description: "Augmente de 20% la puissance des capacités de type {{moveType}} d’un Pokémon.", }, "PokemonLevelIncrementModifierType": { - description: "Fait monter un Pokémon d’un niveau", + description: "Fait monter un Pokémon d’un niveau.", }, "AllPokemonLevelIncrementModifierType": { - description: "Fait monter toute l’équipe d’un niveau", + description: "Fait monter toute l’équipe d’un niveau.", }, "PokemonBaseStatBoosterModifierType": { description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Restaure tous les PV de toute l'équipe", + description: "Restaure tous les PV de toute l'équipe.", }, "AllPokemonFullReviveModifierType": { description: "Réanime et restaure tous les PV de tous les Pokémon K.O.", }, "MoneyRewardModifierType": { - description: "Octroie une {{moneyMultiplier}} somme d’argent ({{moneyAmount}}₽)", + description: "Octroie une {{moneyMultiplier}} somme d’argent ({{moneyAmount}}₽).", extra: { "small": "petite", "moderate": "moyenne", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Augmente de {{boostPercent}}% le gain de Points d’Exp", + description: "Augmente de {{boostPercent}}% le gain de Points d’Exp.", }, "PokemonExpBoosterModifierType": { - description: "Augmente de {{boostPercent}}% le gain de Points d’Exp du porteur", + description: "Augmente de {{boostPercent}}% le gain de Points d’Exp du porteur.", }, "PokemonFriendshipBoosterModifierType": { - description: "Augmente le gain d’amitié de 50% par victoire", + description: "Augmente le gain d’amitié de 50% par victoire.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Augmente de {{accuracyAmount}} la précision des capacités (maximum 100)", + description: "Augmente de {{accuracyAmount}} la précision des capacités (maximum 100).", }, "PokemonMultiHitModifierType": { - description: "Frappe une fois de plus en échange d’une baisse de puissance de respectivement 60/75/82,5% par cumul", + description: "Frappe une fois de plus en échange d’une baisse de puissance de respectivement 60/75/82,5% par cumul.", }, "TmModifierType": { name: "CT{{moveId}} - {{moveName}}", - description: "Apprend la capacité {{moveName}} à un Pokémon", + description: "Apprend la capacité {{moveName}} à un Pokémon.", }, "TmModifierTypeWithInfo": { name: "CT{{moveId}} - {{moveName}}", - description: "Apprend la capacité {{moveName}} à un Pokémon\n(Hold C or Shift for more info)", + description: "Apprend la capacité {{moveName}} à un Pokémon\n(Hold C or Shift for more info).", }, "EvolutionItemModifierType": { - description: "Permet à certains Pokémon d’évoluer", + description: "Permet à certains Pokémon d’évoluer.", }, "FormChangeItemModifierType": { - description: "Permet à certains Pokémon de changer de forme", + description: "Permet à certains Pokémon de changer de forme.", }, "FusePokemonModifierType": { - description: "Fusionne deux Pokémon (transfère le Talent, sépare les stats de base et les types, partage le movepool)", + description: "Fusionne deux Pokémon (transfère le Talent, sépare les stats de base et les types, partage le movepool).", }, "TerastallizeModifierType": { name: "Téra-Éclat {{teraType}}", - description: "{{teraType}} Téracristallise son porteur pendant 10 combats", + description: "{{teraType}} Téracristallise son porteur pendant 10 combats.", }, "ContactHeldItemTransferChanceModifierType": { - description: "{{chancePercent}}% de chances de voler un objet de l’adversaire en l’attaquant", + description: "{{chancePercent}}% de chances de voler un objet de l’adversaire en l’attaquant.", }, "TurnHeldItemTransferModifierType": { - description: "À chaque tour, son porteur obtient un objet de son adversaire", + description: "À chaque tour, son porteur obtient un objet de son adversaire.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Ajoute {{chancePercent}}% de chances d’infliger le statut {{statusEffect}} avec des capacités offensives", + description: "Ajoute {{chancePercent}}% de chances d’infliger le statut {{statusEffect}} avec des capacités offensives.", }, "EnemyEndureChanceModifierType": { - description: "Ajoute {{chancePercent}}% de chances d’encaisser un coup", + description: "Ajoute {{chancePercent}}% de chances d’encaisser un coup.", }, "RARE_CANDY": { name: "Super Bonbon" }, "RARER_CANDY": { name: "Hyper Bonbon" }, - "MEGA_BRACELET": { name: "Méga-Bracelet", description: "Débloque les Méga-Gemmes" }, - "DYNAMAX_BAND": { name: "Poignet Dynamax", description: "Débloque le Dynamax" }, - "TERA_ORB": { name: "Orbe Téracristal", description: "Débloque les Téra-Éclats" }, + "MEGA_BRACELET": { name: "Méga-Bracelet", description: "Débloque les Méga-Gemmes." }, + "DYNAMAX_BAND": { name: "Poignet Dynamax", description: "Débloque le Dynamax." }, + "TERA_ORB": { name: "Orbe Téracristal", description: "Débloque les Téra-Éclats." }, - "MAP": { name: "Carte", description: "Vous permet de choisir votre destination à un croisement" }, + "MAP": { name: "Carte", description: "Vous permet de choisir votre destination à un croisement." }, "POTION": { name: "Potion" }, "SUPER_POTION": { name: "Super Potion" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "Super Parfum" }, "MAX_LURE": { name: "Parfum Max" }, - "MEMORY_MUSHROOM": { name: "Champi Mémoriel", description: "Remémore une capacité à un Pokémon" }, + "MEMORY_MUSHROOM": { name: "Champi Mémoriel", description: "Remémore une capacité à un Pokémon." }, - "EXP_SHARE": { name: "Multi Exp", description: "Tous les non-participants reçoivent 20% des Points d’Exp d’un participant" }, - "EXP_BALANCE": { name: "Équilibr’Exp", description: "Équilibre les Points d’Exp à l’avantage des membres de l’équipe aux plus bas niveaux" }, + "EXP_SHARE": { name: "Multi Exp", description: "Tous les non-participants reçoivent 20% des Points d’Exp d’un participant." }, + "EXP_BALANCE": { name: "Équilibr’Exp", description: "Équilibre les Points d’Exp à l’avantage des membres de l’équipe aux plus bas niveaux." }, - "OVAL_CHARM": { name: "Charme Ovale", description: "Quand plusieurs Pokémon sont en combat, chacun gagne 10% supplémentaires du total d’Exp" }, + "OVAL_CHARM": { name: "Charme Ovale", description: "Quand plusieurs Pokémon sont en combat, chacun gagne 10% supplémentaires du total d’Exp." }, "EXP_CHARM": { name: "Charme Exp" }, "SUPER_EXP_CHARM": { name: "Super Charme Exp" }, @@ -182,44 +182,44 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Grelot Zen" }, - "SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% l’influence de la nature d’un Pokémon sur ses statistiques (cumulatif)" }, + "SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% l’influence de la nature d’un Pokémon sur ses statistiques (cumulatif)." }, "NUGGET": { name: "Pépite" }, "BIG_NUGGET": { name: "Maxi Pépite" }, "RELIC_GOLD": { name: "Vieux Ducat" }, - "AMULET_COIN": { name: "Pièce Rune", description: "Augmente de 20% les gains d’argent" }, - "GOLDEN_PUNCH": { name: "Poing Doré", description: "50% des dégâts infligés sont convertis en argent" }, - "COIN_CASE": { name: "Boite Jetons", description: "Tous les 10 combats, recevez 10% de votre argent en intérêts" }, + "AMULET_COIN": { name: "Pièce Rune", description: "Augmente de 20% les gains d’argent." }, + "GOLDEN_PUNCH": { name: "Poing Doré", description: "50% des dégâts infligés sont convertis en argent." }, + "COIN_CASE": { name: "Boite Jetons", description: "Tous les 10 combats, recevez 10% de votre argent en intérêts." }, - "LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de verrouiller des objets rares si vous relancez les objets proposés" }, + "LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de verrouiller des objets rares si vous relancez les objets proposés." }, "GRIP_CLAW": { name: "Accro Griffe" }, "WIDE_LENS": { name: "Loupe" }, "MULTI_LENS": { name: "Lentille Multi" }, - "HEALING_CHARM": { name: "Charme Soin", description: "Augmente de 10% l’efficacité des capacités et objets de soin de PV (hors Rappels)" }, - "CANDY_JAR": { name: "Bonbonnière", description: "Augmente de 1 le nombre de niveaux gagnés à l’utilisation d’un Super Bonbon" }, + "HEALING_CHARM": { name: "Charme Soin", description: "Augmente de 10% l’efficacité des capacités et objets de soin de PV (hors Rappels)." }, + "CANDY_JAR": { name: "Bonbonnière", description: "Augmente de 1 le nombre de niveaux gagnés à l’utilisation d’un Super Bonbon." }, - "BERRY_POUCH": { name: "Sac à Baies", description: "Ajoute 30% de chances qu’une Baie utilisée ne soit pas consommée" }, + "BERRY_POUCH": { name: "Sac à Baies", description: "Ajoute 30% de chances qu’une Baie utilisée ne soit pas consommée." }, "FOCUS_BAND": { name: "Bandeau", description: "Ajoute 10% de chances de survivre avec 1 PV si les dégâts reçus pouvaient mettre K.O." }, - "QUICK_CLAW": { name: "Vive Griffe", description: "Ajoute 10% de chances d’agir en premier, indépendamment de la vitesse (après la priorité)" }, + "QUICK_CLAW": { name: "Vive Griffe", description: "Ajoute 10% de chances d’agir en premier, indépendamment de la vitesse (après la priorité)." }, - "KINGS_ROCK": { name: "Roche Royale", description: "Ajoute 10% de chances qu’une capacité offensive apeure l’adversaire" }, + "KINGS_ROCK": { name: "Roche Royale", description: "Ajoute 10% de chances qu’une capacité offensive apeure l’adversaire." }, - "LEFTOVERS": { name: "Restes", description: "Soigne à chaque tour 1/16 des PV max d’un Pokémon" }, - "SHELL_BELL": { name: "Grelot Coque", description: "Soigne 1/8 des dégâts infligés par un Pokémon" }, + "LEFTOVERS": { name: "Restes", description: "Soigne à chaque tour 1/16 des PV max d’un Pokémon." }, + "SHELL_BELL": { name: "Grelot Coque", description: "Soigne 1/8 des dégâts infligés par un Pokémon." }, - "TOXIC_ORB": { name: "Orbe Toxique", description: "Un orbe bizarre qui empoisonne gravement son porteur durant le combat" }, - "FLAME_ORB": { name: "Orbe Flamme", description: "Un orbe bizarre qui brûle son porteur durant le combat" }, + "TOXIC_ORB": { name: "Orbe Toxique", description: "Un orbe bizarre qui empoisonne gravement son porteur durant le combat." }, + "FLAME_ORB": { name: "Orbe Flamme", description: "Un orbe bizarre qui brûle son porteur durant le combat." }, "BATON": { name: "Bâton", description: "Permet de transmettre les effets en cas de changement de Pokémon. Ignore les pièges." }, - "SHINY_CHARM": { name: "Charme Chroma", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage chromatique" }, - "ABILITY_CHARM": { name: "Charme Talent", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage avec un Talent Caché" }, + "SHINY_CHARM": { name: "Charme Chroma", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage chromatique." }, + "ABILITY_CHARM": { name: "Charme Talent", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage avec un Talent Caché." }, "IV_SCANNER": { name: "Scanner d’IV", description: "Révèle la qualité de deux IV d’un Pokémon sauvage par scanner possédé. Les meilleurs IV sont révélés en priorité." }, @@ -229,9 +229,9 @@ export const modifierType: ModifierTypeTranslationEntries = { "GOLDEN_POKEBALL": { name: "Poké Ball Dorée", description: "Ajoute un choix d’objet à la fin de chaque combat" }, - "ENEMY_DAMAGE_BOOSTER": { name: "Jeton Dégâts", description: "Augmente les dégâts de 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Jeton Protection", description: "Diminue les dégâts reçus de 2,5%" }, - "ENEMY_HEAL": { name: "Jeton Soin", description: "Soigne 2% des PV max à chaque tour" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Jeton Dégâts", description: "Augmente les dégâts de 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Jeton Protection", description: "Diminue les dégâts reçus de 2,5%." }, + "ENEMY_HEAL": { name: "Jeton Soin", description: "Soigne 2% des PV max à chaque tour." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "Jeton Poison" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Jeton Paralysie" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "Jeton Brulure" }, @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "Module Pyro", "CHILL_DRIVE": "Module Cryo", "DOUSE_DRIVE": "Module Aqua", + + "FIST_PLATE": "Plaque Poing", + "SKY_PLATE": "Plaque Ciel", + "TOXIC_PLATE": "Plaque Toxicité", + "EARTH_PLATE": "Plaque Terre", + "STONE_PLATE": "Plaque Roc", + "INSECT_PLATE": "Plaque Insecte", + "SPOOKY_PLATE": "Plaque Fantôme", + "IRON_PLATE": "Plaque Fer", + "FLAME_PLATE": "Plaque Flamme", + "SPLASH_PLATE": "Plaque Hydro", + "MEADOW_PLATE": "Plaque Herbe", + "ZAP_PLATE": "Plaque Volt", + "MIND_PLATE": "Plaque Esprit", + "ICICLE_PLATE": "Plaque Glace", + "DRACO_PLATE": "Plaque Draco", + "DREAD_PLATE": "Plaque Ombre", + "PIXIE_PLATE": "Plaque Pixie", + "BLANK_PLATE": "Plaque Renouveau", + "LEGEND_PLATE": "Plaque Légende", + "FIGHTING_MEMORY": "ROM Combat", + "FLYING_MEMORY": "ROM Vol", + "POISON_MEMORY": "ROM Poison", + "GROUND_MEMORY": "ROM Sol", + "ROCK_MEMORY": "ROM Roche", + "BUG_MEMORY": "ROM Insecte", + "GHOST_MEMORY": "ROM Spectre", + "STEEL_MEMORY": "ROM Acier", + "FIRE_MEMORY": "ROM Feu", + "WATER_MEMORY": "ROM Eau", + "GRASS_MEMORY": "ROM Plante", + "ELECTRIC_MEMORY": "ROM Électrik", + "PSYCHIC_MEMORY": "ROM Psy", + "ICE_MEMORY": "ROM Glace", + "DRAGON_MEMORY": "ROM Dragon", + "DARK_MEMORY": "ROM Ténèbres", + "FAIRY_MEMORY": "ROM Fée", + "BLANK_MEMORY": "ROM Vierge", }, } as const; diff --git a/src/locales/fr/save-slot-select-ui-handler.ts b/src/locales/fr/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..53b68191b9f --- /dev/null +++ b/src/locales/fr/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Effacer les données de l’emplacement sélectionné ?", + "loading": "Chargement…", + "wave": "Vague", + "lv": "N.", + "empty": "Vide", +} as const; diff --git a/src/locales/fr/starter-select-ui-handler.ts b/src/locales/fr/starter-select-ui-handler.ts index 4aa6185b439..9f504cab11e 100644 --- a/src/locales/fr/starter-select-ui-handler.ts +++ b/src/locales/fr/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Sélectionnez laquelle échanger avec", "unlockPassive": "Débloquer Passif", "reduceCost": "Diminuer le cout", - "cycleShiny": "R: » Chromatiques", - "cycleForm": "F: » Formes", - "cycleGender": "G: » Sexes", - "cycleAbility": "E: » Talents", - "cycleNature": "N: » Natures", - "cycleVariant": "V: » Variants", + "cycleShiny": ": » Chromatiques", + "cycleForm": ": » Formes", + "cycleGender": ": » Sexes", + "cycleAbility": ": » Talents", + "cycleNature": ": » Natures", + "cycleVariant": ": » Variants", "enablePassive": "Activer Passif", "disablePassive": "Désactiver Passif", "locked": "Verrouillé", diff --git a/src/locales/it/achv.ts b/src/locales/it/achv.ts index 42b1995bcde..bf1bfc295e8 100644 --- a/src/locales/it/achv.ts +++ b/src/locales/it/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Achievements", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Mono NORMAL", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Mono FLYING", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Mono GROUND", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "Sting Like A Beedrill", + }, + "MONO_GHOST": { + name: "Who you gonna call?", + }, + "MONO_STEEL": { + name: "Mono STEEL", + }, + "MONO_FIRE": { + name: "Mono FIRE", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Mono GRASS", + }, + "MONO_ELECTRIC": { + name: "Mono ELECTRIC", + }, + "MONO_PSYCHIC": { + name: "Mono PSYCHIC", + }, + "MONO_ICE": { + name: "Mono ICE", + }, + "MONO_DRAGON": { + name: "Mono DRAGON", + }, + "MONO_DARK": { + name: "It's just a phase", + }, + "MONO_FAIRY": { + name: "Mono FAIRY", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/it/challenges.ts b/src/locales/it/challenges.ts new file mode 100644 index 00000000000..149037be740 --- /dev/null +++ b/src/locales/it/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "title": "Challenge Modifiers", + "points": "Bad Ideas", + "confirm_start": "Proceed with these challenges?", + "singleGeneration.name": "Mono Gen", + "singleGeneration.value.0": "Off", + "singleGeneration.desc.0": "You can only use pokemon from the chosen generation.", + "singleGeneration.value.1": "Gen 1", + "singleGeneration.desc.1": "You can only use pokemon from generation one.", + "singleGeneration.value.2": "Gen 2", + "singleGeneration.desc.2": "You can only use pokemon from generation two.", + "singleGeneration.value.3": "Gen 3", + "singleGeneration.desc.3": "You can only use pokemon from generation three.", + "singleGeneration.value.4": "Gen 4", + "singleGeneration.desc.4": "You can only use pokemon from generation four.", + "singleGeneration.value.5": "Gen 5", + "singleGeneration.desc.5": "You can only use pokemon from generation five.", + "singleGeneration.value.6": "Gen 6", + "singleGeneration.desc.6": "You can only use pokemon from generation six.", + "singleGeneration.value.7": "Gen 7", + "singleGeneration.desc.7": "You can only use pokemon from generation seven.", + "singleGeneration.value.8": "Gen 8", + "singleGeneration.desc.8": "You can only use pokemon from generation eight.", + "singleGeneration.value.9": "Gen 9", + "singleGeneration.desc.9": "You can only use pokemon from generation nine.", + "singleType.name": "Mono Type", + "singleType.value.0": "Off", + "singleType.desc.0": "You can only use pokemon of the chosen type.", + "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.", +} as const; diff --git a/src/locales/it/config.ts b/src/locales/it/config.ts index 3f53c8fca01..333c11ae6a8 100644 --- a/src/locales/it/config.ts +++ b/src/locales/it/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const itConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const itConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const itConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/it/game-mode.ts b/src/locales/it/game-mode.ts new file mode 100644 index 00000000000..be342b4c390 --- /dev/null +++ b/src/locales/it/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classic", + "endless": "Endless", + "endlessSpliced": "Endless (Spliced)", + "dailyRun": "Daily Run", + "unknown": "Unknown", + "challenge": "Challenge", +} as const; diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index e891146f754..4e3da7ca992 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -40,13 +40,13 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classifica Settimanale", "noRankings": "Nessuna Classifica", "loading": "Caricamento…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "Giocatori Online", "evolving": "Cosa?\n{{pokemonName}} si evolvendo!", "stoppedEvolving": "{{pokemonName}} ha smesso di evolversi.", "pauseEvolutionsQuestion": "Vuoi sospendere le evoluzioni per {{pokemonName}}?\nLe evoluzioni possono essere riattivate dalla schermata del party.", "evolutionsPaused": "Le evoluzioni sono state sospese per {{pokemonName}}.", "evolutionDone": "Congratulazioni!\n{{pokemonName}} si è evoluto in {{evolvedPokemonName}}!", - "empty":"Vuoto", "yes":"Si", "no":"No", "disclaimer": "DISCLAIMER", diff --git a/src/locales/it/modifier-type.ts b/src/locales/it/modifier-type.ts index ac313e2444c..b16604200f8 100644 --- a/src/locales/it/modifier-type.ts +++ b/src/locales/it/modifier-type.ts @@ -4,11 +4,11 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{modifierCount}}x {{pokeballName}}", - description: "Ricevi {{pokeballName}} x{{modifierCount}} (Inventario: {{pokeballAmount}}) \nTasso di cattura: {{catchRate}}", + description: "Ricevi {{pokeballName}} x{{modifierCount}} (Inventario: {{pokeballAmount}}) \nTasso di cattura: {{catchRate}}.", }, "AddVoucherModifierType": { - name: "{{modifierCount}}x {{voucherTypeName}}", - description: "Ricevi {{voucherTypeName}} x{{modifierCount}}", + name: "{{modifierCount}}x {{voucherTypeName}}.", + description: "Ricevi {{voucherTypeName}} x{{modifierCount}}.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "Restituisce {{restorePoints}} PS o {{restorePercent}}% PS ad un Pokémon, a seconda del valore più alto", + description: "Restituisce {{restorePoints}} PS o {{restorePercent}}% PS ad un Pokémon, a seconda del valore più alto.", extra: { - "fully": "Restituisce tutti i PS ad un Pokémon", - "fullyWithStatus": "Restituisce tutti i PS ad un Pokémon e lo cura da ogni stato", + "fully": "Restituisce tutti i PS ad un Pokémon.", + "fullyWithStatus": "Restituisce tutti i PS ad un Pokémon e lo cura da ogni stato.", } }, "PokemonReviveModifierType": { - description: "Rianima un Pokémon esausto e gli restituisce il {{restorePercent}}% PS", + description: "Rianima un Pokémon esausto e gli restituisce il {{restorePercent}}% PS.", }, "PokemonStatusHealModifierType": { - description: "Cura tutti i problemi di stato di un Pokémon", + description: "Cura tutti i problemi di stato di un Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Restituisce {{restorePoints}} PP per una mossa di un Pokémon ", + description: "Restituisce {{restorePoints}} PP per una mossa di un Pokémon.", extra: { - "fully": "Restituisce tutti i PP di una mossa", + "fully": "Restituisce tutti i PP di una mossa.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Restituisce {{restorePoints}} PP a tutte le mosse di un Pokémon", + description: "Restituisce {{restorePoints}} PP a tutte le mosse di un Pokémon.", extra: { - "fully": "Restituisce tutti i PP a tutte le mosse di un Pokémon", + "fully": "Restituisce tutti i PP a tutte le mosse di un Pokémon.", } }, "PokemonPpUpModifierType": { - description: "Aumenta i PP di una mossa di {{upPoints}} per ogni 5 PP (massimo 3)", + description: "Aumenta i PP di una mossa di {{upPoints}} per ogni 5 PP (massimo 3).", }, "PokemonNatureChangeModifierType": { - name: "Menta {{natureName}}", - description: "Cambia la natura del Pokémon in {{natureName}} e sblocca la natura per il Pokémon iniziale", + name: "Menta {{natureName}}.", + description: "Cambia la natura del Pokémon in {{natureName}} e sblocca la natura per il Pokémon iniziale.", }, "DoubleBattleChanceBoosterModifierType": { - description: "Raddoppia la possibilità di imbattersi in doppie battaglie per {{battleCount}} battaglie", + description: "Raddoppia la possibilità di imbattersi in doppie battaglie per {{battleCount}} battaglie.", }, "TempBattleStatBoosterModifierType": { - description: "Aumenta {{tempBattleStatName}} di un livello a tutti i Pokémon nel gruppo per 5 battaglie", + description: "Aumenta {{tempBattleStatName}} di un livello a tutti i Pokémon nel gruppo per 5 battaglie.", }, "AttackTypeBoosterModifierType": { - description: "Aumenta la potenza delle mosse di tipo {{moveType}} del 20% per un Pokémon", + description: "Aumenta la potenza delle mosse di tipo {{moveType}} del 20% per un Pokémon.", }, "PokemonLevelIncrementModifierType": { - description: "Fa salire un Pokémon di un livello", + description: "Fa salire un Pokémon di un livello.", }, "AllPokemonLevelIncrementModifierType": { - description: "Aumenta il livello di tutti i Pokémon nel gruppo di 1", + description: "Aumenta il livello di tutti i Pokémon nel gruppo di 1.", }, "PokemonBaseStatBoosterModifierType": { - description: "Aumenta {{statName}} di base del possessore del 10%", + description: "Aumenta {{statName}} di base del possessore del 10%.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Recupera il 100% dei PS per tutti i Pokémon", + description: "Recupera il 100% dei PS per tutti i Pokémon.", }, "AllPokemonFullReviveModifierType": { - description: "Rianima tutti i Pokémon esausti restituendogli tutti i PS", + description: "Rianima tutti i Pokémon esausti restituendogli tutti i PS.", }, "MoneyRewardModifierType": { - description: "Garantisce una {{moneyMultiplier}} quantità di soldi (₽{{moneyAmount}})", + description: "Garantisce una {{moneyMultiplier}} quantità di soldi (₽{{moneyAmount}}).", extra: { "small": "poca", "moderate": "moderata", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Aumenta il guadagno di Punti Esperienza del {{boostPercent}}%", + description: "Aumenta il guadagno di Punti Esperienza del {{boostPercent}}%.", }, "PokemonExpBoosterModifierType": { - description: "Aumenta il guadagno di Punti Esperienza del possessore del {{boostPercent}}%", + description: "Aumenta il guadagno di Punti Esperienza del possessore del {{boostPercent}}%.", }, "PokemonFriendshipBoosterModifierType": { - description: "Aumenta del 50% il guadagno di amicizia per vittoria", + description: "Aumenta del 50% il guadagno di amicizia per vittoria.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Aumenta l'accuratezza delle mosse di {{accuracyAmount}} (massimo 100)", + description: "Aumenta l'accuratezza delle mosse di {{accuracyAmount}} (massimo 100).", }, "PokemonMultiHitModifierType": { - description: "Gli attacchi colpiscono una volta in più al costo di una riduzione di potenza del 60/75/82,5% per mossa", + description: "Gli attacchi colpiscono una volta in più al costo di una riduzione di potenza del 60/75/82,5% per mossa.", }, "TmModifierType": { - name: "MT{{moveId}} - {{moveName}}", - description: "Insegna {{moveName}} a un Pokémon", + name: "MT{{moveId}} - {{moveName}}.", + description: "Insegna {{moveName}} a un Pokémon.", }, "TmModifierTypeWithInfo": { name: "MT{{moveId}} - {{moveName}}", - description: "Insegna {{moveName}} a un Pokémon\n(Hold C or Shift for more info)", + description: "Insegna {{moveName}} a un Pokémon\n(Hold C or Shift for more info).", }, "EvolutionItemModifierType": { - description: "Fa evolvere determinate specie di Pokémon", + description: "Fa evolvere determinate specie di Pokémon.", }, "FormChangeItemModifierType": { - description: "Fa cambiare forma a determinati Pokémon", + description: "Fa cambiare forma a determinati Pokémon.", }, "FusePokemonModifierType": { - description: "Combina due Pokémon (trasferisce i poteri, divide le statistiche e i tipi base, condivide il pool di mosse)", + description: "Combina due Pokémon (trasferisce i poteri, divide le statistiche e i tipi base, condivide il pool di mosse).", }, "TerastallizeModifierType": { name: "Teralite {{teraType}}", - description: "Teracristallizza in {{teraType}} il possessore per massimo 10 battaglie", + description: "Teracristallizza in {{teraType}} il possessore per massimo 10 battaglie.", }, "ContactHeldItemTransferChanceModifierType": { - description: "Quando si attacca, c'è una probabilità del {{chancePercent}}% che l'oggetto in possesso del nemico venga rubato", + description: "Quando si attacca, c'è una probabilità del {{chancePercent}}% che l'oggetto in possesso del nemico venga rubato.", }, "TurnHeldItemTransferModifierType": { - description: "Ogni turno, il possessore acquisisce un oggetto posseduto dal nemico", + description: "Ogni turno, il possessore acquisisce un oggetto posseduto dal nemico.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Aggiunge una probabilità del {{chancePercent}}% di infliggere {{statusEffect}} con le mosse d'attacco", + description: "Aggiunge una probabilità del {{chancePercent}}% di infliggere {{statusEffect}} con le mosse d'attacco.", }, "EnemyEndureChanceModifierType": { - description: "Aggiunge una probabilità del {{probabilitàPercent}}% di resistere ad un colpo", + description: "Aggiunge una probabilità del {{probabilitàPercent}}% di resistere ad un colpo.", }, "RARE_CANDY": { name: "Caramella Rara" }, "RARER_CANDY": { name: "Caramella Molto Rara" }, - "MEGA_BRACELET": { name: "Megapolsiera", description: "Le Megapietre sono disponibili" }, - "DYNAMAX_BAND": { name: "Polsino Dynamax", description: "I Fungomax sono disponibili" }, - "TERA_ORB": { name: "Terasfera", description: "I Teraliti sono disponibili" }, + "MEGA_BRACELET": { name: "Megapolsiera", description: "Le Megapietre sono disponibili." }, + "DYNAMAX_BAND": { name: "Polsino Dynamax", description: "I Fungomax sono disponibili." }, + "TERA_ORB": { name: "Terasfera", description: "I Teraliti sono disponibili." }, - "MAP": { name: "Mappa", description: "Permette di scegliere la propria strada a un bivio" }, + "MAP": { name: "Mappa", description: "Permette di scegliere la propria strada a un bivio." }, "POTION": { name: "Pozione" }, "SUPER_POTION": { name: "Superpozione" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cenere Magica" }, - "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di svenimento" }, + "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di svenimento." }, "ETHER": { name: "Etere" }, "MAX_ETHER": { name: "Etere Max" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "Profumo Invito Super" }, "MAX_LURE": { name: "Profumo Invito Max" }, - "MEMORY_MUSHROOM": { name: "Fungo della Memoria", description: "Ricorda la mossa dimenticata di un Pokémon" }, + "MEMORY_MUSHROOM": { name: "Fungo della Memoria", description: "Ricorda la mossa dimenticata di un Pokémon." }, - "EXP_SHARE": { name: "Condividi Esperienza", description: "Tutti i Pokémon della squadra ricevono il 20% dei Punti Esperienza dalla lotta anche se non vi hanno partecipato" }, - "EXP_BALANCE": { name: "Bilancia Esperienza", description: "Bilancia i Punti Esperienza ricevuti verso i Pokémon del gruppo di livello inferiore" }, + "EXP_SHARE": { name: "Condividi Esperienza", description: "Tutti i Pokémon della squadra ricevono il 20% dei Punti Esperienza dalla lotta anche se non vi hanno partecipato." }, + "EXP_BALANCE": { name: "Bilancia Esperienza", description: "Bilancia i Punti Esperienza ricevuti verso i Pokémon del gruppo di livello inferiore." }, - "OVAL_CHARM": { name: "Ovamuleto", description: "Quando più Pokémon partecipano a una battaglia, ognuno di essi riceve il 10% in più dell'esperienza totale" }, + "OVAL_CHARM": { name: "Ovamuleto", description: "Quando più Pokémon partecipano a una battaglia, ognuno di essi riceve il 10% in più dell'esperienza totale." }, "EXP_CHARM": { name: "Esperienzamuleto" }, "SUPER_EXP_CHARM": { name: "Esperienzamuleto Super" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Calmanella" }, - "SOUL_DEW": { name: "Cuorugiada", description: "Aumenta del 10% l'influenza della natura di un Pokémon sulle sue statistiche (Aggiuntivo)" }, + "SOUL_DEW": { name: "Cuorugiada", description: "Aumenta del 10% l'influenza della natura di un Pokémon sulle sue statistiche (Aggiuntivo)." }, "NUGGET": { name: "Pepita" }, "BIG_NUGGET": { name: "Granpepita" }, "RELIC_GOLD": { name: " Dobloantico" }, - "AMULET_COIN": { name: "Monetamuleto", description: "Aumenta le ricompense in denaro del 20%" }, - "GOLDEN_PUNCH": { name: "Pugno Dorato", description: "Garantisce il 50% dei danni inflitti come denaro" }, - "COIN_CASE": { name: " Salvadanaio", description: "Dopo ogni 10° battaglia, riceverete il 10% del vostro denaro in interessi" }, + "AMULET_COIN": { name: "Monetamuleto", description: "Aumenta le ricompense in denaro del 20%." }, + "GOLDEN_PUNCH": { name: "Pugno Dorato", description: "Garantisce il 50% dei danni inflitti come denaro." }, + "COIN_CASE": { name: " Salvadanaio", description: "Dopo ogni 10° battaglia, riceverete il 10% del vostro denaro in interessi." }, - "LOCK_CAPSULE": { name: "Capsula Scrigno", description: "Permette di bloccare le rarità degli oggetti quando si fa un reroll degli oggetti" }, + "LOCK_CAPSULE": { name: "Capsula Scrigno", description: "Permette di bloccare le rarità degli oggetti quando si fa un reroll degli oggetti." }, "GRIP_CLAW": { name: "Presartigli" }, "WIDE_LENS": { name: "Grandelente" }, "MULTI_LENS": { name: "Multilente" }, - "HEALING_CHARM": { name: "Curamuleto", description: "Aumenta del 10% l'efficacia delle mosse e degli oggetti che ripristinano i PS (escluse le rianimazioni)" }, - "CANDY_JAR": { name: "Barattolo di caramelle", description: "Aumenta di 1 il numero di livelli aggiunti dalle Caramelle Rare" }, + "HEALING_CHARM": { name: "Curamuleto", description: "Aumenta del 10% l'efficacia delle mosse e degli oggetti che ripristinano i PS (escluse le rianimazioni)." }, + "CANDY_JAR": { name: "Barattolo di caramelle", description: "Aumenta di 1 il numero di livelli aggiunti dalle Caramelle Rare." }, - "BERRY_POUCH": { name: "Porta Bacche", description: "Aggiunge il 30% di possibilità che una bacca usata non venga consumata" }, + "BERRY_POUCH": { name: "Porta Bacche", description: "Aggiunge il 30% di possibilità che una bacca usata non venga consumata." }, - "FOCUS_BAND": { name: "Bandana", description: "Chi ce l'ha ottiene il 10% di possibilità aggiuntivo di evitare un potenziale KO e rimanere con un solo PS" }, + "FOCUS_BAND": { name: "Bandana", description: "Chi ce l'ha ottiene il 10% di possibilità aggiuntivo di evitare un potenziale KO e rimanere con un solo PS." }, - "QUICK_CLAW": { name: "Rapidartigli", description: "Aggiunge una probabilità del 10% di muoversi per primi, indipendentemente dalla velocità (dopo la priorità)" }, + "QUICK_CLAW": { name: "Rapidartigli", description: "Aggiunge una probabilità del 10% di muoversi per primi, indipendentemente dalla velocità (dopo la priorità)." }, - "KINGS_ROCK": { name: "Roccia di re", description: "Aggiunge il 10% di possibilità che una mossa d'attacco faccia tentennare l'avversario" }, + "KINGS_ROCK": { name: "Roccia di re", description: "Aggiunge il 10% di possibilità che una mossa d'attacco faccia tentennare l'avversario." }, - "LEFTOVERS": { name: "Avanzi", description: "Ripristina 1/16 dei PS massimi di un Pokémon ogni turno" }, - "SHELL_BELL": { name: "Conchinella", description: "Guarisce 1/8 del danno inflitto a un Pokémon" }, + "LEFTOVERS": { name: "Avanzi", description: "Ripristina 1/16 dei PS massimi di un Pokémon ogni turno." }, + "SHELL_BELL": { name: "Conchinella", description: "Guarisce 1/8 del danno inflitto a un Pokémon." }, - "TOXIC_ORB": { name: "Tossicsfera", description: "Sfera bizzarra che iperavvelena chi l’ha con sé in una lotta" }, - "FLAME_ORB": { name: "Fiammosfera", description: "Sfera bizzarra che procura una scottatura a chi l’ha con sé in una lotta" }, + "TOXIC_ORB": { name: "Tossicsfera", description: "Sfera bizzarra che iperavvelena chi l’ha con sé in una lotta." }, + "FLAME_ORB": { name: "Fiammosfera", description: "Sfera bizzarra che procura una scottatura a chi l’ha con sé in una lotta." }, - "BATON": { name: "Staffetta", description: "Permette di trasmettere gli effetti quando si cambia Pokémon, aggirando anche le trappole" }, + "BATON": { name: "Staffetta", description: "Permette di trasmettere gli effetti quando si cambia Pokémon, aggirando anche le trappole." }, - "SHINY_CHARM": { name: "Cromamuleto", description: "Misterioso amuleto luminoso che aumenta la probabilità di incontrare Pokémon cromatici" }, - "ABILITY_CHARM": { name: "Abilitamuleto", description: "Aumenta drasticamente la possibilità che un Pokémon selvatico abbia un'abilità nascosta" }, + "SHINY_CHARM": { name: "Cromamuleto", description: "Misterioso amuleto luminoso che aumenta la probabilità di incontrare Pokémon cromatici." }, + "ABILITY_CHARM": { name: "Abilitamuleto", description: "Aumenta drasticamente la possibilità che un Pokémon selvatico abbia un'abilità nascosta." }, - "IV_SCANNER": { name: "Scanner IV", description: "Permette di scansionare gli IV dei Pokémon selvatici. Vengono rivelati 2 IV per pila. I migliori IV vengono mostrati per primi" }, + "IV_SCANNER": { name: "Scanner IV", description: "Permette di scansionare gli IV dei Pokémon selvatici. Vengono rivelati 2 IV per pila. I migliori IV vengono mostrati per primi." }, "DNA_SPLICERS": { name: " Cuneo DNA" }, "MINI_BLACK_HOLE": { name: "Piccolo Buco Nero" }, - "GOLDEN_POKEBALL": { name: "Poké Ball Oro", description: "Aggiunge 1 opzione di oggetto extra alla fine di ogni battaglia" }, + "GOLDEN_POKEBALL": { name: "Poké Ball Oro", description: "Aggiunge 1 opzione di oggetto extra alla fine di ogni battaglia." }, - "ENEMY_DAMAGE_BOOSTER": { name: "Gettone del Danno", description: "Aumenta il danno del 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Gettone della Protezione", description: "Riduce i danni ricevuti del 2.5%" }, - "ENEMY_HEAL": { name: "Gettone del Recupero", description: "Cura il 2% dei PS massimi ogni turno" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Gettone del Danno", description: "Aumenta il danno del 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Gettone della Protezione", description: "Riduce i danni ricevuti del 2.5%." }, + "ENEMY_HEAL": { name: "Gettone del Recupero", description: "Cura il 2% dei PS massimi ogni turno." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "Gettone del Veleno" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Gettone della Paralisi" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "Gettone della Bruciatura" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Gettone Guarigione Completa", description: "Aggiunge una probabilità del 2.5% a ogni turno di curare una condizione di stato" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Gettone Guarigione Completa", description: "Aggiunge una probabilità del 2.5% a ogni turno di curare una condizione di stato." }, "ENEMY_ENDURE_CHANCE": { name: "Gettone di Resistenza" }, - "ENEMY_FUSED_CHANCE": { name: "Gettone della fusione", description: "Aggiunge l'1% di possibilità che un Pokémon selvatico sia una fusione" }, + "ENEMY_FUSED_CHANCE": { name: "Gettone della fusione", description: "Aggiunge l'1% di possibilità che un Pokémon selvatico sia una fusione." }, }, TempBattleStatBoosterItem: { "x_attack": "Attacco X", @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "Piromodulo", "CHILL_DRIVE": "Gelomodulo", "DOUSE_DRIVE": "Idromodulo", + + "FIST_PLATE": "Lastrapugno", + "SKY_PLATE": "Lastracielo", + "TOXIC_PLATE": "Lastrafiele", + "EARTH_PLATE": "Lastrageo", + "STONE_PLATE": "Lastrapietra", + "INSECT_PLATE": "Lastrabaco", + "SPOOKY_PLATE": "Lastratetra", + "IRON_PLATE": "Lastraferro", + "FLAME_PLATE": "Lastrarogo", + "SPLASH_PLATE": "Lastraidro", + "MEADOW_PLATE": "Lastraprato", + "ZAP_PLATE": "Lastrasaetta", + "MIND_PLATE": "Lastramente", + "ICICLE_PLATE": "Lastragelo", + "DRACO_PLATE": "Lastradrakon", + "DREAD_PLATE": "Lastratimore", + "PIXIE_PLATE": "Lastraspiritello", + "BLANK_PLATE": "Lastraripristino", + "LEGEND_PLATE": "Lastraleggenda", + "FIGHTING_MEMORY": "ROM Lotta", + "FLYING_MEMORY": "ROM Volante", + "POISON_MEMORY": "ROM Veleno", + "GROUND_MEMORY": "ROM Terra", + "ROCK_MEMORY": "ROM Roccia", + "BUG_MEMORY": "ROM Coleottero", + "GHOST_MEMORY": "ROM Spettro", + "STEEL_MEMORY": "ROM Acciaio", + "FIRE_MEMORY": "ROM Fuoco", + "WATER_MEMORY": "ROM Acqua", + "GRASS_MEMORY": "ROM Erba", + "ELECTRIC_MEMORY": "ROM Elettro", + "PSYCHIC_MEMORY": "ROM Psico", + "ICE_MEMORY": "ROM Ghiaccio", + "DRAGON_MEMORY": "ROM Drago", + "DARK_MEMORY": "ROM Buio", + "FAIRY_MEMORY": "ROM Folletto", + "BLANK_MEMORY": "ROM Vuota", }, } as const; diff --git a/src/locales/it/nature.ts b/src/locales/it/nature.ts index cf620e1a105..401567901ad 100644 --- a/src/locales/it/nature.ts +++ b/src/locales/it/nature.ts @@ -15,7 +15,7 @@ export const nature: SimpleTranslationEntries = { "Hasty": "Lesta", "Serious": "Seria", "Jolly": "Allegra", - "Naive": "Ingenuaa", + "Naive": "Ingenua", "Modest": "Modesta", "Mild": "Mite", "Quiet": "Quieta", diff --git a/src/locales/it/save-slot-select-ui-handler.ts b/src/locales/it/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..16e36e471a5 --- /dev/null +++ b/src/locales/it/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Overwrite the data in the selected slot?", + "loading": "Loading...", + "wave": "Wave", + "lv": "Lv", + "empty": "Vuoto", +} as const; diff --git a/src/locales/it/starter-select-ui-handler.ts b/src/locales/it/starter-select-ui-handler.ts index 0f3f9df421a..16061766f30 100644 --- a/src/locales/it/starter-select-ui-handler.ts +++ b/src/locales/it/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Seleziona una mossa da scambiare con", "unlockPassive": "Sblocca Passiva", "reduceCost": "Riduci Costo", - "cycleShiny": "R: Alterna Shiny", - "cycleForm": "F: Alterna Forma", - "cycleGender": "G: Alterna Sesso", - "cycleAbility": "E: Alterna Abilità", - "cycleNature": "N: Alterna Natura", - "cycleVariant": "V: Alterna Variante", + "cycleShiny": ": Shiny", + "cycleForm": ": Forma", + "cycleGender": ": Sesso", + "cycleAbility": ": Abilità", + "cycleNature": ": Natura", + "cycleVariant": ": Variante", "enablePassive": "Attiva Passiva", "disablePassive": "Disattiva Passiva", "locked": "Bloccato", diff --git a/src/locales/ko/achv.ts b/src/locales/ko/achv.ts index d48a63868b1..295c4cf72a1 100644 --- a/src/locales/ko/achv.ts +++ b/src/locales/ko/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "업적", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "무패", description: "클래식 모드 클리어", }, + + "MONO_GEN_ONE": { + name: "근본 라이벌", + description: "1세대 챌린지 모드 클리어.", + }, + "MONO_GEN_TWO": { + name: "이거 1.5세대죠?", + description: "2세대 챌린지 모드 클리어.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "3세대 챌린지 모드 클리어.", + }, + "MONO_GEN_FOUR": { + name: "난천이 진짜 최강인가요?", + description: "4세대 챌린지 모드 클리어.", + }, + "MONO_GEN_FIVE": { + name: "100% 오리지널!", + description: "5세대 챌린지 모드 클리어.", + }, + "MONO_GEN_SIX": { + name: "크루아상 안에 뭐 들었나요?", + description: "6세대 챌린지 모드 클리어.", + }, + "MONO_GEN_SEVEN": { + name: "기술적으로는…", + description: "7세대 챌린지 모드 클리어.", + }, + "MONO_GEN_EIGHT": { + name: "챔피언 타임!", + description: "8세대 챌린지 모드 클리어.", + }, + "MONO_GEN_NINE": { + name: "걔, 봐 준 거야", + description: "9세대 챌린지 모드 클리어.", + }, + + "MonoType": { + description: "{{type}} 타입 챌린지 모드 클리어.", + }, + "MONO_NORMAL": { + name: "심플한 것이 가장 강한 것", + }, + "MONO_FIGHTING": { + name: "태권도 할 줄 알아요", + }, + "MONO_FLYING": { + name: "추락하는 것은 날개가 있다", + }, + "MONO_POISON": { + name: "관동 지방 최애 타입", + }, + "MONO_GROUND": { + name: "전기 안 통해요", + }, + "MONO_ROCK": { + name: "웅골참", + }, + "MONO_BUG": { + name: "독침붕처럼 쏴라", + }, + "MONO_GHOST": { + name: "누굴 부를 거야?", + }, + "MONO_STEEL": { + name: "강철 심장", + }, + "MONO_FIRE": { + name: "불타오르네", + }, + "MONO_WATER": { + name: "물 들어올 때 노 젓기", + }, + "MONO_GRASS": { + name: "초록은 동색", + }, + "MONO_ELECTRIC": { + name: "찌릿찌릿", + }, + "MONO_PSYCHIC": { + name: "1세대 최강", + }, + "MONO_ICE": { + name: "얼음땡", + }, + "MONO_DRAGON": { + name: "용용 죽겠지", + }, + "MONO_DARK": { + name: "어둠의 다크", + }, + "MONO_FAIRY": { + name: "설마 자시안으로?", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts index cc91141718c..1f88a895c7c 100644 --- a/src/locales/ko/battle.ts +++ b/src/locales/ko/battle.ts @@ -58,5 +58,7 @@ export const battle: SimpleTranslationEntries = { "ivScannerUseQuestion": "{{pokemonName}}에게 개체값탐지기를 사용하시겠습니까?", "wildPokemonWithAffix": "야생 {{pokemonName}}", "foePokemonWithAffix": "상대 {{pokemonName}}", - "useMove": "{{pokemonNameWithAffix}}의 {{moveName}}!" + "useMove": "{{pokemonNameWithAffix}}의 {{moveName}}!", + "drainMessage": "{{pokemonName}}[[로]]부터\n체력을 흡수했다!", + "regainHealth": "{{pokemonName}}[[는]]\n기력을 회복했다!" } as const; diff --git a/src/locales/ko/challenges.ts b/src/locales/ko/challenges.ts new file mode 100644 index 00000000000..3dad36fd8d1 --- /dev/null +++ b/src/locales/ko/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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": "페어리 타입의 포켓몬만 사용할 수 있습니다.", +} as const; diff --git a/src/locales/ko/config.ts b/src/locales/ko/config.ts index 936154153be..ca14d87cc10 100644 --- a/src/locales/ko/config.ts +++ b/src/locales/ko/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const koConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const koConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const koConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/ko/dialogue.ts b/src/locales/ko/dialogue.ts index cdb6670650f..b8b72fc1d20 100644 --- a/src/locales/ko/dialogue.ts +++ b/src/locales/ko/dialogue.ts @@ -60,86 +60,86 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "breeder": { "encounter": { - 1: "Obedient Pokémon, selfish Pokémon… Pokémon have unique characteristics.", - 2: "Even though my upbringing and behavior are poor, I've raised my Pokémon well.", - 3: "Hmm, do you discipline your Pokémon? Pampering them too much is no good.", + 1: "순종적인 포켓몬, 이기적인 포켓몬… 포켓몬들은 각기 다른 성격을 가지고 있지.", + 2: "내 태도가 그렇게 좋진 않아도, 내 포켓몬들은 잘 키웠어.", + 3: "음, 넌 포켓몬들을 훈육하니? 너무 심하게 하는 것은 좋지 않다고.", }, "victory": { - 1: "It is important to nurture and train each Pokémon's characteristics.", - 2: "Unlike my diabolical self, these are some good Pokémon.", - 3: "Too much praise can spoil both Pokémon and people.", + 1: "각 포켓몬의 성격을 이해하고 육성하는 건 중요해.", + 2: "사악한 나와는 달리 좋은 포켓몬들도 있지.", + 3: "과도한 칭찬은 사람과 포켓몬 모두에게 독이 될 수 있어.", }, "defeat": { - 1: "You should not get angry at your Pokémon, even if you lose a battle.", - 2: "Right? Pretty good Pokémon, huh? I'm suited to raising things.", - 3: "No matter how much you love your Pokémon, you still have to discipline them when they misbehave." + 1: "배틀에서 지더라도 포켓몬에게 화를 내면 안돼.", + 2: "어때? 꽤 괜찮은 포켓몬이지? 난 무언가 기르는 게 꽤 잘 맞더라고.", + 3: "네가 포켓몬을 얼마나 사랑하는지와 관계없이, 그들이 잘못을 저지르면 바로잡아야 해." } }, "breeder_female": { "encounter": { - 1: "Pokémon never betray you. They return all the love you give them.", - 2: "Shall I give you a tip for training good Pokémon?", - 3: "I have raised these very special Pokémon using a special method." + 1: "포켓몬은 절대 널 배신하지 않아. 네가 주는 사랑을 고스란히 되돌려 준다구.", + 2: "좋은 포켓몬을 키우는 팁을 알려줄까?", + 3: "난 아주 특별한 방법으로 아주 특별한 포켓몬들을 키웠지!" }, "victory": { - 1: "Ugh… It wasn't supposed to be like this. Did I administer the wrong blend?", - 2: "How could that happen to my Pokémon… What are you feeding your Pokémon?", - 3: "If I lose, that tells you I was just killing time. It doesn't damage my ego at all." + 1: "이런… 이렇게 될 리가 없는데. 내가 블렌딩을 잘못 썼나?", + 2: "내 포켓몬에게 이런 일이… 넌 네 포켓몬에게 뭘 먹이는 거야?", + 3: "내가 지는 건 그저 내가 시간을 때우고 있었다는 걸 알려주는 거지. 내 자존심엔 전혀 상처가 되지 않는다구." }, "defeat": { - 1: "This proves my Pokémon have accepted my love.", - 2: "The real trick behind training good Pokémon is catching good Pokémon.", - 3: "Pokémon will be strong or weak depending on how you raise them." + 1: "이건 내 포켓몬들이 내 사랑을 받아들였다는 걸 입증하지.", + 2: "좋은 포켓몬을 키우는 진짜 비결은 좋은 포켓몬을 잡는 거야.", + 3: "포켓몬의 강함과 약함은 네가 어떻게 키우느냐에 따라 결정되지." } }, "fisherman": { "encounter": { - 1: "Aack! You made me lose a bite!\nWhat are you going to do about it?", - 2: "Go away! You're scaring the Pokémon!", - 3: "Let's see if you can reel in a victory!", + 1: "앗! 너 때문에 한 마리 놓쳤잖아! 어떻게 할 거야?", + 2: "저리 가! 네가 포켓몬들을 놀래키고 있잖아!", + 3: "네가 승리를 낚을 수 있을지 한번 보자고!", }, "victory": { - 1: "Just forget about it.", - 2: "Next time, I'll be reelin' in the triumph!", - 3: "Guess I underestimated the currents this time.", + 1: "그냥 잊어버려.", + 2: "다음 번엔 내가 승리의 나팔을 울리고 있을거다!", + 3: "이번엔 내가 물살을 과소평가했나보군.", }, }, "fisherman_female": { "encounter": { - 1: "Woah! I've hooked a big one!", - 2: "Line's in, ready to reel in success!", - 3: "Ready to make waves!" + 1: "월척이다!", + 2: "낚시대는 던져졌고, 이젠 성공을 끌어올리는 일만 남았다!", + 3: "파도를 일으킬 준비는 끝났어!" }, "victory": { - 1: "I'll be back with a stronger hook.", - 2: "I'll reel in victory next time.", - 3: "I'm just sharpening my hooks for the comeback!" + 1: "더 튼튼한 바늘을 가지고 돌아올테다.", + 2: "다음번엔 꼭 성공을 낚을 거야!", + 3: "다시 돌아올 날을 기다리며 바늘을 다듬고 있을게!" }, }, "swimmer": { "encounter": { - 1: "Time to dive in!", - 2: "Let's ride the waves of victory!", - 3: "Ready to make a splash!", + 1: "뛰어들 시간이다!", + 2: "승리의 파도 속으로!", + 3: "첨벙댈 준비는 끝났어!", }, "victory": { - 1: "Drenched in defeat!", - 2: "A wave of defeat!", - 3: "Back to shore, I guess.", + 1: "패배에 젖어버렸어…", + 2: "패배의 파도였군.", + 3: "해변으로 돌아갈 시간이군.", }, }, "backpacker": { "encounter": { - 1: "Pack up, game on!", - 2: "Let's see if you can keep pace!", - 3: "Gear up, challenger!", - 4: "I've spent 20 years trying to find myself… But where am I?" + 1: "게임 시작이야! 짐 단단히 싸놓으라구!", + 2: "네가 속도를 유지할 수 있을지 보자!", + 3: "각오 단단히 하라고!", + 4: "20년 동안 나 자신을 찾기 위해 헤매왔어… 근데 내가 어디 있지?" }, "victory": { - 1: "Tripped up this time!", - 2: "Oh, I think I'm lost.", - 3: "Dead end!", - 4: "Wait up a second! Hey! Don't you know who I am?" + 1: "이번엔 걸려 넘어져 버렸네!", + 2: "내가 속도를 잃어버렸잖아!", + 3: "막다른 길이야!", + 4: "잠깐! 그래 거기, 혹시 내가 누군지 아나?" }, }, "ace_trainer": { @@ -211,34 +211,34 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "battle_girl": { "encounter": { - 1: "You don't have to try to impress me. You can lose against me.", + 1: "감동을 주려고 노력할 필요는 없어. 네가 질 수도 있으니까.", }, "victory": { - 1: "It's hard to say good-bye, but we are running out of time…", + 1: "작별인사는 어렵지만, 우리에겐 시간이 얼마 안 남았네…", }, }, "hiker": { "encounter": { - 1: "My middle-age spread has given me as much gravitas as the mountains I hike!", - 2: "I inherited this big-boned body from my parents… I'm like a living mountain range…", + 1: "중년으로 접어들면서 등산해왔던 산처럼 진중해졌습니다!", + 2: "살아있는 산같은… 큰 체격을 부모님이 물려주셨죠…", }, "victory": { - 1: "At least I cannot lose when it comes to BMI!", - 2: "It's not enough… It's never enough. My bad cholesterol isn't high enough…" + 1: "적어도 BMI에 대해서는 질 수 없습니다!", + 2: "부족해… 절대로 충분하지 않아. 저의 콜레스테롤이 부족합니다…" }, }, "ranger": { "encounter": { - 1: "When I am surrounded by nature, most other things cease to matter.", - 2: "When I'm living without nature in my life, sometimes I'll suddenly feel an anxiety attack coming on." + 1: "자연에 둘러싸여 있으면, 다른 건 중요하지 않게 느껴져.", + 2: "인생에서 자연을 빼고 살면, 가끔 갑자기 마음이 불안해지지." }, "victory": { - 1: "It doesn't matter to the vastness of nature whether I win or lose…", - 2: "Something like this is pretty trivial compared to the stifling feelings of city life." + 1: "광활한 자연 앞에서는 내가 이기든 지든 상관없어…", + 2: "도시 생활의 답답한 느낌에 비하면 이런 것은 아주 사소한 일지." }, "defeat": { - 1: "I won the battle. But victory is nothing compared to the vastness of nature…", - 2: "I'm sure how you feel is not so bad if you compare it to my anxiety attacks…" + 1: "내가 이겼네. 그러나 승리는 광대한 자연에 비하면 아무것도 아니야…", + 2: "내 마음속 불안함과 비교하면, 당신 기분은 그렇게 나쁘지 않을텐데…" } }, "scientist": { @@ -305,84 +305,264 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "hex_maniac": { "encounter": { - 1: "I normally only ever listen to classical music, but if I lose, I think I shall try a bit of new age!", - 2: "I grow stronger with each tear I cry." + 1: "평소에는 클래식 음악만 들었는데, 지면 뉴에이지도 좀 들어볼까!", + 2: "눈물을 흘릴 때마다 더 강해지는 것 같아." }, "victory": { - 1: "Is this the dawning of the age of Aquarius?", - 2: "Now I can get even stronger. I grow with every grudge." + 1: "지금이 물병자리 시대의 시작일까?", + 2: "이제 나는 더 강해지겠지. 모든 원한과 함께 성장하겠어." }, "defeat": { - 1: "New age simply refers to twentieth century classical composers, right?", - 2: "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself." + 1: "뉴에이지란 단순히 20세기 클래식 작곡가들을 말하는 거, 맞지?", + 2: "슬픔이나 좌절에 얽매이지 마. 넌 그 원한을 원동력으로 사용할 수 있어." } }, "psychic": { "encounter": { - 1: "Hi! Focus!", + 1: "안녕! 집중해!", }, "victory": { - 1: "Eeeeek!", + 1: "에에에에엣!", }, }, "officer": { "encounter": { - 1: "Brace yourself, because justice is about to be served!", - 2: "Ready to uphold the law and serve justice on the battlefield!" + 1: "마음의 준비를 하시죠, 정의가 곧 실행될 거니까요!", + 2: "법을 지키고 정의를 위해 봉사할 준비가 되었습니다!" }, "victory": { - 1: "The weight of justice feels heavier than ever…", - 2: "The shadows of defeat linger in the precinct." + 1: "정의의 무게가 그 어느 때보다 무겁게 느껴집니다…", + 2: "패배의 그림자가 관할 경찰서에 남았습니다." } }, "beauty": { "encounter": { - 1: "My last ever battle… That's the way I'd like us to view this match…", + 1: "나의 마지막 배틀… 이 승부를 그렇게 봐주셨으면 좋겠어요…", }, "victory": { - 1: "It's been fun… Let's have another last battle again someday…", + 1: "즐거웠어요… 언젠가 또 다른 마지막 승부를 하죠…", }, }, "baker": { "encounter": { - 1: "Hope you're ready to taste defeat!" + 1: "패배의 맛을 볼 준비는 됐겠지!" }, "victory": { - 1: "I'll bake a comeback." + 1: "실력이든 빵이든, 굽고 나면 단단해지는 법이라네." }, }, "biker": { "encounter": { - 1: "Time to rev up and leave you in the dust!" + 1: "힘차게 먼지 속으로 출발할 시간입니다!" }, "victory": { - 1: "I'll tune up for the next race." + 1: "다음 경주를 위해 준비해야겠습니다." }, }, "firebreather": { "encounter": { - 1: "My flames shall devour you!", - 2: "My soul is on fire. I'll show you how hot it burns!", - 3: "Step right up and take a look!" + 1: "내 불꽃이 너를 삼킬 테니까!", + 2: "내 영혼은 불타고 있다. 얼마나 뜨겁게 타는지 보여주지!", + 3: "이리 올라와서 보도록!" }, "victory": { - 1: "I burned down to ashes...", - 2: "Yow! That's hot!", - 3: "Ow! I scorched the tip of my nose!" + 1: "하얗게 불태웠다………", + 2: "큭! 제법 뜨겁군!", + 3: "으윽! 코끝에 화상을 입었다!" }, }, "sailor": { "encounter": { - 1: "Matey, you're walking the plank if you lose!", - 2: "Come on then! My sailor's pride is at stake!", - 3: "Ahoy there! Are you seasick?" + 1: "친구여, 진다면 널빤지 행이야!", + 2: "덤벼! 내 선원으로서 자존심이 위태롭군!", + 3: "여어 거기! 뱃멀미 하나?" }, "victory": { - 1: "Argh! Beaten by a kid!", - 2: "Your spirit sank me!", - 3: "I think it's me that's seasick..." + 1: "크윽! 꼬맹이한테 지다니!", + 2: "네 영혼이 나를 침몰시켰어!", + 3: "내가 뱃멀미가 나는 것 같군…" }, }, + "rocket_grunt": { + "encounter": { + 1: "트러블에 대비하도록!" + }, + "victory": { + 1: "로켓단은 다시 떠오를 거니까!" + }, + }, + "magma_grunt": { + "encounter": { + 1: " 마그마단을 방해한다면, 자비는 없닷!" + }, + "victory": { + 1: "하? 내가 졌어?!" + }, + }, + "aqua_grunt": { + "encounter": { + 1: "아쿠아단을 넘본 사람에게는 자비는 없다, 꼬마도 마찬가지야!" + }, + "victory": { + 1: "말도 안돼!" + }, + }, + "galactic_grunt": { + "encounter": { + 1: "갤럭시단을 방해하지 마!" + }, + "victory": { + 1: "사격 중지…… " + }, + }, + "plasma_grunt": { + "encounter": { + 1: "다른 생각을 가진사람들은 용납하지 않겠다!" + }, + "victory": { + 1: "플라-스마-!" + }, + }, + "flare_grunt": { + "encounter": { + 1: "패션이 우리한텐 가장 중요하다고!" + }, + "victory": { + 1: "미래가 밝아 보이질 않네." + }, + }, + "rocket_boss_giovanni_1": { + "encounter": { + 1: "그래서! 여기까지 오다니, 감탄이 절로 나오는군!" + }, + "victory": { + 1: "하! 이럴 순 없어!" + }, + "defeat": { + 1: "자신의 힘을 측정하지 못하는 걸 보아하니, 아직 별볼일 없는 꼬맹이로군. 내 말을 명심하도록. " + } + }, + "rocket_boss_giovanni_2": { + "encounter": { + 1: "옛 친구들이 나를 필요로 하고 있다…… 그런데도 방해하겠다는 건가?" + }, + "victory": { + 1: "어떻게 이런 일이…?\n로켓단의 소중한 꿈이 환상에 불과해졌군…… " + }, + "defeat": { + 1: "로켓단은 다시 태어난다, 그리고 세상을 지배할 것이다!" + } + }, + "magma_boss_maxie_1": { + "encounter": { + 1: "내 손으로 널 파묻어주지. 영광으로 알도록!" + }, + "victory": { + 1: "윽! 꽤… 제법이군…\n내가 뒤쳐졌지만, 겨우 한 끝이다…" + }, + "defeat": { + 1: "마그마단이 앞선다!" + } + }, + "magma_boss_maxie_2": { + "encounter": { + 1: "나와 내 목표 사이에 남은 마지막 장애물이로군.\n최후의 공격에 대비하도록! 후하하하!" + }, + "victory": { + 1: "이런… 이럴 수는… 없어… " + }, + "defeat": { + 1: "이제부터… 인류의 이상을 위해 대지를 더 늘려가겠다." + } + }, + "aqua_boss_archie_1": { + "encounter": { + 1: "내가 아쿠아단의 리더다, 유감스럽게도 넌 이게 끝이겠군." + }, + "victory": { + 1: "다시 어딘가에서 만나도록하지. 그 얼굴 기억해둘테니까." + }, + "defeat": { + 1: "좋군! 이제 아쿠아단을 막아설 것은 없다!" + } + }, + "aqua_boss_archie_2": { + "encounter": { + 1: "이 날이 오는 것을 너무 오래 기다렸군.\n이것이 우리의 진정한 힘이다!" + }, + "victory": { + 1: "내가 생각했던 것들이…… " + }, + "defeat": { + 1: "이 세상을 원래의 순수한 상태로 되돌리겠다, 그 모든 것을!!" + } + }, + "galactic_boss_cyrus_1": { + "encounter": { + 1: "넌 공허한 감정에 이끌려 이곳에 오게된 것이다.\n마음에 귀를 기울인 것을 후회하게 해주지!" + }, + "victory": { + 1: "흥미롭군. 게다가 꽤 궁금해졌어." + }, + "defeat": { + 1: "새로운 세상을 만들 것이다…" + } + }, + "galactic_boss_cyrus_2": { + "encounter": { + 1: "이런 우리가 다시 만나게 됐군. 우리의 운명이 얽히게 된 것 같군.\n 하지만 지금 여기서, 나는 마침내 그 끈을 끊을 것이다!" + }, + "victory": { + 1: "어떻게? 어째서? 어떻게?!" + }, + "defeat": { + 1: "작별이로군." + } + }, + "plasma_boss_ghetsis_1": { + "encounter": { + 1: "누구도 저를 막을 수 없습니다! 무슨 짓을 하더라도!" + }, + "victory": { + 1: "…어떻게 된 거지? 이 몸은 플라스마단을 만들어낸 완벽한 남자라고! " + }, + "defeat": { + 1: "세계를 바꿀 완전한 지배자가 아니었단 말인가!? …흐하하!" + } + }, + "plasma_boss_ghetsis_2": { + "encounter": { + 1: "오시죠! 당신이 모든 희망을 잃는 순간의 얼굴을 보겠습니다!" + }, + "victory": { + 1: "내 계산이… 틀려! 내 치밀한 계획이 틀리다니! 세상은 내 것이어야 하는데!" + }, + "defeat": { + 1: "큐레무! 합체해라!" + } + }, + "flare_boss_lysandre_1": { + "encounter": { + 1: "나를 막겠다고? 배틀로 증명하도록." + }, + "victory": { + 1: "네가 나를 여기서 막았군. 하지만 잠시 기다리도록. " + }, + "defeat": { + 1: "포켓몬은… 더 이상 존재하지 않는다." + } + }, + "flare_boss_lysandre_2": { + "encounter": { + 1: "너의 미래와 나의 미래… 어느 쪽이 옳은지 서로의 포켓몬에게 묻도록 하지." + }, + "victory": { + 1: "크윽!" + }, + "defeat": { + 1: "우매한 자들이 이 아름다운 세상을 계속 더럽히고 있군." + } + }, "brock": { "encounter": { 1: "내 전문인 바위 타입 포켓몬으로 널 쓰러뜨려줄게! 덤벼!", @@ -697,19 +877,19 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "falkner": { "encounter": { - 1: "I'll show you the real power of the magnificent bird Pokémon!", - 2: "Winds, stay with me!", - 3: "Dad! I hope you're watching me battle from above!" + 1: "넓은 하늘을 화려하게 나는 새 포켓몬의 진정한 강함을 알게 해주겠다!", + 2: "바람이여, 나에게 오라!", + 3: "아버지, 내 시합을 하늘에서도 봐줘!" }, "victory": { - 1: "I understand… I'll bow out gracefully.", - 2: "A defeat is a defeat. You are strong indeed.", - 3: "…Shoot! Yeah, I lost." + 1: "알았다… 미련없이 땅에 내려가지.", + 2: "패배는 패배니까. 넌 정말 강하군.", + 3: "…큭! 그래, 내가 졌다." }, "defeat": { - 1: "Dad! I won with your cherished bird Pokémon…", - 2: "Bird Pokémon are the best after all!", - 3: "Feels like I'm catching up to my dad!" + 1: "아버지! 소중히 여기던 새 포켓몬으로 이겼어…", + 2: "언제나 새 포켓몬이 최강이다!", + 3: "아버지를 따라 잡은 기분이군!" } }, "nessa": { @@ -874,83 +1054,83 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "morty": { "encounter": { - 1: `With a little more, I could see a future in which I meet the legendary Pokémon. - $You're going to help me reach that level!`, - 2: `It's said that a rainbow-hued Pokémon will come down to appear before a truly powerful Trainer. - $I believed that tale, so I have secretly trained here all my life. As a result, I can now see what others cannot. - $I see a shadow of the person who will make the Pokémon appear. - $I believe that person is me! You're going to help me reach that level!`, - 3: "Whether you choose to believe or not, mystic power does exist.", - 4: "You can bear witness to the fruits of my training.", - 5: "You must make your soul one with that of Pokémon. Can you do this?", - 6: "Say, do you want to be part of my training?" + 1: `조금만 더 노력하면, 내가 전설의 포켓몬을 만나는 미래가 보여. + $내가 그 수준에 도달할 수 있게 도와줘!`, + 2: `커다란 무지개색 포켓몬은 진정한 강함을 가진 트레이너 앞에 나타난다는 이야기가 있어. + $난 그 이야기를 믿고, 줄곧 이 곳에서 몰래 수행하고 있어. 그 결과로, 다른 사람들은 볼 수 없는 것을 볼 수 있게 됐지. + $내겐 그 포켓몬을 나타나게 할 사람의 그림자가 보이거든. + $난 그게 나라고 믿어! 넌 내가 그 수준에 올라갈 수 있도록 도와줘야겠어!`, + 3: "네가 믿든 믿지 않든, 불가사의한 힘은 존재해.", + 4: "넌 내 수련의 결실을 보게 될 거야.", + 5: "포켓몬과 너의 영혼을 하나로 만들어야 해. 가능하겠어?", + 6: "저기, 너 내 수행의 일부분이 되고 싶은거지?" }, "victory": { - 1: "I'm not good enough yet…", - 2: `I see… Your journey has taken you to far-away places and you have witnessed much more than I. - $I envy you for that…`, - 3: "How is this possible…", - 4: `I don't think our potentials are so different. - $But you seem to have something more than that… So be it.`, - 5: "Guess I need more training.", - 6: "That's a shame." + 1: "나는 아직 멀었구나…", + 2: `그래… 여행으로 먼 곳을 돌아다니면서, 나보다 훨씬 많은 것을 봐왔구나. + $네가 조금 부럽네…`, + 3: "이게 어떻게 가능한 거지…", + 4: `우리의 잠재력은 그렇게 다르진 않은 것 같아. + $그치만 넌 그것과 다른 무언가를 많이 갖고 있는 것 같네… 흐음.`, + 5: "수련이 더 필요하겠군.", + 6: "안타깝게 됐네." }, "defeat": { - 1: "I moved… one step ahead again.", - 2: "Fufufu…", - 3: "Wh-what?! It can't be! Even that wasn't enough?", - 4: "I feel like I just smashed through a really stubborn boulder!", - 5: "Ahahahah!", - 6: "I knew I would win!" + 1: "내가…다시 한 발짝 앞섰어.", + 2: "후후훗…", + 3: "뭐-뭐야?! 이럴 수가! 그것도 부족해?", + 4: "정말 단단한 바위를 뚫고 나온 기분인데!", + 5: "아하하하하!", + 6: "내가 이길 줄 알았어!" } }, "crispin": { "encounter": { - 1: "I wanna win, so that's exactly what I'll do!", - 2: "I battle because I wanna battle! And you know what? That's how it should be!" + 1: "이기고 싶으니까 이기고 말겠어!", + 2: "싸우고 싶으면 싸운다! 이거면 충분하지 않아!?" }, "victory": { - 1: "I wanted to win…but I lost!", - 2: "I lost…'cause I couldn't win!" + 1: "이기고 싶었는데…졌잖아!", + 2: "이기지 못해서…지고 말았어!" }, "defeat": { - 1: "Hey, wait a sec. Did I just win? I think I just won! Talk about satisfying!", - 2: "Wooo! That was amazing!" + 1: "잠시만. 나 지금 이긴거지? 이긴 거 맞지! 기분 좋은데!", + 2: "우와아! 이거 굉장한데!" } }, "amarys": { "encounter": { - 1: `I want to be the one to help a certain person. That being the case, I cannot afford to lose. - $… Our battle starts now.`, + 1: `네리네는 그 사람을 구원하고 싶습니다. 그렇기에 패배는 용납되지 않습니다. + $… 승부를 시작합니다.`, }, "victory": { - 1: "I am… not enough, I see." + 1: "네리네는… 안 된다는 건가요." }, "defeat": { - 1: "Victory belongs to me. Well fought." + 1: "네리네가 승리했습니다. 수고하셨습니다." } }, "lacey": { "encounter": { - 1: "I'll be facing you with my usual party as a member of the Elite Four." + 1: "이번에는 사천왕으로서 승부하는 거니까 평소 사용하는 아이들로 상대해 드릴게요!" }, "victory": { - 1: "That was a great battle!" + 1: "멋진 포켓몬 배틀이었어요!" }, "defeat": { - 1: "Let's give your Pokémon a nice round of applause for their efforts!" + 1: "당신의 포켓몬의 노력에 박수를 보내주세요!" } }, "drayton": { "encounter": { - 1: `Man, I love chairs. Don't you love chairs? What lifesavers. - $I don't get why everyone doesn't just sit all the time. Standing up's tiring work!`, + 1: `의자는 좋은 거야. 너도 그렇게 생각해? 정말 고마운 물건이지. + $왜 다들 앉지 않는 걸까. 서 있는 건 힘들잖아!`, }, "victory": { - 1: "Guess I should've expected that!" + 1: "전보다 더 강해질 줄이야!" }, "defeat": { - 1: "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?" + 1: "헤헤헷! 내 승리야. 분한 건 알겠지만 카지처럼 나가떨어지지마, 응?" } }, "ramos": { @@ -1146,26 +1326,26 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "lorelei": { "encounter": { - 1: `No one can best me when it comes to icy Pokémon! Freezing moves are powerful! - $Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?`, + 1: `얼음포켓몬을 내보내면 대적할 사람이 없지! 상대를 얼린다는 건 매우 강력한 공격이야. + $네 포켓몬이 꽁꽁 얼면 그때부턴 내 손바닥 위거든! 아하하! 준비됐어?`, }, "victory": { - 1: "How dare you!" + 1: "어떻게 감히!" }, "defeat": { - 1: "There's nothing you can do once you're frozen." + 1: "얼어붙은 넌 아무것도 할 수 없어." } }, "will": { "encounter": { - 1: `I have trained all around the world, making my psychic Pokémon powerful. - $I can only keep getting better! Losing is not an option!`, + 1: `나는 전세계를 돌아다니며, 강한 에스퍼 포켓몬을 만들도록 수행해왔다. + $계속 더 정진하겠다! 패배는 선택지에 없어!`, }, "victory": { - 1: "I… I can't… believe it…" + 1: "이… 내가… 믿을수 없어…" }, "defeat": { - 1: "That was close. I wonder what it is that you lack." + 1: "근소한 차이였다. 네게 부족한 것이 무엇인지 궁금하군." } }, "malva": { @@ -1216,35 +1396,35 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "bruno": { "encounter": { - 1: "We will grind you down with our superior power! Hoo hah!" + 1: "우월한 힘으로 너를 부숴주지! 우! 하~앗!" }, "victory": { - 1: "Why? How could I lose?" + 1: "하? 어떻게 내가 진 거지?" }, "defeat": { - 1: "You can challenge me all you like, but the results will never change!" + 1: "얼마든지 내게 도전 할 수 있지만, 결과는 절대 바뀌지 않을 거다!" } }, "bugsy": { "encounter": { - 1: "I'm Bugsy! I never lose when it comes to bug Pokémon!" + 1: "내 이름은 호일! 벌레 포켓몬에 대해서라면 누구에게도 지지 않아!" }, "victory": { - 1: "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win." + 1: "우와, 대단해! 넌 포켓몬 전문가구나!\n내 연구는 아직 안 끝났네. 응, 네가 이겼어." }, "defeat": { - 1: "Thanks! Thanks to our battle, I was also able to make progress in my research!" + 1: "고마워! 방금 승부 덕분에, 내 연구도 진전을 이룬 것 같아!" } }, "koga": { "encounter": { - 1: "Fwahahahaha! Pokémon are not merely about brute force--you shall see soon enough!" + 1: "후하하하! 포켓몬은 딘순히 강한 것만이 아니다--곧 알려주지!" }, "victory": { - 1: "Ah! You've proven your worth!" + 1: "하! 스스로 증명해냈군!" }, "defeat": { - 1: "Have you learned to fear the techniques of the ninja?" + 1: "인술을 피하는 방법을 배워보겠나?" } }, "bertha": { @@ -1319,13 +1499,13 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "agatha": { "encounter": { - 1: "Pokémon are for battling! I'll show you how a real Trainer battles!" + 1: "포켓몬은 싸우게 하려고 있는 것이야! 진정한 싸움이라는 것을 보여주겠다!" }, "victory": { - 1: "Oh my! You're something special, child!" + 1: "이런! 넌 무언가 특별하구나, 꼬마야!" }, "defeat": { - 1: "Bahaha. That's how a proper battle's done!" + 1: "바하하하. 제대로 된 승부는 이렇게 하는거다!" } }, "flint": { @@ -1414,33 +1594,33 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "lance": { "encounter": { - 1: "I've been waiting for you. Allow me to test your skill.", - 2: "I thought that you would be able to get this far. Let's get this started." + 1: "널 기다리고 있었다. 그 실력을 시험해보겠어.", + 2: "여기까지 올 수 있을거라고 생각했다. 슬슬 시작해볼까." }, "victory": { - 1: "You got me. You are magnificent!", - 2: "I never expected another trainer to beat me… I'm surprised." + 1: "날 따라잡았군. 훌륭해!", + 2: "다른 트레이너가 날 이길 거라곤 생각 못했는데… 놀랍군." }, "defeat": { - 1: "That was close. Want to try again?", - 2: "It's not that you are weak. Don't let it bother you." + 1: "근소하군. 다시 해볼까?", + 2: "네가 약해서가 아니다. 신경쓰지 말도록." } }, "karen": { "encounter": { - 1: "I am Karen. Would you care for a showdown with my Dark-type Pokémon?", - 2: "I am unlike those you've already met.", - 3: "You've assembled a charming team. Our battle should be a good one." + 1: "난 카렌! 내 악 타입 포켓몬과의 승부를 원하니?", + 2: "난 네가 이전에 만났던 트레이너들과는 달라.", + 3: "강한 포켓몬, 약한 포켓몬, 그런 건 사람이 멋대로 정하는 것." }, "victory": { - 1: "No! I can't win. How did you become so strong?", - 2: "I will not stray from my chosen path.", - 3: "The Champion is looking forward to meeting you." + 1: "좋아하는 마음이 전해진다면 포켓몬도 답할거야. 그렇게 강해지는 거지", + 2: "난 내가 선택한 길을 걸어갈거야.", + 3: "챔피언이 너를 기다리고 있어." }, "defeat": { - 1: "That's about what I expected.", - 2: "Well, that was relatively entertaining.", - 3: "Come visit me anytime." + 1: "정말 강한 트레이너라면 좋아하는 포켓몬으로 이길 수 있도록 열심히 해야 해.", + 2: "뭐, 비교적 재밌었어.", + 3: "언제라도 다시 찾아와, 상대해줄게." } }, "milo": { @@ -1507,13 +1687,13 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "blue": { "encounter": { - 1: "You must be pretty good to get this far." + 1: "여기까지 왔다니, 실력이 꽤 봐줄만 할 것 같은데." }, "victory": { - 1: "I've only lost to him and now to you… Him? Hee, hee…" + 1: "그 녀석한테만 지는 줄 알았는데… 누구냐고? 하, 하…" }, "defeat": { - 1: "See? My power is what got me here." + 1: "봤지? 여기까지 온 내 실력." } }, "piers": { @@ -1540,24 +1720,24 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "jasmine": { "encounter": { - 1: "Oh… Your Pokémon are impressive. I think I will enjoy this." + 1: "와… 당신의 포켓몬은 인상적이네요. 재미있을 것 같아요." }, "victory": { - 1: "You are truly strong. I'll have to try much harder, too." + 1: "당신은 정말 강하네요. 저도 더 열심히 노력해야겠어요." }, "defeat": { - 1: "I never expected to win." + 1: "이길 줄은 몰랐어요." } }, "lance_champion": { "encounter": { - 1: "I am still the Champion. I won't hold anything back." + 1: "여전히 난 챔피언이다. 더이상 주저할 게 없군." }, "victory": { - 1: "This is the emergence of a new Champion." + 1: "새로운 챔피언의 등장이군." }, "defeat": { - 1: "I successfully defended my Championship." + 1: "성공적으로 챔피언 자리를 지켜냈다." } }, "steven": { @@ -1652,24 +1832,24 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "whitney": { "encounter": { - 1: "Hey! Don't you think Pokémon are, like, super cute?" + 1: "있지! 포켓몬들 말이야, 정말 너무 귀엽지?" }, "victory": { - 1: "Waaah! Waaah! You're so mean!" + 1: "흑! 으아앙! 너무해!" }, "defeat": { - 1: "And that's that!" + 1: "이걸로 끝!" } }, "chuck": { "encounter": { - 1: "Hah! You want to challenge me? Are you brave or just ignorant?" + 1: "하! 나에게 도전하겠다고? 용감한 거냐, 아니면 그냥 무모한 거냐?" }, "victory": { - 1: "You're strong! Would you please make me your apprentice?" + 1: "자네 강하군! 나를 제자로 삼아주겠나?" }, "defeat": { - 1: "There. Do you realize how much more powerful I am than you?" + 1: "자. 내가 자네보다 얼마나 더 강력한지 깨달았겠지?" } }, "katy": { @@ -1685,24 +1865,24 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "pryce": { "encounter": { - 1: "Youth alone does not ensure victory! Experience is what counts." + 1: "젊음만으로는 승리를 보장할 수 없다! 중요한 것은 경험이다." }, "victory": { - 1: "Outstanding! That was perfect. Try not to forget what you feel now." + 1: "특출하군! 완벽해. 지금 이 느낌을 잊지 말도록." }, "defeat": { - 1: "Just as I envisioned." + 1: "내가 예상했던 그대로군." } }, "clair": { "encounter": { - 1: "Do you know who I am? And you still dare to challenge me?" + 1: "내가 누군지 알지? 그런데도 감히 내게 도전해?" }, "victory": { - 1: "I wonder how far you can get with your skill level. This should be fascinating." + 1: "네 실력이 어디까지 올라갈 수 있는지 궁금하네. 아주 흥미진진하겠어." }, "defeat": { - 1: "That's that." + 1: "끝이다." } }, "maylene": { @@ -2448,7 +2628,7 @@ export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { }, "marnie_piers_double": { "encounter": { - 1: `두송: 큰서트 즐길 준비 됐어? + 1: `두송: 콘서트 즐길 준비 됐어? $마리: 오빠... 얘들은 노래가 아니라 승부를 하러 왔어...`, }, "victory": { diff --git a/src/locales/ko/game-mode.ts b/src/locales/ko/game-mode.ts new file mode 100644 index 00000000000..ad387010a8f --- /dev/null +++ b/src/locales/ko/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "클래식", + "endless": "엔들리스", + "endlessSpliced": "엔들리스(융합체)", + "dailyRun": "데일리 런", + "unknown": "언노운", + "challenge": "챌린지", +} as const; diff --git a/src/locales/ko/menu.ts b/src/locales/ko/menu.ts index 3bd52540f94..9245d67533a 100644 --- a/src/locales/ko/menu.ts +++ b/src/locales/ko/menu.ts @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "주간 랭킹", "noRankings": "랭킹 정보 없음", "loading": "로딩 중…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "플레이어 온라인", - "empty":"빈 슬롯", "yes":"예", "no":"아니오", "disclaimer": "면책 조항", diff --git a/src/locales/ko/modifier-type.ts b/src/locales/ko/modifier-type.ts index 34d57474e56..a4786f86176 100644 --- a/src/locales/ko/modifier-type.ts +++ b/src/locales/ko/modifier-type.ts @@ -8,7 +8,7 @@ export const modifierType: ModifierTypeTranslationEntries = { }, "AddVoucherModifierType": { name: "{{voucherTypeName}} {{modifierCount}}장", - description: "{{voucherTypeName}} {{modifierCount}}장을 획득", + description: "{{voucherTypeName}} {{modifierCount}}장을 획득한다.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "포켓몬 1마리의 HP를 {{restorePoints}} 또는 {{restorePercent}}% 중\n높은 수치만큼 회복", + description: "포켓몬 1마리의 HP를 {{restorePoints}} 또는 {{restorePercent}}% 중\n높은 수치만큼 회복한다.", extra: { - "fully": "포켓몬 1마리의 HP를 모두 회복", - "fullyWithStatus": "포켓몬 1마리의 HP와 상태 이상을 모두 회복", + "fully": "포켓몬 1마리의 HP를 모두 회복한다.", + "fullyWithStatus": "포켓몬 1마리의 HP와 상태 이상을 모두 회복한다.", } }, "PokemonReviveModifierType": { - description: "기절해 버린 포켓몬 1마리의 HP를 {{restorePercent}}%까지 회복", + description: "기절해 버린 포켓몬 1마리의 HP를 {{restorePercent}}%까지 회복한다.", }, "PokemonStatusHealModifierType": { - description: "포켓몬 1마리의 상태 이상을 모두 회복", + description: "포켓몬 1마리의 상태 이상을 모두 회복한다.", }, "PokemonPpRestoreModifierType": { - description: "포켓몬이 기억하고 있는 기술 중 1개의 PP를 {{restorePoints}}만큼 회복", + description: "포켓몬이 기억하고 있는 기술 중 1개의 PP를 {{restorePoints}}만큼 회복한다.", extra: { - "fully": "포켓몬이 기억하고 있는 기술 중 1개의 PP를 모두 회복", + "fully": "포켓몬이 기억하고 있는 기술 중 1개의 PP를 모두 회복한다.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "포켓몬이 기억하고 있는 4개의 기술 PP를 {{restorePoints}}씩 회복", + description: "포켓몬이 기억하고 있는 4개의 기술 PP를 {{restorePoints}}씩 회복한다.", extra: { - "fully": "포켓몬이 기억하고 있는 4개의 기술 PP를 모두 회복", + "fully": "포켓몬이 기억하고 있는 4개의 기술 PP를 모두 회복한다.", } }, "PokemonPpUpModifierType": { - description: "포켓몬이 기억하고 있는 기술 중 1개의 PP 최대치를 5마다 {{upPoints}}씩 상승 (최대 3)", + description: "포켓몬이 기억하고 있는 기술 중 1개의 PP 최대치를 5마다 {{upPoints}}씩 상승시킨다 (최대 3).", }, "PokemonNatureChangeModifierType": { name: "{{natureName}}민트", description: "포켓몬의 성격을 {{natureName}}[[로]] 바꾸고 스타팅에도 등록한다.", }, "DoubleBattleChanceBoosterModifierType": { - description: "{{battleCount}}번의 배틀 동안 더블 배틀이 등장할 확률 두 배", + description: "{{battleCount}}번의 배틀 동안 더블 배틀이 등장할 확률이 두 배가 된다.", }, "TempBattleStatBoosterModifierType": { - description: "자신의 모든 포켓몬이 5번의 배틀 동안 {{tempBattleStatName}}[[가]] 한 단계 증가" + description: "자신의 모든 포켓몬이 5번의 배틀 동안 {{tempBattleStatName}}[[가]] 한 단계 증가한다." }, "AttackTypeBoosterModifierType": { - description: "지니게 하면 {{moveType}}타입 기술의 위력이 20% 상승", + description: "지니게 하면 {{moveType}}타입 기술의 위력이 20% 상승한다.", }, "PokemonLevelIncrementModifierType": { - description: "포켓몬 1마리의 레벨이 1만큼 상승", + description: "포켓몬 1마리의 레벨이 1만큼 상승한다.", }, "AllPokemonLevelIncrementModifierType": { - description: "자신의 모든 포켓몬의 레벨이 1씩 상승", + description: "자신의 모든 포켓몬의 레벨이 1씩 상승한다.", }, "PokemonBaseStatBoosterModifierType": { description: "지니게 하면 {{statName}} 종족값을 10% 올려준다. 개체값이 높을수록 더 많이 누적시킬 수 있다.", }, "AllPokemonFullHpRestoreModifierType": { - description: "자신의 포켓몬의 HP를 모두 회복", + description: "자신의 포켓몬의 HP를 모두 회복한다.", }, "AllPokemonFullReviveModifierType": { - description: "자신의 포켓몬의 HP를 기절해 버렸더라도 모두 회복", + description: "자신의 포켓몬의 HP를 기절해 버렸더라도 모두 회복한다.", }, "MoneyRewardModifierType": { - description: "{{moneyMultiplier}} 양의 돈을 획득 (₽{{moneyAmount}})", + description: "{{moneyMultiplier}} 양의 돈을 획득한다 (₽{{moneyAmount}}).", extra: { "small": "적은", "moderate": "적당한", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "포켓몬이 받는 경험치가 늘어나는 부적. {{boostPercent}}% 증가", + description: "포켓몬이 받는 경험치가 {{boostPercent}}% 증가한다.", }, "PokemonExpBoosterModifierType": { - description: "지니게 한 포켓몬은 받을 수 있는 경험치가 {{boostPercent}}% 증가", + description: "지니게 한 포켓몬은 받는 경험치가 {{boostPercent}}% 증가한다.", }, "PokemonFriendshipBoosterModifierType": { - description: "배틀 승리로 얻는 친밀도가 50% 증가", + description: "배틀 승리로 얻는 친밀도가 50% 증가한다.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "기술의 명중률이 {{accuracyAmount}} 증가 (최대 100)", + description: "기술의 명중률이 {{accuracyAmount}} 증가한다 (최대 100).", }, "PokemonMultiHitModifierType": { description: "지닌 개수(최대 3개)마다 추가 공격을 하는 대신, 공격력이 60%(1개)/75%(2개)/82.5%(3개)만큼 감소합니다.", }, "TmModifierType": { name: "No.{{moveId}} {{moveName}}", - description: "포켓몬에게 {{moveName}}[[를]] 가르침", + description: "포켓몬에게 {{moveName}}[[를]] 가르침.", }, "TmModifierTypeWithInfo": { name: "No.{{moveId}} {{moveName}}", - description: "포켓몬에게 {{moveName}}를(을) 가르침\n(C 또는 Shift를 꾹 눌러 정보 확인)", + description: "포켓몬에게 {{moveName}}를(을) 가르침\n(C 또는 Shift를 꾹 눌러 정보 확인).", }, "EvolutionItemModifierType": { - description: "어느 특정 포켓몬을 진화", + description: "어느 특정 포켓몬을 진화시킨다.", }, "FormChangeItemModifierType": { - description: "어느 특정 포켓몬을 폼 체인지", + description: "어느 특정 포켓몬을 폼 체인지시킨다.", }, "FusePokemonModifierType": { - description: "두 포켓몬을 결합 (특성 변환, 종족값과 타입 분배, 기술폭 공유)", + description: "두 포켓몬을 결합시킨다 (특성 변환, 종족값과 타입 분배, 기술폭 공유).", }, "TerastallizeModifierType": { name: "테라피스 {{teraType}}", - description: "지니게 하면 10번의 배틀 동안 {{teraType}} 테라스탈타입으로 테라스탈", + description: "지니게 하면 10번의 배틀 동안 {{teraType}} 테라스탈타입으로 테라스탈한다.", }, "ContactHeldItemTransferChanceModifierType": { - description: "공격했을 때, {{chancePercent}}%의 확률로 상대의 도구를 도둑질", + description: "공격했을 때, {{chancePercent}}%의 확률로 상대의 도구를 도둑질한다.", }, "TurnHeldItemTransferModifierType": { - description: "매 턴, 지닌 포켓몬은 상대로부터 도구를 하나 획득", + description: "매 턴, 지닌 포켓몬은 상대로부터 도구를 하나 획득한다.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "공격했을 때 {{statusEffect}} 상태로 만들 확률 {{chancePercent}}% 추가", + description: "공격했을 때 {{statusEffect}} 상태로 만들 확률이 {{chancePercent}}% 추가된다.", }, "EnemyEndureChanceModifierType": { - description: "받은 공격을 버텨낼 확률 {{chancePercent}}% 추가", + description: "받은 공격을 버텨낼 확률이 {{chancePercent}}% 추가된다.", }, "RARE_CANDY": { name: "이상한사탕" }, "RARER_CANDY": { name: "더이상한사탕" }, - "MEGA_BRACELET": { name: "메가링", description: "메가스톤을 사용 가능" }, - "DYNAMAX_BAND": { name: "다이맥스 밴드", description: "다이버섯을 사용 가능" }, - "TERA_ORB": { name: "테라스탈오브", description: "테라피스를 사용 가능" }, + "MEGA_BRACELET": { name: "메가링", description: "메가스톤을 사용할 수 있게 된다." }, + "DYNAMAX_BAND": { name: "다이맥스 밴드", description: "다이버섯을 사용할 수 있게 된다." }, + "TERA_ORB": { name: "테라스탈오브", description: "테라피스를 사용할 수 있게 된다." }, - "MAP": { name: "지도", description: "갈림길에서 목적지 선택 가능" }, + "MAP": { name: "지도", description: "갈림길에서 목적지를 선택할 수 있다." }, "POTION": { name: "상처약" }, "SUPER_POTION": { name: "좋은상처약" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "성스러운분말" }, - "REVIVER_SEED": { name: "부활의씨앗", description: "포켓몬이 쓰러지려 할 때 HP를 절반 회복" }, + "REVIVER_SEED": { name: "부활의씨앗", description: "포켓몬이 쓰러지려 할 때 HP를 절반 회복한다." }, "ETHER": { name: "PP에이드" }, "MAX_ETHER": { name: "PP회복" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "실버코롱" }, "MAX_LURE": { name: "골드코롱" }, - "MEMORY_MUSHROOM": { name: "기억버섯", description: "포켓몬의 잊어버린 기술을 떠올림" }, + "MEMORY_MUSHROOM": { name: "기억버섯", description: "포켓몬이 잊어버린 기술을 떠올린다." }, - "EXP_SHARE": { name: "학습장치", description: "배틀에 참여하지 않아도 20%의 경험치를 받을 수 있는 장치" }, - "EXP_BALANCE": { name: "균형학습장치", description: "레벨이 낮은 포켓몬이 받는 경험치를 가중" }, + "EXP_SHARE": { name: "학습장치", description: "배틀에 참여하지 않아도 20%의 경험치를 받을 수 있게 된다." }, + "EXP_BALANCE": { name: "균형학습장치", description: "레벨이 낮은 포켓몬이 받는 경험치를 가중시킨다." }, - "OVAL_CHARM": { name: "둥근부적", description: "여러 마리의 포켓몬이 배틀에 참여할 경우, 전체 경험치의 10%씩을 추가로 획득" }, + "OVAL_CHARM": { name: "둥근부적", description: "여러 마리의 포켓몬이 배틀에 참여할 경우, 전체 경험치의 10%씩을 추가로 획득한다." }, "EXP_CHARM": { name: "경험부적" }, "SUPER_EXP_CHARM": { name: "좋은경험부적" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "평온의방울" }, - "SOUL_DEW": { name: "마음의물방울", description: "지닌 포켓몬의 성격의 효과가 10% 증가 (합연산)" }, + "SOUL_DEW": { name: "마음의물방울", description: "지닌 포켓몬의 성격의 효과가 10% 증가한다 (합연산)." }, "NUGGET": { name: "금구슬" }, "BIG_NUGGET": { name: "큰금구슬" }, "RELIC_GOLD": { name: "고대의금화" }, - "AMULET_COIN": { name: "부적금화", description: "받는 돈이 20% 증가" }, - "GOLDEN_PUNCH": { name: "골든펀치", description: "주는 데미지의 50%만큼 돈을 획득" }, - "COIN_CASE": { name: "동전케이스", description: "매 열 번째 배틀마다, 가진 돈의 10%를 이자로 획득" }, + "AMULET_COIN": { name: "부적금화", description: "받는 돈이 20% 증가한다." }, + "GOLDEN_PUNCH": { name: "골든펀치", description: "주는 데미지의 50%만큼 돈을 획득한다." }, + "COIN_CASE": { name: "동전케이스", description: "매 열 번째 배틀마다, 가진 돈의 10%를 이자로 획득한다." }, - "LOCK_CAPSULE": { name: "록캡슐", description: "받을 아이템을 갱신할 때 희귀도를 고정 가능" }, + "LOCK_CAPSULE": { name: "록캡슐", description: "받을 아이템을 갱신할 때 희귀도를 고정시킬 수 있게 된다." }, "GRIP_CLAW": { name: "끈기갈고리손톱" }, "WIDE_LENS": { name: "광각렌즈" }, "MULTI_LENS": { name: "멀티렌즈" }, - "HEALING_CHARM": { name: "치유의부적", description: "HP를 회복하는 기술을 썼을 때 효율이 10% 증가 (부활 제외)" }, - "CANDY_JAR": { name: "사탕단지", description: "이상한사탕 종류의 아이템이 올려주는 레벨 1 증가" }, + "HEALING_CHARM": { name: "치유의부적", description: "HP를 회복하는 기술을 썼을 때 효율이 10% 증가한다 (부활 제외)." }, + "CANDY_JAR": { name: "사탕단지", description: "이상한사탕 종류의 아이템이 올려주는 레벨이 1 증가한다." }, - "BERRY_POUCH": { name: "열매주머니", description: "사용한 나무열매가 소모되지 않을 확률 33% 추가" }, + "BERRY_POUCH": { name: "열매주머니", description: "사용한 나무열매가 소모되지 않을 확률이 30% 추가된다." }, - "FOCUS_BAND": { name: "기합의머리띠", description: "기절할 듯한 데미지를 받아도 HP를 1 남겨서 견딜 확률 10% 추가" }, + "FOCUS_BAND": { name: "기합의머리띠", description: "기절할 듯한 데미지를 받아도 HP를 1 남겨서 견딜 확률이 10% 추가된다." }, - "QUICK_CLAW": { name: "선제공격손톱", description: "상대보다 먼저 행동할 수 있게 될 확률 10% 추가 (우선도 처리 이후)" }, + "QUICK_CLAW": { name: "선제공격손톱", description: "상대보다 먼저 행동할 수 있게 될 확률이 10% 추가된다 (우선도 처리 이후)." }, - "KINGS_ROCK": { name: "왕의징표석", description: "공격해서 데미지를 줄 때 상대를 풀죽일 확률 10% 추가" }, + "KINGS_ROCK": { name: "왕의징표석", description: "공격해서 데미지를 줄 때 상대를 풀죽일 확률이 10% 추가된다." }, - "LEFTOVERS": { name: "먹다남은음식", description: "포켓몬의 HP가 매 턴 최대 체력의 1/16씩 회복" }, - "SHELL_BELL": { name: "조개껍질방울", description: "포켓몬이 준 데미지의 1/8씩 회복" }, + "LEFTOVERS": { name: "먹다남은음식", description: "포켓몬의 HP가 매 턴 최대 체력의 1/16씩 회복된다." }, + "SHELL_BELL": { name: "조개껍질방울", description: "포켓몬이 준 데미지의 1/8씩을 회복한다." }, "TOXIC_ORB": { name: "맹독구슬", description: "이 도구를 지닌 포켓몬은 턴이 끝나는 시점에 상태이상에 걸리지 않았다면 맹독 상태가 된다." }, "FLAME_ORB": { name: "화염구슬", description: "이 도구를 지닌 포켓몬은 턴이 끝나는 시점에 상태이상에 걸리지 않았다면 화상 상태가 된다." }, "BATON": { name: "바톤", description: "포켓몬을 교체할 때 효과를 넘겨줄 수 있으며, 함정의 영향을 받지 않게 함" }, - "SHINY_CHARM": { name: "빛나는부적", description: "야생 포켓몬이 색이 다른 포켓몬으로 등장할 확률을 급격히 증가" }, - "ABILITY_CHARM": { name: "특성부적", description: "야생 포켓몬이 숨겨진 특성을 가지고 등장할 확률을 급격히 증가" }, + "SHINY_CHARM": { name: "빛나는부적", description: "야생 포켓몬이 색이 다른 포켓몬으로 등장할 확률을 급격히 높인다." }, + "ABILITY_CHARM": { name: "특성부적", description: "야생 포켓몬이 숨겨진 특성을 가지고 등장할 확률을 급격히 높인다." }, - "IV_SCANNER": { name: "개체값탐지기", description: "야생 포켓몬의 개체값을 확인 가능하다. 높은 값이 먼저 표시되며 확인할 수 있는 개체값을 두 종류씩 추가" }, + "IV_SCANNER": { name: "개체값탐지기", description: "야생 포켓몬의 개체값을 확인 가능하다. 높은 값부터, 확인할 수 있는 개체값이 두 종류씩 추가된다." }, "DNA_SPLICERS": { name: "유전자쐐기" }, "MINI_BLACK_HOLE": { name: "미니 블랙홀" }, - "GOLDEN_POKEBALL": { name: "황금몬스터볼", description: "전투 후 획득하는 아이템의 선택지를 하나 더 추가" }, + "GOLDEN_POKEBALL": { name: "황금몬스터볼", description: "전투 후 획득하는 아이템의 선택지가 하나 더 늘어난다." }, - "ENEMY_DAMAGE_BOOSTER": { name: "데미지 토큰", description: "주는 데미지를 5% 증가" }, - "ENEMY_DAMAGE_REDUCTION": { name: "보호 토큰", description: "받는 데미지를 2.5% 감소" }, - "ENEMY_HEAL": { name: "회복 토큰", description: "매 턴 최대 체력의 2%를 회복" }, + "ENEMY_DAMAGE_BOOSTER": { name: "데미지 토큰", description: "주는 데미지를 5% 증가시킨다." }, + "ENEMY_DAMAGE_REDUCTION": { name: "보호 토큰", description: "받는 데미지를 2.5% 감소시킨다." }, + "ENEMY_HEAL": { name: "회복 토큰", description: "매 턴 최대 체력의 2%를 회복한다." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "독 토큰" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "마비 토큰" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "화상 토큰" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "만병통치 토큰", description: "매 턴 상태이상에서 회복될 확률 2.5% 추가" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "만병통치 토큰", description: "매 턴 상태이상에서 회복될 확률이 2.5% 추가된다." }, "ENEMY_ENDURE_CHANCE": { name: "버티기 토큰" }, - "ENEMY_FUSED_CHANCE": { name: "합체 토큰", description: "야생 포켓몬이 합체할 확률 1% 추가" }, + "ENEMY_FUSED_CHANCE": { name: "합체 토큰", description: "야생 포켓몬이 합체되어 등장할 확률이 1% 추가된다." }, }, TempBattleStatBoosterItem: { "x_attack": "플러스파워", @@ -425,5 +425,6 @@ export const modifierType: ModifierTypeTranslationEntries = { "DRAGON_MEMORY": "드래곤메모리", "DARK_MEMORY": "다크메모리", "FAIRY_MEMORY": "페어리메모리", + "BLANK_MEMORY": "빈메모리", }, } as const; diff --git a/src/locales/ko/move.ts b/src/locales/ko/move.ts index 60a5a5eaafc..700a623c3cc 100644 --- a/src/locales/ko/move.ts +++ b/src/locales/ko/move.ts @@ -3393,7 +3393,7 @@ export const move: MoveTranslationEntries = { effect: "무수히 많은 불덩이로 공격한다. 화상 상태로 만들 때가 있다. 상대가 상태 이상인 경우 위력이 2배가 된다." }, ceaselessEdge: { - name: "비검천충파", + name: "비검천중파", effect: "조개껍질 검으로 공격한다. 조개껍질 파편은 압정이 되어 상대의 발밑에 흩어진다." }, bleakwindStorm: { diff --git a/src/locales/ko/pokemon-info-container.ts b/src/locales/ko/pokemon-info-container.ts index 5882561bdd8..c1477ffc08b 100644 --- a/src/locales/ko/pokemon-info-container.ts +++ b/src/locales/ko/pokemon-info-container.ts @@ -7,5 +7,6 @@ export const pokemonInfoContainer: SimpleTranslationEntries = { "nature": "성격:", "epic": "에픽", "rare": "레어", - "common": "커먼" + "common": "커먼", + "form": "폼:" } as const; diff --git a/src/locales/ko/save-slot-select-ui-handler.ts b/src/locales/ko/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..213da34bda5 --- /dev/null +++ b/src/locales/ko/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "선택한 슬롯에 데이터를 덮어쓰시겠습니까?", + "loading": "로딩 중...", + "wave": "웨이브", + "lv": "Lv", + "empty": "빈 슬롯", +} as const; diff --git a/src/locales/ko/starter-select-ui-handler.ts b/src/locales/ko/starter-select-ui-handler.ts index 9a27824e541..587baa3abc4 100644 --- a/src/locales/ko/starter-select-ui-handler.ts +++ b/src/locales/ko/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "교체될 기술을 선택해주세요. 대상:", "unlockPassive": "패시브 해금", "reduceCost": "코스트 줄이기", - "cycleShiny": "R: 특별한 색", - "cycleForm": "F: 폼 체인지", - "cycleGender": "G: 암수 전환", - "cycleAbility": "E: 특성 전환", - "cycleNature": "N: 성격 전환", - "cycleVariant": "V: 색상 전환", + "cycleShiny": ": 특별한 색", + "cycleForm": ": 폼", + "cycleGender": ": 암수", + "cycleAbility": ": 특성", + "cycleNature": ": 성격", + "cycleVariant": ": 색상", "enablePassive": "패시브 활성화", "disablePassive": "패시브 비활성화", "locked": "잠김", diff --git a/src/locales/ko/trainers.ts b/src/locales/ko/trainers.ts index 0bc99640333..2a61627c5a7 100644 --- a/src/locales/ko/trainers.ts +++ b/src/locales/ko/trainers.ts @@ -13,6 +13,12 @@ export const titles: SimpleTranslationEntries = { "rival": "라이벌", "professor": "박사", "frontier_brain": "프런티어 브레인", + "rocket_boss": "로켓단 보스", + "magma_boss": "마그마단 보스", + "aqua_boss": "아쿠아단 보스", + "galactic_boss": "갤럭시단 보스", + "plasma_boss": "플라스마단 보스", + "flare_boss": "플레어단 보스", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -48,7 +54,7 @@ export const trainerClasses: SimpleTranslationEntries = { "depot_agent": "역무원", "doctor": "의사", "doctor_female": "간호사", // doctor_f.png 파일이 간호사 - "firebreather": "Firebreather", + "firebreather": "불놀이꾼", "fisherman": "낚시꾼", "fisherman_female": "낚시꾼", "gentleman": "신사", @@ -118,7 +124,19 @@ export const trainerClasses: SimpleTranslationEntries = { "worker": "작업원", "worker_female": "작업원", "workers": "작업원", - "youngster": "반바지 꼬마" + "youngster": "반바지 꼬마", + "rocket_grunt": "로켓단 조무래기", + "rocket_grunt_female": "로켓단 조무래기", + "magma_grunt": "마그마단 조무래기", + "magma_grunt_female": "마그마단 조무래기", + "aqua_grunt": "아쿠아단 조무래기", + "aqua_grunt_female": "아쿠아단 조무래기", + "galactic_grunt": "갤럭시단 조무래기", + "galactic_grunt_female": "갤럭시단 조무래기", + "plasma_grunt": "플라스마단 조무래기", + "plasma_grunt_female": "플라스마단 조무래기", + "flare_grunt": "플레어단 조무래기", + "flare_grunt_female": "플레어단 조무래기", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -247,6 +265,11 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "단델", "rival": "핀", "rival_female": "아이비", + "maxie": "마적", + "archie": "아강", + "cyrus": "태홍", + "ghetsis": "게치스", + "lysandre": "플라드리", // Double Names "blue_red_double": "그린 & 레드", diff --git a/src/locales/ko/tutorial.ts b/src/locales/ko/tutorial.ts index 70702aa1698..1e0f8af3ce1 100644 --- a/src/locales/ko/tutorial.ts +++ b/src/locales/ko/tutorial.ts @@ -23,7 +23,8 @@ export const tutorial: SimpleTranslationEntries = { statChange: `포켓몬은 교체하지 않으면 다음 전투에서도 능력치 변화가 유지됩니다. $대신 트레이너 배틀이나 새로운 바이옴 입장 직전에 자동으로 들여보내지게 됩니다. $C 또는 Shift를 꾹 눌러 현재 포켓몬의 능력치 변화를 볼 수도 있습니다. - $V를 눌러 상대방이 사용했던 기술도 확인하여 전투를 유리하게 이끌어봅시다.`, + $V를 눌러 상대방이 사용했던 기술도 확인할 수 있습니다. + $단, 이번 배틀에서 상대 포켓몬이 이미 사용한 기술만 나타납니다.`, selectItem: `전투가 끝날때마다 무작위 아이템 3개 중 하나를 선택하여 얻습니다. $종류는 소모품, 포켓몬의 지닌 도구, 영구적 패시브 아이템에 이르기까지 다양합니다. diff --git a/src/locales/pt_BR/achv.ts b/src/locales/pt_BR/achv.ts index 5aaccc465ac..a15d59df6c5 100644 --- a/src/locales/pt_BR/achv.ts +++ b/src/locales/pt_BR/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Conquistas", }, @@ -168,4 +169,367 @@ export const achv: AchievementTranslationEntries = { name: "Invencível", description: "Vença o jogo no modo clássico", }, + + "MONO_GEN_ONE": { + + name: "O Início de Tudo", + description: "Complete o desafio da geração um.", + }, + "MONO_GEN_TWO": { + name: "Geração 1.5", + description: "Complete o desafio da geração dois.", + }, + "MONO_GEN_THREE": { + name: "Será que tem muita água?", + description: "Complete o desafio da geração três.", + }, + "MONO_GEN_FOUR": { + name: "Essa foi a mais difícil?", + description: "Complete o desafio da geração quatro.", + }, + "MONO_GEN_FIVE": { + name: "Nada original", + description: "Complete o desafio da geração cinco.", + }, + "MONO_GEN_SIX": { + name: "Esse croissant tem recheio?", + description: "Complete o desafio da geração seis.", + }, + "MONO_GEN_SEVEN": { + name: "Z-Move ou Se vira nos 30?", + description: "Complete o desafio da geração sete.", + }, + "MONO_GEN_EIGHT": { + name: "Finalmente ele ganhou!", + description: "Complete o desafio da geração oito.", + }, + "MONO_GEN_NINE": { + name: "Isso aqui tá muito fácil!", + description: "Complete o desafio da geração nove.", + }, + + "MonoType": { + description: "Complete o desafio de monotipo {{type}}.", + }, + "MONO_NORMAL": { + name: "Tenho medo de fantasma", + }, + "MONO_FIGHTING": { + name: "Briga de Rua", + }, + "MONO_FLYING": { + name: "Rinha de Pidgeys", + }, + "MONO_POISON": { + name: "Menina Veneno", + }, + "MONO_GROUND": { + name: "Deixou eles comendo poeira!", + }, + "MONO_ROCK": { + name: "Duro como Pedra", + }, + "MONO_BUG": { + name: "Vida de Inseto", + }, + "MONO_GHOST": { + name: "Posso dormir com você hoje, mamãe?", + }, + "MONO_STEEL": { + name: "Levantando Ferro", + }, + "MONO_FIRE": { + name: "Tá Pegando Fogo, Bicho!", + }, + "MONO_WATER": { + name: "Água mole em pedra dura...", + }, + "MONO_GRASS": { + name: "Jardim Botânico", + }, + "MONO_ELECTRIC": { + name: "Choque de Realidade", + }, + "MONO_PSYCHIC": { + name: "Preciso de Terapia", + }, + "MONO_ICE": { + name: "Era do Gelo", + }, + "MONO_DRAGON": { + name: "Caverna do Dragão", + }, + "MONO_DARK": { + name: "É só uma fase", + }, + "MONO_FAIRY": { + name: "Clube das Winx", + }, +} as const; + +// Achievement translations for the when the player character is female +export const PGFachv: AchievementTranslationEntries = { + "Achievements": { + name: "Conquistas", + }, + "Locked": { + name: "Não conquistado", + }, + + "MoneyAchv": { + description: "Acumule um total de ₽{{moneyAmount}}", + }, + "10K_MONEY": { + name: "Chuva de Dinheiro", + }, + "100K_MONEY": { + name: "Tô Rica!", + }, + "1M_MONEY": { + name: "Quem Quer Ser Um Milionário?", + }, + "10M_MONEY": { + name: "Tio Patinhas", + }, + + "DamageAchv": { + description: "Inflija {{damageAmount}} de dano em um único golpe", + }, + "250_DMG": { + name: "Essa Doeu!", + }, + "1000_DMG": { + name: "Essa Doeu Mais!", + }, + "2500_DMG": { + name: "Essa Doeu Muito!", + }, + "10000_DMG": { + name: "Essa Doeu Pra Caramba!", + }, + + "HealAchv": { + description: "Cure {{healAmount}} {{HP}} de uma vez só com um movimento, habilidade ou item segurado", + }, + "250_HEAL": { + name: "Residente", + }, + "1000_HEAL": { + name: "Enfermeira", + }, + "2500_HEAL": { + name: "Médica", + }, + "10000_HEAL": { + name: "Médica de Plantão", + }, + + "LevelAchv": { + description: "Aumente o nível de um Pokémon para o Nv{{level}}", + }, + "LV_100": { + name: "Calma Que Tem Mais!", + }, + "LV_250": { + name: "Treinadora de Elite", + }, + "LV_1000": { + name: "Ao Infinito e Além!", + }, + + "RibbonAchv": { + description: "Acumule um total de {{ribbonAmount}} Fitas", + }, + "10_RIBBONS": { + name: "Fita de Bronze", + }, + "25_RIBBONS": { + name: "Fita de Prata", + }, + "50_RIBBONS": { + name: "Fita de Ouro", + }, + "75_RIBBONS": { + name: "Fita de Platina", + }, + "100_RIBBONS": { + name: "Fita de Diamante", + }, + + "TRANSFER_MAX_BATTLE_STAT": { + name: "Trabalho em Equipe", + description: "Use Baton Pass com pelo menos um atributo aumentado ao máximo", + }, + "MAX_FRIENDSHIP": { + name: "Melhores Amigos", + description: "Alcance a amizade máxima com um Pokémon", + }, + "MEGA_EVOLVE": { + name: "Megamorfose", + description: "Megaevolua um Pokémon", + }, + "GIGANTAMAX": { + name: "Ficou Gigante!", + description: "Gigantamax um Pokémon", + }, + "TERASTALLIZE": { + name: "Terastalização", + description: "Terastalize um Pokémon", + }, + "STELLAR_TERASTALLIZE": { + name: "Estrela Cadente", + description: "Terastalize um Pokémon para o tipo Estelar", + }, + "SPLICE": { + name: "Fusão!", + description: "Funda dois Pokémon com um Splicer de DNA", + }, + "MINI_BLACK_HOLE": { + name: "Buraco Sem Fundo", + description: "Adquira um Mini Buraco Negro", + }, + "CATCH_MYTHICAL": { + name: "Mítico", + description: "Capture um Pokémon Mítico", + }, + "CATCH_SUB_LEGENDARY": { + name: "Quase Lendário", + description: "Capture um Pokémon Semi-Lendário", + }, + "CATCH_LEGENDARY": { + name: "Lendário", + description: "Capture um Pokémon Lendário", + }, + "SEE_SHINY": { + name: "Ué, Tá Brilhando?", + description: "Encontre um Pokémon Shiny selvagem", + }, + "SHINY_PARTY": { + name: "Tá Todo Mundo Brilhando!", + description: "Tenha uma equipe formada por 6 Pokémon Shiny", + }, + "HATCH_MYTHICAL": { + name: "Ovo Mítico", + description: "Choque um Pokémon Mítico", + }, + "HATCH_SUB_LEGENDARY": { + name: "Ovo Semi-Lendário", + description: "Choque um Pokémon Semi-Lendário", + }, + "HATCH_LEGENDARY": { + name: "Ovo Lendário", + description: "Choque um Pokémon Lendário", + }, + "HATCH_SHINY": { + name: "Ovo Shiny", + description: "Choque um Pokémon Shiny", + }, + "HIDDEN_ABILITY": { + name: "Potencial Oculto", + description: "Capture um Pokémon com uma Habilidade Oculta", + }, + "PERFECT_IVS": { + name: "Perfeição Certificada", + description: "Obtenha IVs perfeitos em um Pokémon", + }, + "CLASSIC_VICTORY": { + name: "Invencível", + description: "Vença o jogo no modo clássico", + }, + + "MONO_GEN_ONE": { + + name: "O Início de Tudo", + description: "Complete o desafio da geração um.", + }, + "MONO_GEN_TWO": { + name: "Geração 1.5", + description: "Complete o desafio da geração dois.", + }, + "MONO_GEN_THREE": { + name: "Será que tem muita água?", + description: "Complete o desafio da geração três.", + }, + "MONO_GEN_FOUR": { + name: "Essa foi a mais difícil?", + description: "Complete o desafio da geração quatro.", + }, + "MONO_GEN_FIVE": { + name: "Nada original", + description: "Complete o desafio da geração cinco.", + }, + "MONO_GEN_SIX": { + name: "Esse croissant tem recheio?", + description: "Complete o desafio da geração seis.", + }, + "MONO_GEN_SEVEN": { + name: "Z-Move ou Se vira nos 30?", + description: "Complete o desafio da geração sete.", + }, + "MONO_GEN_EIGHT": { + name: "Finalmente ele ganhou!", + description: "Complete o desafio da geração oito.", + }, + "MONO_GEN_NINE": { + name: "Isso aqui tá muito fácil!", + description: "Complete o desafio da geração nove.", + }, + + "MonoType": { + description: "Complete o desafio de monotipo {{type}}.", + }, + "MONO_NORMAL": { + name: "Tenho medo de fantasma", + }, + "MONO_FIGHTING": { + name: "Briga de Rua", + }, + "MONO_FLYING": { + name: "Rinha de Pidgeys", + }, + "MONO_POISON": { + name: "Menina Veneno", + }, + "MONO_GROUND": { + name: "Deixou eles comendo poeira!", + }, + "MONO_ROCK": { + name: "Duro como Pedra", + }, + "MONO_BUG": { + name: "Vida de Inseto", + }, + "MONO_GHOST": { + name: "Posso dormir com você hoje, mamãe?", + }, + "MONO_STEEL": { + name: "Levantando Ferro", + }, + "MONO_FIRE": { + name: "Tá Pegando Fogo, Bicho!", + }, + "MONO_WATER": { + name: "Água mole em pedra dura...", + }, + "MONO_GRASS": { + name: "Jardim Botânico", + }, + "MONO_ELECTRIC": { + name: "Choque de Realidade", + }, + "MONO_PSYCHIC": { + name: "Preciso de Terapia", + }, + "MONO_ICE": { + name: "Era do Gelo", + }, + "MONO_DRAGON": { + name: "Caverna do Dragão", + }, + "MONO_DARK": { + name: "É só uma fase", + }, + "MONO_FAIRY": { + name: "Clube das Winx", + }, } as const; diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts index 47a74fe17b1..ebe0a090473 100644 --- a/src/locales/pt_BR/battle.ts +++ b/src/locales/pt_BR/battle.ts @@ -5,7 +5,7 @@ export const battle: SimpleTranslationEntries = { "trainerAppeared": "{{trainerName}}\nquer batalhar!", "trainerAppearedDouble": "{{trainerName}}\nquerem batalhar!", "singleWildAppeared": "Um {{pokemonName}} selvagem apareceu!", - "trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!", + "trainerSendOut": "{{trainerName}} escolheu\n{{pokemonName}}!", "multiWildAppeared": "Um {{pokemonName1}} e um {{pokemonName2}} selvagens\napareceram!", "playerComeBack": "{{pokemonName}}, retorne!", "trainerComeBack": "{{trainerName}} retirou {{pokemonName}} da batalha!", @@ -13,9 +13,9 @@ export const battle: SimpleTranslationEntries = { "trainerGo": "{{trainerName}} escolheu {{pokemonName}}!", "switchQuestion": "Quer trocar\nde {{pokemonName}}?", "trainerDefeated": "Você derrotou\n{{trainerName}}!", - "moneyWon": "You got\n₽{{moneyAmount}} for winning!", + "moneyWon": "Você ganhou\n₽{{moneyAmount}} por ganhar!", "pokemonCaught": "{{pokemonName}} foi capturado!", - "partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?", + "partyFull": "Sua equipe está cheia.\nSolte um Pokémon para ter espaço para {{pokemonName}}?", "pokemon": "Pokémon", "sendOutPokemon": "{{pokemonName}}, eu escolho você!!", "hitResultCriticalHit": "Um golpe crítico!", diff --git a/src/locales/pt_BR/challenges.ts b/src/locales/pt_BR/challenges.ts new file mode 100644 index 00000000000..9b7bfe1973c --- /dev/null +++ b/src/locales/pt_BR/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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.", +} as const; diff --git a/src/locales/pt_BR/config.ts b/src/locales/pt_BR/config.ts index 3baca7df382..7fa3c483926 100644 --- a/src/locales/pt_BR/config.ts +++ b/src/locales/pt_BR/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -25,27 +27,30 @@ import { menuUiHandler } from "./menu-ui-handler"; import { modifierType } from "./modifier-type"; import { move } from "./move"; import { nature } from "./nature"; +import { partyUiHandler } from "./party-ui-handler"; import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; import { tutorial } from "./tutorial"; import { voucher } from "./voucher"; import { weather } from "./weather"; -import { partyUiHandler } from "./party-ui-handler"; export const ptBrConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const ptBrConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -63,10 +69,12 @@ export const ptBrConfig = { modifierType: modifierType, move: move, nature: nature, + partyUiHandler: partyUiHandler, pokeball: pokeball, pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, @@ -75,5 +83,4 @@ export const ptBrConfig = { tutorial: tutorial, voucher: voucher, weather: weather, - partyUiHandler: partyUiHandler }; diff --git a/src/locales/pt_BR/game-mode.ts b/src/locales/pt_BR/game-mode.ts new file mode 100644 index 00000000000..5f0e930703b --- /dev/null +++ b/src/locales/pt_BR/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Clássico", + "endless": "Infinito", + "endlessSpliced": "Infinito (Fusões)", + "dailyRun": "Desafio Diário", + "unknown": "Desconhecido", + "challenge": "Desafio", +} as const; diff --git a/src/locales/pt_BR/growth.ts b/src/locales/pt_BR/growth.ts index 50762e5ad94..945520c91d7 100644 --- a/src/locales/pt_BR/growth.ts +++ b/src/locales/pt_BR/growth.ts @@ -1,10 +1,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const growth: SimpleTranslationEntries = { - "Erratic": "Instável", + "Erratic": "Muito Rápido", "Fast": "Rápido", "Medium_Fast": "Meio Rápido", "Medium_Slow": "Meio Lento", "Slow": "Lento", - "Fluctuating": "Flutuante" + "Fluctuating": "Muito Lento", } as const; diff --git a/src/locales/pt_BR/menu.ts b/src/locales/pt_BR/menu.ts index 000ffb1e397..f4fc8cc3a72 100644 --- a/src/locales/pt_BR/menu.ts +++ b/src/locales/pt_BR/menu.ts @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classificação Semanal", "noRankings": "Sem Classificação", "loading": "Carregando…", + "loadingAsset": "Carregando recurso: {{assetName}}", "playersOnline": "Jogadores Ativos", - "empty": "Vazio", "yes": "Sim", "no": "Não", "disclaimer": "AVISO", diff --git a/src/locales/pt_BR/modifier-type.ts b/src/locales/pt_BR/modifier-type.ts index 373938b9266..b0df31d5f65 100644 --- a/src/locales/pt_BR/modifier-type.ts +++ b/src/locales/pt_BR/modifier-type.ts @@ -4,11 +4,11 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{modifierCount}}x {{pokeballName}}", - description: "Ganhe x{{modifierCount}} {{pokeballName}} (Mochila: {{pokeballAmount}}) \nChance de captura: {{catchRate}}", + description: "Ganhe x{{modifierCount}} {{pokeballName}} (Mochila: {{pokeballAmount}}) \nChance de captura: {{catchRate}}.", }, "AddVoucherModifierType": { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "Ganhe x{{modifierCount}} {{voucherTypeName}}", + description: "Ganhe x{{modifierCount}} {{voucherTypeName}}.", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "Restaura {{restorePoints}} PS ou {{restorePercent}}% PS de um Pokémon, o que for maior", + description: "Restaura {{restorePoints}} PS ou {{restorePercent}}% PS de um Pokémon, o que for maior.", extra: { - "fully": "Restaura totalmente os PS de um Pokémon", - "fullyWithStatus": "Restaura totalmente os PS de um Pokémon e cura qualquer mudança de estado", + "fully": "Restaura totalmente os PS de um Pokémon.", + "fullyWithStatus": "Restaura totalmente os PS de um Pokémon e cura qualquer mudança de estado.", } }, "PokemonReviveModifierType": { - description: "Reanima um Pokémon e restaura {{restorePercent}}% PS", + description: "Reanima um Pokémon e restaura {{restorePercent}}% PS.", }, "PokemonStatusHealModifierType": { - description: "Cura uma mudança de estado de um Pokémon", + description: "Cura uma mudança de estado de um Pokémon.", }, "PokemonPpRestoreModifierType": { - description: "Restaura {{restorePoints}} PP para um movimento de um Pokémon", + description: "Restaura {{restorePoints}} PP para um movimento de um Pokémon.", extra: { - "fully": "Restaura todos os PP para um movimento de um Pokémon", + "fully": "Restaura todos os PP para um movimento de um Pokémon.", } }, "PokemonAllMovePpRestoreModifierType": { - description: "Restaura {{restorePoints}} PP para todos os movimentos de um Pokémon", + description: "Restaura {{restorePoints}} PP para todos os movimentos de um Pokémon.", extra: { - "fully": "Restaura todos os PP para todos os movimentos de um Pokémon", + "fully": "Restaura todos os PP para todos os movimentos de um Pokémon.", } }, "PokemonPpUpModifierType": { - description: "Aumenta permanentemente os PP para o movimento de um Pokémon em {{upPoints}} para cada 5 PP máximos (máximo 3)", + description: "Aumenta permanentemente os PP para o movimento de um Pokémon em {{upPoints}} para cada 5 PP máximos (máximo 3).", }, "PokemonNatureChangeModifierType": { name: "Hortelã {{natureName}}", - description: "Muda a natureza do Pokémon para {{natureName}} e a desbloqueia permanentemente", + description: "Muda a natureza do Pokémon para {{natureName}} e a desbloqueia permanentemente.", }, "DoubleBattleChanceBoosterModifierType": { - description: "Dobra as chances de encontrar uma batalha em dupla por {{battleCount}} batalhas", + description: "Dobra as chances de encontrar uma batalha em dupla por {{battleCount}} batalhas.", }, "TempBattleStatBoosterModifierType": { - description: "Aumenta o atributo de {{tempBattleStatName}} para todos os membros da equipe por 5 batalhas", + description: "Aumenta o atributo de {{tempBattleStatName}} para todos os membros da equipe por 5 batalhas.", }, "AttackTypeBoosterModifierType": { - description: "Aumenta o poder dos ataques do tipo {{moveType}} de um Pokémon em 20%", + description: "Aumenta o poder dos ataques do tipo {{moveType}} de um Pokémon em 20%.", }, "PokemonLevelIncrementModifierType": { - description: "Aumenta em 1 o nível de um Pokémon", + description: "Aumenta em 1 o nível de um Pokémon.", }, "AllPokemonLevelIncrementModifierType": { - description: "Aumenta em 1 os níveis de todos os Pokémon", + description: "Aumenta em 1 os níveis de todos os Pokémon.", }, "PokemonBaseStatBoosterModifierType": { - description: "Aumenta o atributo base de {{statName}} em 10%. Quanto maior os IVs, maior o limite de aumento", + description: "Aumenta o atributo base de {{statName}} em 10%. Quanto maior os IVs, maior o limite de aumento.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Restaura totalmente os PS de todos os Pokémon", + description: "Restaura totalmente os PS de todos os Pokémon.", }, "AllPokemonFullReviveModifierType": { - description: "Reanima todos os Pokémon, restaurando totalmente seus PS", + description: "Reanima todos os Pokémon, restaurando totalmente seus PS.", }, "MoneyRewardModifierType": { - description: "Garante uma quantidade {{moneyMultiplier}} de dinheiro (₽{{moneyAmount}})", + description: "Garante uma quantidade {{moneyMultiplier}} de dinheiro (₽{{moneyAmount}}).", extra: { "small": "pequena", "moderate": "moderada", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "Aumenta o ganho de pontos de experiência em {{boostPercent}}%", + description: "Aumenta o ganho de pontos de experiência em {{boostPercent}}%.", }, "PokemonExpBoosterModifierType": { - description: "Aumenta o ganho de pontos de experiência de quem segura em {{boostPercent}}%", + description: "Aumenta o ganho de pontos de experiência de quem segura em {{boostPercent}}%.", }, "PokemonFriendshipBoosterModifierType": { - description: "Aumenta o ganho de amizade por vitória em 50%", + description: "Aumenta o ganho de amizade por vitória em 50%.", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "Aumenta a precisão dos movimentos em {{accuracyAmount}} (máximo 100)", + description: "Aumenta a precisão dos movimentos em {{accuracyAmount}} (máximo 100).", }, "PokemonMultiHitModifierType": { - description: "Ataques acertam uma vez adicional ao custo de uma redução de poder de 60/75/82.5% por item, respectivamente", + description: "Ataques acertam uma vez adicional ao custo de uma redução de poder de 60/75/82.5% por item, respectivamente.", }, "TmModifierType": { name: "TM{{moveId}} - {{moveName}}", - description: "Ensina {{moveName}} a um Pokémon", + description: "Ensina {{moveName}} a um Pokémon.", }, "TmModifierTypeWithInfo": { name: "TM{{moveId}} - {{moveName}}", - description: "Ensina {{moveName}} a um Pokémon\n(Segure C ou Shift para mais informações)", + description: "Ensina {{moveName}} a um Pokémon\n(Segure C ou Shift para mais informações).", }, "EvolutionItemModifierType": { - description: "Faz certos Pokémon evoluírem", + description: "Faz certos Pokémon evoluírem.", }, "FormChangeItemModifierType": { - description: "Faz certos Pokémon mudarem de forma", + description: "Faz certos Pokémon mudarem de forma.", }, "FusePokemonModifierType": { - description: "Combina dois Pokémon (transfere Habilidade, divide os atributos base e tipos, compartilha os movimentos)", + description: "Combina dois Pokémon (transfere Habilidade, divide os atributos base e tipos, compartilha os movimentos).", }, "TerastallizeModifierType": { name: "Fragmento Tera {{teraType}}", - description: "Terastalize um Pokémon para o tipo {{teraType}} por 10 ondas", + description: "Terastalize um Pokémon para o tipo {{teraType}} por 10 ondas.", }, "ContactHeldItemTransferChanceModifierType": { - description: "Quando atacar, tem {{chancePercent}}% de chance de roubar um item do oponente", + description: "Quando atacar, tem {{chancePercent}}% de chance de roubar um item do oponente.", }, "TurnHeldItemTransferModifierType": { - description: "Todo turno, o Pokémon ganha um item aleatório do oponente", + description: "Todo turno, o Pokémon ganha um item aleatório do oponente.", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "Ganha {{chancePercent}}% de chance de infligir {{statusEffect}} com ataques", + description: "Ganha {{chancePercent}}% de chance de infligir {{statusEffect}} com ataques.", }, "EnemyEndureChanceModifierType": { - description: "Ganha {{chancePercent}}% de chance de sobreviver a um ataque que o faria desmaiar", + description: "Ganha {{chancePercent}}% de chance de sobreviver a um ataque que o faria desmaiar.", }, "RARE_CANDY": { name: "Doce Raro" }, "RARER_CANDY": { name: "Doce Raríssimo" }, - "MEGA_BRACELET": { name: "Mega Bracelete", description: "Mega Pedras ficam disponíveis" }, - "DYNAMAX_BAND": { name: "Bracelete Dynamax", description: "Cogumáximos ficam disponíveis" }, - "TERA_ORB": { name: "Orbe Tera", description: "Fragmentos Tera ficam disponíveis" }, + "MEGA_BRACELET": { name: "Mega Bracelete", description: "Mega Pedras ficam disponíveis." }, + "DYNAMAX_BAND": { name: "Bracelete Dynamax", description: "Cogumáximos ficam disponíveis." }, + "TERA_ORB": { name: "Orbe Tera", description: "Fragmentos Tera ficam disponíveis." }, - "MAP": { name: "Mapa", description: "Permite escolher a próxima rota" }, + "MAP": { name: "Mapa", description: "Permite escolher a próxima rota." }, "POTION": { name: "Poção" }, "SUPER_POTION": { name: "Super Poção" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cinza Sagrada" }, - "REVIVER_SEED": { name: "Semente Reanimadora", description: "Após desmaiar, reanima com 50% de PS" }, + "REVIVER_SEED": { name: "Semente Reanimadora", description: "Após desmaiar, reanima com 50% de PS." }, "ETHER": { name: "Éter" }, "MAX_ETHER": { name: "Éter Máximo" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "Super Incenso" }, "MAX_LURE": { name: "Incenso Máximo" }, - "MEMORY_MUSHROOM": { name: "Cogumemória", description: "Relembra um movimento esquecido" }, + "MEMORY_MUSHROOM": { name: "Cogumemória", description: "Relembra um movimento esquecido." }, - "EXP_SHARE": { name: "Compart. de Exp.", description: "Distribui pontos de experiência para todos os membros da equipe" }, - "EXP_BALANCE": { name: "Balanceador de Exp.", description: "Distribui pontos de experiência principalmente para os Pokémon mais fracos" }, + "EXP_SHARE": { name: "Compart. de Exp.", description: "Distribui pontos de experiência para todos os membros da equipe." }, + "EXP_BALANCE": { name: "Balanceador de Exp.", description: "Distribui pontos de experiência principalmente para os Pokémon mais fracos." }, - "OVAL_CHARM": { name: "Amuleto Oval", description: "Quando vários Pokémon participam de uma batalha, cada um recebe 10% extra de pontos de experiência" }, + "OVAL_CHARM": { name: "Amuleto Oval", description: "Quando vários Pokémon participam de uma batalha, cada um recebe 10% extra de pontos de experiência." }, "EXP_CHARM": { name: "Amuleto de Exp." }, "SUPER_EXP_CHARM": { name: "Super Amuleto de Exp." }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Guizo" }, - "SOUL_DEW": { name: "Joia da Alma", description: "Aumenta a influência da natureza de um Pokémon em seus atributos em 10% (cumulativo)" }, + "SOUL_DEW": { name: "Joia da Alma", description: "Aumenta a influência da natureza de um Pokémon em seus atributos em 10% (cumulativo)." }, "NUGGET": { name: "Pepita" }, "BIG_NUGGET": { name: "Pepita Grande" }, "RELIC_GOLD": { name: "Relíquia de Ouro" }, - "AMULET_COIN": { name: "Moeda Amuleto", description: "Aumenta a recompensa de dinheiro em 50%" }, - "GOLDEN_PUNCH": { name: "Soco Dourado", description: "Concede 50% do dano causado em dinheiro" }, - "COIN_CASE": { name: "Moedeira", description: "Após cada 10ª batalha, recebe 10% de seu dinheiro em juros" }, + "AMULET_COIN": { name: "Moeda Amuleto", description: "Aumenta a recompensa de dinheiro em 50%." }, + "GOLDEN_PUNCH": { name: "Soco Dourado", description: "Concede 50% do dano causado em dinheiro." }, + "COIN_CASE": { name: "Moedeira", description: "Após cada 10ª batalha, recebe 10% de seu dinheiro em juros." }, - "LOCK_CAPSULE": { name: "Cápsula de Travamento", description: "Permite que você trave raridades de itens ao rolar novamente" }, + "LOCK_CAPSULE": { name: "Cápsula de Travamento", description: "Permite que você trave raridades de itens ao rolar novamente." }, "GRIP_CLAW": { name: "Garra-Aperto" }, "WIDE_LENS": { name: "Lente Ampla" }, "MULTI_LENS": { name: "Multi Lentes" }, - "HEALING_CHARM": { name: "Amuleto de Cura", description: "Aumenta a eficácia dos movimentos e itens que restauram PS em 10% (exceto Reanimador)" }, - "CANDY_JAR": { name: "Pote de Doces", description: "Aumenta o número de níveis adicionados pelo Doce Raro em 1" }, + "HEALING_CHARM": { name: "Amuleto de Cura", description: "Aumenta a eficácia dos movimentos e itens que restauram PS em 10% (exceto Reanimador)." }, + "CANDY_JAR": { name: "Pote de Doces", description: "Aumenta o número de níveis adicionados pelo Doce Raro em 1." }, - "BERRY_POUCH": { name: "Bolsa de Berries", description: "Adiciona uma chance de 30% de que uma berry usada não seja consumida" }, + "BERRY_POUCH": { name: "Bolsa de Berries", description: "Adiciona uma chance de 30% de que uma berry usada não seja consumida." }, - "FOCUS_BAND": { name: "Bandana", description: "Adiciona uma chance de 10% de sobreviver com 1 PS após ser danificado o suficiente para desmaiar" }, + "FOCUS_BAND": { name: "Bandana", description: "Adiciona uma chance de 10% de sobreviver com 1 PS após ser danificado o suficiente para desmaiar." }, - "QUICK_CLAW": { name: "Garra Rápida", description: "Adiciona uma chance de 10% de atacar primeiro, ignorando sua velocidade (após prioridades)" }, + "QUICK_CLAW": { name: "Garra Rápida", description: "Adiciona uma chance de 10% de atacar primeiro, ignorando sua velocidade (após prioridades)." }, - "KINGS_ROCK": { name: "Pedra do Rei", description: "Adiciona uma chance de 10% de movimentos fazerem o oponente hesitar" }, + "KINGS_ROCK": { name: "Pedra do Rei", description: "Adiciona uma chance de 10% de movimentos fazerem o oponente hesitar." }, - "LEFTOVERS": { name: "Sobras", description: "Cura 1/16 dos PS máximos de um Pokémon a cada turno" }, - "SHELL_BELL": { name: "Concha-Sino", description: "Cura 1/8 do dano causado por um Pokémon" }, + "LEFTOVERS": { name: "Sobras", description: "Cura 1/16 dos PS máximos de um Pokémon a cada turno." }, + "SHELL_BELL": { name: "Concha-Sino", description: "Cura 1/8 do dano causado por um Pokémon." }, - "TOXIC_ORB": { name: "Esfera Tóxica", description: "Uma esfera estranha que exala toxinas quando tocada e envenena seriamente quem a segurar" }, - "FLAME_ORB": { name: "Esfera da Chama", description: "Uma esfera estranha que aquece quando tocada e queima quem a segurar" }, + "TOXIC_ORB": { name: "Esfera Tóxica", description: "Uma esfera estranha que exala toxinas quando tocada e envenena seriamente quem a segurar." }, + "FLAME_ORB": { name: "Esfera da Chama", description: "Uma esfera estranha que aquece quando tocada e queima quem a segurar." }, - "BATON": { name: "Bastão", description: "Permite passar mudanças de atributo ao trocar Pokémon, ignorando armadilhas" }, + "BATON": { name: "Bastão", description: "Permite passar mudanças de atributo ao trocar Pokémon, ignorando armadilhas." }, - "SHINY_CHARM": { name: "Amuleto Brilhante", description: "Aumenta drasticamente a chance de um Pokémon selvagem ser Shiny" }, - "ABILITY_CHARM": { name: "Amuleto de Habilidade", description: "Aumenta drasticamente a chance de um Pokémon selvagem ter uma Habilidade Oculta" }, + "SHINY_CHARM": { name: "Amuleto Brilhante", description: "Aumenta drasticamente a chance de um Pokémon selvagem ser Shiny." }, + "ABILITY_CHARM": { name: "Amuleto de Habilidade", description: "Aumenta drasticamente a chance de um Pokémon selvagem ter uma Habilidade Oculta." }, - "IV_SCANNER": { name: "Scanner de IVs", description: "Permite escanear os IVs de Pokémon selvagens. 2 IVs são revelados por item. Os melhores IVs são mostrados primeiro" }, + "IV_SCANNER": { name: "Scanner de IVs", description: "Permite escanear os IVs de Pokémon selvagens. 2 IVs são revelados por item. Os melhores IVs são mostrados primeiro." }, "DNA_SPLICERS": { name: "Splicer de DNA" }, "MINI_BLACK_HOLE": { name: "Mini Buraco Negro" }, - "GOLDEN_POKEBALL": { name: "Poké Bola Dourada", description: "Adiciona 1 opção de item extra ao final de cada batalha" }, + "GOLDEN_POKEBALL": { name: "Poké Bola Dourada", description: "Adiciona 1 opção de item extra ao final de cada batalha." }, - "ENEMY_DAMAGE_BOOSTER": { name: "Token de Dano", description: "Aumenta o dano em 5%" }, - "ENEMY_DAMAGE_REDUCTION": { name: "Token de Proteção", description: "Reduz o dano recebido em 2,5%" }, - "ENEMY_HEAL": { name: "Token de Recuperação", description: "Cura 2% dos PS máximos a cada turno" }, + "ENEMY_DAMAGE_BOOSTER": { name: "Token de Dano", description: "Aumenta o dano em 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Token de Proteção", description: "Reduz o dano recebido em 2,5%." }, + "ENEMY_HEAL": { name: "Token de Recuperação", description: "Cura 2% dos PS máximos a cada turno." }, "ENEMY_ATTACK_POISON_CHANCE": { name: "Token de Veneno" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Token de Paralisia" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "Token de Queimadura" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Token de Cura Total", description: "Adiciona uma chance de 2.5% a cada turno de curar uma condição de status" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Token de Cura Total", description: "Adiciona uma chance de 2.5% a cada turno de curar uma condição de status." }, "ENEMY_ENDURE_CHANCE": { name: "Token de Persistência" }, - "ENEMY_FUSED_CHANCE": { name: "Token de Fusão", description: "Adiciona uma chance de 1% de que um Pokémon selvagem seja uma fusão" }, + "ENEMY_FUSED_CHANCE": { name: "Token de Fusão", description: "Adiciona uma chance de 1% de que um Pokémon selvagem seja uma fusão." }, }, TempBattleStatBoosterItem: { "x_attack": "Ataque X", @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "IgneDisco", "CHILL_DRIVE": "CrioDisco", "DOUSE_DRIVE": "HidroDisco", + + "FIST_PLATE": "Placa de Punho", + "SKY_PLATE": "Placa do Céu", + "TOXIC_PLATE": "Placa Tóxica", + "EARTH_PLATE": "Placa Terrestre", + "STONE_PLATE": "Placa de Pedra", + "INSECT_PLATE": "Placa de Insetos", + "SPOOKY_PLATE": "Placa Assustadora", + "IRON_PLATE": "Placa de Ferro", + "FLAME_PLATE": "Placa da Chama", + "SPLASH_PLATE": "Placa de Respingo", + "MEADOW_PLATE": "Placa de Prado", + "ZAP_PLATE": "Placa Elétrica", + "MIND_PLATE": "Placa Mental", + "ICICLE_PLATE": "Placa de Gelo", + "DRACO_PLATE": "Placa de Draco", + "DREAD_PLATE": "Placa do Pavor", + "PIXIE_PLATE": "Placa Duende", + "BLANK_PLATE": "Placa em Branco", + "LEGEND_PLATE": "Placa de Legenda", + "FIGHTING_MEMORY": "Memória de Lutador", + "FLYING_MEMORY": "Memória Voadora", + "POISON_MEMORY": "Memória Venenosa", + "GROUND_MEMORY": "Memória Terrestre", + "ROCK_MEMORY": "Memória da Rocha", + "BUG_MEMORY": "Memória de Insetos", + "GHOST_MEMORY": "Memória Fantasma", + "STEEL_MEMORY": "Memória de Aço", + "FIRE_MEMORY": "Memória de Fogo", + "WATER_MEMORY": "Memória da Água", + "GRASS_MEMORY": "Memória de Planta", + "ELECTRIC_MEMORY": "Memória Elétrica", + "PSYCHIC_MEMORY": "Memória Psíquica", + "ICE_MEMORY": "Memória de Gelo", + "DRAGON_MEMORY": "Memória do Dragão", + "DARK_MEMORY": "Memória Negra", + "FAIRY_MEMORY": "Memória de Fada", + "BLANK_MEMORY": "Memória Vazia", }, } as const; diff --git a/src/locales/pt_BR/party-ui-handler.ts b/src/locales/pt_BR/party-ui-handler.ts index 9d3c7baa9ae..763d733f3e8 100644 --- a/src/locales/pt_BR/party-ui-handler.ts +++ b/src/locales/pt_BR/party-ui-handler.ts @@ -1,10 +1,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const partyUiHandler: SimpleTranslationEntries = { - "SEND_OUT": "Send Out", - "SUMMARY": "Summary", - "CANCEL": "Cancel", - "RELEASE": "Release", - "APPLY": "Apply", - "TEACH": "Teach" + "SEND_OUT": "Trocar", + "SUMMARY": "Sumário", + "CANCEL": "Cancelar", + "RELEASE": "Soltar", + "APPLY": "Aplicar", + "TEACH": "Ensinar", } as const; diff --git a/src/locales/pt_BR/save-slot-select-ui-handler.ts b/src/locales/pt_BR/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..23aeed7c5c7 --- /dev/null +++ b/src/locales/pt_BR/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Substituir os dados desse slot?", + "loading": "Carregando...", + "wave": "Onda", + "lv": "Nv", + "empty": "Vazio", +} as const; diff --git a/src/locales/pt_BR/starter-select-ui-handler.ts b/src/locales/pt_BR/starter-select-ui-handler.ts index 4d4ee94505b..fc98e72c614 100644 --- a/src/locales/pt_BR/starter-select-ui-handler.ts +++ b/src/locales/pt_BR/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "Escolha o movimento que substituirá", "unlockPassive": "Aprender Passiva", "reduceCost": "Reduzir Custo", - "cycleShiny": "R: » Shiny", - "cycleForm": "F: » Forma", - "cycleGender": "G: » Gênero", - "cycleAbility": "E: » Habilidade", - "cycleNature": "N: » Natureza", - "cycleVariant": "V: » Variante", + "cycleShiny": ": » Shiny", + "cycleForm": ": » Forma", + "cycleGender": ": » Gênero", + "cycleAbility": ": » Habilidade", + "cycleNature": ": » Natureza", + "cycleVariant": ": » Variante", "enablePassive": "Ativar Passiva", "disablePassive": "Desativar Passiva", "locked": "Bloqueada", diff --git a/src/locales/pt_BR/trainers.ts b/src/locales/pt_BR/trainers.ts index 4942fa7999f..a2c6046e85e 100644 --- a/src/locales/pt_BR/trainers.ts +++ b/src/locales/pt_BR/trainers.ts @@ -18,8 +18,8 @@ export const titles: SimpleTranslationEntries = { // Titles of trainers like "Youngster" or "Lass" export const trainerClasses: SimpleTranslationEntries = { - "ace_trainer": "Trinador Ás", - "ace_trainer_female": "Trinadora Ás", + "ace_trainer": "Treinador Ás", + "ace_trainer_female": "Treinadora Ás", "ace_duo": "Dupla Ás", "artist": "Artista", "artist_female": "Artista", diff --git a/src/locales/zh_CN/achv.ts b/src/locales/zh_CN/achv.ts index 42b1995bcde..10012592330 100644 --- a/src/locales/zh_CN/achv.ts +++ b/src/locales/zh_CN/achv.ts @@ -1,171 +1,270 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { - name: "Achievements", + name: "成就", }, "Locked": { - name: "Locked", + name: "未解锁", }, "MoneyAchv": { - description: "Accumulate a total of ₽{{moneyAmount}}", + description: "累计获得 ₽{{moneyAmount}}", }, "10K_MONEY": { - name: "Money Haver", + name: "小有积蓄", }, "100K_MONEY": { - name: "Rich", + name: "大户人家", }, "1M_MONEY": { - name: "Millionaire", + name: "百万富翁", }, "10M_MONEY": { - name: "One Percenter", + name: "暴发户", }, "DamageAchv": { - description: "Inflict {{damageAmount}} damage in one hit", + description: "在单次攻击中造成 {{damageAmount}} 点伤害", }, "250_DMG": { - name: "Hard Hitter", + name: "重拳出击", }, "1000_DMG": { - name: "Harder Hitter", + name: "神拳猛击", }, "2500_DMG": { - name: "That's a Lotta Damage!", + name: "夺少?", }, "10000_DMG": { - name: "One Punch Man", + name: "一拳超人", }, "HealAchv": { - description: "Heal {{healAmount}} {{HP}} at once with a move, ability, or held item", + description: "通过技能、能力或携带的道具一次性治疗 {{healAmount}} {{HP}}点", }, "250_HEAL": { - name: "Novice Healer", + name: "新手奶妈", }, "1000_HEAL": { - name: "Big Healer", + name: "治疗担当", }, "2500_HEAL": { - name: "Cleric", + name: "牧师", }, "10000_HEAL": { - name: "Recovery Master", + name: "泉水", }, "LevelAchv": { - description: "Level up a Pokémon to Lv{{level}}", + description: "将一只宝可梦提升到 Lv{{level}}", }, "LV_100": { - name: "But Wait, There's More!", + name: "别急,后面还有", }, "LV_250": { - name: "Elite", + name: "精英", }, "LV_1000": { - name: "To Go Even Further Beyond", + name: "天外有天", }, "RibbonAchv": { - description: "Accumulate a total of {{ribbonAmount}} Ribbons", + description: "累计获得 {{ribbonAmount}} 个勋章", }, "10_RIBBONS": { - name: "Pokémon League Champion", + name: "宝可梦联盟冠军", }, "25_RIBBONS": { - name: "Great League Champion", + name: "超级球联盟冠军", }, "50_RIBBONS": { - name: "Ultra League Champion", + name: "高级球联盟冠军", }, "75_RIBBONS": { - name: "Rogue League Champion", + name: "肉鸽球联盟冠军", }, "100_RIBBONS": { - name: "Master League Champion", + name: "大师球联盟冠军", }, "TRANSFER_MAX_BATTLE_STAT": { - name: "Teamwork", - description: "Baton pass to another party member with at least one stat maxed out", + name: "团队协作", + description: "在一项属性强化至最大时用接力棒传递给其他宝可梦", }, "MAX_FRIENDSHIP": { - name: "Friendmaxxing", - description: "Reach max friendship on a Pokémon", + name: "亲密无间", + description: "使一只宝可梦的亲密度达到最大值", }, "MEGA_EVOLVE": { - name: "Megamorph", - description: "Mega evolve a Pokémon", + name: "大变身", + description: "超级进化一只宝可梦", }, "GIGANTAMAX": { - name: "Absolute Unit", - description: "Gigantamax a Pokémon", + name: "这位更是重量级", + description: "极巨化一只宝可梦", }, "TERASTALLIZE": { - name: "STAB Enthusiast", - description: "Terastallize a Pokémon", + name: "本系爱好者", + description: "太晶化一只宝可梦", }, "STELLAR_TERASTALLIZE": { - name: "The Hidden Type", - description: "Stellar Terastallize a Pokémon", + name: "隐藏属性", + description: "星晶化一只宝可梦", }, "SPLICE": { - name: "Infinite Fusion", - description: "Splice two Pokémon together with DNA Splicers", + name: "无限融合", + description: "使用基因之楔将两只宝可梦融合在一起", }, "MINI_BLACK_HOLE": { - name: "A Hole Lot of Items", - description: "Acquire a Mini Black Hole", + name: "一大洞的道具", + description: "获得一个迷你黑洞", }, "CATCH_MYTHICAL": { - name: "Mythical", - description: "Catch a mythical Pokémon", + name: "神秘礼物", + description: "捕捉一只幻之宝可梦", }, "CATCH_SUB_LEGENDARY": { - name: "(Sub-)Legendary", - description: "Catch a sub-legendary Pokémon", + name: "二级传说", + description: "捕捉一只准传说宝可梦", }, "CATCH_LEGENDARY": { - name: "Legendary", - description: "Catch a legendary Pokémon", + name: "传说", + description: "捕捉一只传说宝可梦", }, "SEE_SHINY": { - name: "Shiny", - description: "Find a shiny Pokémon in the wild", + name: "闪耀夺目", + description: "在野外找到一只闪光宝可梦", }, "SHINY_PARTY": { - name: "That's Dedication", - description: "Have a full party of shiny Pokémon", + name: "呕心沥血", + description: "拥有一支由闪光宝可梦组成的满员队伍", }, "HATCH_MYTHICAL": { - name: "Mythical Egg", - description: "Hatch a mythical Pokémon from an egg", + name: "幻兽蛋", + description: "从蛋中孵化出一只幻之宝可梦", }, "HATCH_SUB_LEGENDARY": { - name: "Sub-Legendary Egg", - description: "Hatch a sub-legendary Pokémon from an egg", + name: "二级传说蛋", + description: "从蛋中孵化出一只二级传说宝可梦", }, "HATCH_LEGENDARY": { - name: "Legendary Egg", - description: "Hatch a legendary Pokémon from an egg", + name: "传说蛋", + description: "从蛋中孵化出一只传说宝可梦", }, "HATCH_SHINY": { - name: "Shiny Egg", - description: "Hatch a shiny Pokémon from an egg", + name: "金色传说!", + description: "从蛋中孵化出一只闪光宝可梦", }, "HIDDEN_ABILITY": { - name: "Hidden Potential", - description: "Catch a Pokémon with a hidden ability", + name: "隐藏实力", + description: "捕捉一只拥有隐藏特性的宝可梦", }, "PERFECT_IVS": { - name: "Certificate of Authenticity", - description: "Get perfect IVs on a Pokémon", + name: "合格证", + description: "获得一只拥有完美个体值的宝可梦", }, "CLASSIC_VICTORY": { - name: "Undefeated", - description: "Beat the game in classic mode", + name: "战无不胜", + description: "在经典模式中通关游戏", + }, + + "MONO_GEN_ONE": { + name: "最初的劲敌", + description: "完成仅限第一世代的挑战.", + }, + "MONO_GEN_TWO": { + name: "1.5世代", + description: "完成仅限第二世代的挑战.", + }, + "MONO_GEN_THREE": { + name: "“水太多了”", + description: "完成仅限第三世代的挑战.", + }, + "MONO_GEN_FOUR": { + name: "她真是最强冠军吗?", + description: "完成仅限第四世代的挑战.", + }, + "MONO_GEN_FIVE": { + name: "完全原创", + description: "完成仅限第五世代的挑战.", + }, + "MONO_GEN_SIX": { + name: "女大公", + description: "完成仅限第六世代的挑战.", + }, + "MONO_GEN_SEVEN": { + name: "首届冠军", + description: "完成仅限第七世代的挑战.", + }, + "MONO_GEN_EIGHT": { + name: "冠军时刻!", + description: "完成仅限第八世代的挑战.", + }, + "MONO_GEN_NINE": { + name: "她又放水了", + description: "完成仅限第九世代的挑战.", + }, + + "MonoType": { + description: "完成 {{type}} 单属性挑战.", + }, + "MONO_NORMAL": { + name: "异乎寻常的寻常", + }, + "MONO_FIGHTING": { + name: "我有真功夫", + }, + "MONO_FLYING": { + name: "愤怒的小鸟", + }, + "MONO_POISON": { + name: "关都地区特色", + }, + "MONO_GROUND": { + name: "地震预报", + }, + "MONO_ROCK": { + name: "坚如磐石", + }, + "MONO_BUG": { + name: "音箱蟀侠", + }, + "MONO_GHOST": { + name: "捉鬼敢死队", + }, + "MONO_STEEL": { + name: "铁巨人", + }, + "MONO_FIRE": { + name: "搓火球解决一切", + }, + "MONO_WATER": { + name: "当雨来临,倾盆而下", + }, + "MONO_GRASS": { + name: "别踏这个青", + }, + "MONO_ELECTRIC": { + name: "瞄准大岩蛇的角!", + }, + "MONO_PSYCHIC": { + name: "脑洞大开", + }, + "MONO_ICE": { + name: "如履薄冰", + }, + "MONO_DRAGON": { + name: "准神俱乐部", + }, + "MONO_DARK": { + name: "总有叛逆期", + }, + "MONO_FAIRY": { + name: "林克,醒醒!", }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/zh_CN/challenges.ts b/src/locales/zh_CN/challenges.ts new file mode 100644 index 00000000000..8793f5177d7 --- /dev/null +++ b/src/locales/zh_CN/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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": "你只能使用妖精属性的宝可梦", +} as const; diff --git a/src/locales/zh_CN/config.ts b/src/locales/zh_CN/config.ts index 0560b829dea..3f5504f64ce 100644 --- a/src/locales/zh_CN/config.ts +++ b/src/locales/zh_CN/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const zhCnConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const zhCnConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const zhCnConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index 26602079f65..cbbc009f2e2 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -4,1317 +4,1276 @@ import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/plugins export const PGMdialogue: DialogueTranslationEntries = { "youngster": { "encounter": { - 1: "Hey, wanna battle?", - 2: "Are you a new trainer too?", - 3: "Hey, I haven't seen you before. Let's battle!", - 4: "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", - 5: "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!", - 6: "All right! Let's go!", - 7: "All right! Here I come! I'll show you my power!", - 8: "Haw haw haw... I'll show you how hawesome my Pokémon are!", - 9: "No need to waste time saying hello. Bring it on whenever you're ready!", - 10: "Don't let your guard down, or you may be crying when a kid beats you.", - 11: "I've raised my Pokémon with great care. You're not allowed to hurt them!", - 12: "Glad you made it! It won't be an easy job from here.", - 13: "The battles continue forever! Welcome to the world with no end!" + 1: "嘿,想来对战吗?", + 2: "你也是新人训练师吗?", + 3: "嘿,我之前没见过你。我们来对战吧!", + 4: "我刚输了,所以我正在寻找更多的宝可梦。$等等!你看起来很弱!\n来吧,我们对战吧!", + 5: "我们见过面吗?我记不太清了。$嗯,不管怎样,很高兴见到你!", + 6: "好的!我们上吧!", + 7: "好的!我来啦!我会向你展示我的实力!", + 8: "嚯嚯嚯...我会向你展示我的宝可梦有多厉害!", + 9: "不要浪费时间打招呼。你准备好了就放马过来!", + 10: "别掉以轻心,$否则你可能会被小朋友打到哭鼻子哦。", + 11: "我精心培养了我的宝可梦。不许你伤害它们!", + 12: "恭喜你成功了!从这以后可不轻松哦。", + 13: "战斗永无止境!欢迎来到没有尽头的世界!", }, "victory": { - 1: "Wow! You're strong!", - 2: "I didn't stand a chance, huh?", - 3: "I'll find you again when I'm older and beat you!", - 4: "Ugh. I don't have any more Pokémon.", - 5: "No way… NO WAY! How could I lose again…", - 6: "No! I lost!", - 7: "Whoa! You are incredible! I'm amazed and surprised!", - 8: "Could it be… How… My Pokémon and I are the strongest, though…", - 9: "I won't lose next time! Let's battle again sometime!", - 10: "Sheesh! Can't you see that I'm just a kid! It wasn't fair of you to go all out like that!", - 11: "Your Pokémon are more amazing! Trade with me!", - 12: "I got a little carried away earlier, but what job was I talking about?", - 13: "Ahaha! There it is! That's right! You're already right at home in this world!" + 1: "哇!你很强!", + 2: "我根本没机会赢,对吧?", + 3: "我会等长大了再来打败你!", + 4: "呃。我没有更多宝可梦了。", + 5: "不可能…不可能!我怎么可能又输了…", + 6: "不!我输了!", + 7: "哇!你真是太不可思议了!我既惊讶又钦佩!", + 8: "这怎么…怎么可能…$明明我和我的宝可梦是最强大的…", + 9: "下次我不会输了!我们找时间再对战吧!", + 10: "天哪!你看不出我还只是个小孩子吗!$你那样全力以赴太赖了!", + 11: "你的宝可梦更棒啊!和我交换吧!", + 12: "我之前有点上头,我说了什么来着?", + 13: "啊哈哈!就是这样!$对!你已经熟悉这个世界了!", } }, "lass": { "encounter": { - 1: "Let's have a battle, shall we?", - 2: "You look like a new trainer. Let's have a battle!", - 3: "I don't recognize you. How about a battle?", - 4: "Let's have a fun Pokémon battle!", - 5: "I'll show you the ropes of how to really use Pokémon!", - 6: "A serious battle starts from a serious beginning! Are you sure you're ready?", - 7: "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.", - 8: "You'd better go easy on me, OK? Though I'll be seriously fighting!", - 9: "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time." + 1: "我们来对战吧,好吗?", + 2: "你看起来像是个新人训练师。我们来战斗吧!", + 3: "我不认识你。来对战怎么样?", + 4: "让我们来进行一场有趣的宝可梦对战吧!", + 5: "我会向你展示如何真正使用宝可梦!", + 6: "一场认真的对战从始于认真的开场白!$你确定你准备好了吗?", + 7: "花无重开日,人无再少年。$你在对战中只有一次机会。$很快,你就只能活在回忆中了。", + 8: "你最好对我手下留情,好吗?$当然我会认真对战的!", + 9: "学校很无聊,我无事可做。$*哈欠*…我只是来对战打发时间。", }, "victory": { - 1: "That was impressive! I've got a lot to learn.", - 2: "I didn't think you'd beat me that bad…", - 3: "I hope we get to have a rematch some day.", - 4: "That was pretty amazingly fun! You've totally exhausted me…", - 5: "You actually taught me a lesson! You're pretty amazing!", - 6: "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", - 7: "I don't need memories like this. Deleting memory…", - 8: "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", - 9: "I'm actually getting tired of battling… There's gotta be something new to do…" + 1: "那真是令人印象深刻!我还有很多要学习。", + 2: "我没想到你会这么轻易地打败我…", + 3: "我希望有一天,我们能再进行一场对战。", + 4: "那真是场非常有趣的对战!$你让我精疲力尽了…", + 5: "你给我上了一课!你真是太棒了!", + 6: "说真的,我输了。$这,怎么说,真的好难过,但你也真的很厉害。", + 7: "我不需要像这样的记忆。删除记忆中…", + 8: "嘿!我告诉过你要对我手下留情!$不过,当你认真的时候,你真的很酷。", + 9: "实际上,我开始厌倦对战了…$一定有新的事情可以做…", } }, "breeder": { "encounter": { - 1: "Obedient Pokémon, selfish Pokémon… Pokémon have unique characteristics.", - 2: "Even though my upbringing and behavior are poor, I've raised my Pokémon well.", - 3: "Hmm, do you discipline your Pokémon? Pampering them too much is no good.", + 1: "听话的宝可梦,自私的宝可梦…$宝可梦有独特的性格呢。", + 2: "尽管我出生贫寒,但我的宝可梦培养的很好。", + 3: "嗯,你有没有管教你的宝可梦?$过度溺爱是不好的。", }, "victory": { - 1: "It is important to nurture and train each Pokémon's characteristics.", - 2: "Unlike my diabolical self, these are some good Pokémon.", - 3: "Too much praise can spoil both Pokémon and people.", + 1: "对每个宝可梦因材施教是很重要的。", + 2: "不像一无是处的我…这些宝可梦都很优秀。", + 3: "过度的赞美会宠坏宝可梦和人。", }, "defeat": { - 1: "You should not get angry at your Pokémon, even if you lose a battle.", - 2: "Right? Pretty good Pokémon, huh? I'm suited to raising things.", - 3: "No matter how much you love your Pokémon, you still have to discipline them when they misbehave." + 1: "即使输了,也不应该对你的宝可梦发火。", + 2: "相当好的宝可梦,对吧?我很会养东西。", + 3: "无论你多么爱你的宝可梦,$你仍要在它没做好时管教它们。", } }, "breeder_female": { "encounter": { - 1: "Pokémon never betray you. They return all the love you give them.", - 2: "Shall I give you a tip for training good Pokémon?", - 3: "I have raised these very special Pokémon using a special method." + 1: "宝可梦永远不会背叛你。$它们会回报你对它们的爱。", + 2: "要我教教你训练优秀宝可梦的技巧吗?", + 3: "特别的宝可梦有特别的培育技巧。", }, "victory": { - 1: "Ugh… It wasn't supposed to be like this. Did I administer the wrong blend?", - 2: "How could that happen to my Pokémon… What are you feeding your Pokémon?", - 3: "If I lose, that tells you I was just killing time. It doesn't damage my ego at all." + 1: "呃…事情不应该是这样的。$我是不是用错了能量方块?", + 2: "这怎么会发生在我的宝可梦身上…$你给你的宝可梦喂了什么?", + 3: "如果我输了,我告诉你我只是在消磨时间。$你根本不会伤害到我的自尊心。", }, "defeat": { - 1: "This proves my Pokémon have accepted my love.", - 2: "The real trick behind training good Pokémon is catching good Pokémon.", - 3: "Pokémon will be strong or weak depending on how you raise them." + 1: "这证明了我的宝可梦已经接受了我的爱。", + 2: "训出好宝可梦的真正技巧是捉到好的宝可梦。", + 3: "宝可梦的强弱取决于你的饲养方式。", } }, "fisherman": { "encounter": { - 1: "Aack! You made me lose a bite!\nWhat are you going to do about it?", - 2: "Go away! You're scaring the Pokémon!", - 3: "Let's see if you can reel in a victory!", + 1: "啊!你让我错过了一次咬钩!$你打算怎么办?", + 2: "走开!你吓跑了宝可梦!", + 3: "让我看看你能否赢得胜利!", }, "victory": { - 1: "Just forget about it.", - 2: "Next time, I'll be reelin' in the triumph!", - 3: "Guess I underestimated the currents this time.", + 1: "算了吧。", + 2: "下一次,我将卷土重来,凯旋而归!", + 3: "我想这次我低估了海流。", }, }, "fisherman_female": { "encounter": { - 1: "Woah! I've hooked a big one!", - 2: "Line's in, ready to reel in success!", - 3: "Ready to make waves!" + 1: "哇!我钓到了一条大鱼!", + 2: "线已收好,准备提竿!", + 3: "准备制造波浪!", }, "victory": { - 1: "I'll be back with a stronger hook.", - 2: "I'll reel in victory next time.", - 3: "I'm just sharpening my hooks for the comeback!" + 1: "我会带着更强大的鱼钩回来。", + 2: "下次我会赢得胜利。", + 3: "我只是在为回归磨利我的鱼钩!", }, }, "swimmer": { "encounter": { - 1: "Time to dive in!", - 2: "Let's ride the waves of victory!", - 3: "Ready to make a splash!", + 1: "是时候潜水了!", + 2: "让我们一起乘风破浪,赢得胜利!", + 3: "该一鸣惊人了!", }, "victory": { - 1: "Drenched in defeat!", - 2: "A wave of defeat!", - 3: "Back to shore, I guess.", + 1: "沉浸在失败中!", + 2: "失败的波浪!", + 3: "后浪死在沙滩上,我猜。", }, }, "backpacker": { "encounter": { - 1: "Pack up, game on!", - 2: "Let's see if you can keep pace!", - 3: "Gear up, challenger!", - 4: "I've spent 20 years trying to find myself… But where am I?" + 1: "收拾行李,开始游戏!", + 2: "让我看看你是否能跟上!", + 3: "全副武装,挑战者!", + 4: "我花了20年时间试图找到自己……但我在哪里?", }, "victory": { - 1: "Tripped up this time!", - 2: "Oh, I think I'm lost.", - 3: "Dead end!", - 4: "Wait up a second! Hey! Don't you know who I am?" + 1: "这次绊倒了!", + 2: "哦,我觉得我迷路了。", + 3: "死路!", + 4: "等一下!嘿!你不知道我是谁吗?", }, }, "ace_trainer": { "encounter": { - 1: "You seem quite confident.", - 2: "Your Pokémon… Show them to me…", - 3: "Because I'm an Ace Trainer, people think I'm strong.", - 4: "Are you aware of what it takes to be an Ace Trainer?" + 1: "你看起来挺自信的。", + 2: "你的宝可梦…… 让我看看……", + 3: "因为我是王牌训练师,人们认为我很强。", + 4: "你知道成为王牌训练师需要什么吗?", }, "victory": { - 1: "Yes… You have good Pokémon…", - 2: "What?! But I'm a battling genius!", - 3: "Of course, you are the main character!", - 4: "OK! OK! You could be an Ace Trainer!" + 1: "是的…… 你的宝可梦很棒……", + 2: "什么?!我是战斗天才啊!", + 3: "理所应当,你才是主角!", + 4: "好好好!你可以成为王牌训练师!", }, "defeat": { - 1: "I am devoting my body and soul to Pokémon battles!", - 2: "All within my expectations… Nothing to be surprised about…", - 3: "I thought I'd grow up to be a frail person who looked like they would break if you squeezed them too hard.", - 4: "Of course I'm strong and don't lose. It's important that I win gracefully." + 1: "我将把我的身体和灵魂全都奉献给宝可梦对战!", + 2: "一切都在我的预料之中… \n没有什么好惊讶的…", + 3: "我觉得我长大后有点玻璃心,$你太压力我我会跨的……", + 4: "我当然很强大,不会输。$而且重要的是我要优雅地赢。", } }, "parasol_lady": { "encounter": { - 1: "Time to grace the battlefield with elegance and poise!", + 1: "是时候用优雅和从容来为战斗添彩了!", }, "victory": { - 1: "My elegance remains unbroken!", + 1: "我的优雅依然完好无损!", } }, "twins": { "encounter": { - 1: "Get ready, because when we team up, it's double the trouble!", - 2: "Two hearts, one strategy – let's see if you can keep up with our twin power!", - 3: "Hope you're ready for double trouble, because we're about to bring the heat!" + 1: "准备好咯,因为我们联手,\n麻烦双倍!", + 2: "两颗心,一条绳$让我们看看你能否跟上我们双胞胎的力量!", + 3: "希望你准备好了面对双倍的麻烦,$因为我们即将燃起来啦!", }, "victory": { - 1: "We may have lost this round, but our bond remains unbreakable!", - 2: "Our twin spirit won't be dimmed for long.", - 3: "We'll come back stronger as a dynamic duo!" + 1: "虽然我们在这一轮输了,$但我们的羁绊依然坚不可摧!", + 2: "我们的双胞胎精神,才不会就此熄灭。", + 3: "我们会作为充满活力的二人组,$卷土重来,变得更强!", }, "defeat": { - 1: "Twin power reigns supreme!", - 2: "Two hearts, one triumph!", - 3: "Double the smiles, double the victory dance!" + 1: "双胞胎的力量至高无上!", + 2: "两颗心,一起赢!", + 3: "笑容成双,共舞成双!", } }, "cyclist": { "encounter": { - 1: "Get ready to eat my dust!", - 2: "Gear up, challenger! I'm about to leave you in the dust!", - 3: "Pedal to the metal, let's see if you can keep pace!" + 1: "准备好在我后面吃土吧!", + 2: "挑战者,准备好!我要把你打的落花流水!", + 3: "全速前进,让我看看你能不能跟的上!", }, "victory": { - 1: "Spokes may be still, but determination pedals on.", - 2: "Outpaced!", - 3: "The road to victory has many twists and turns yet to explore." + 1: "轮子可能不转了,但我的决心没有停下。", + 2: "被超越了!", + 3: "通往胜利的道路还有许多曲折等待探索。", }, }, "black_belt": { "encounter": { - 1: "I praise your courage in challenging me! For I am the one with the strongest kick!", - 2: "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?" + 1: "我赞扬你挑战我的勇气!$因为我是踢力最强的人!", + 2: "哦,我明白了。你想被切成碎片吗?$或者你更喜欢当个沙袋?", }, "victory": { - 1: "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.", - 2: "Hmmm… If I was going to lose anyway, I was hoping to get totally messed up in the process." + 1: "哦。是宝可梦在战斗。$我强大的踢击一点忙都没帮上。", + 2: "嗯…如果我无论如何都会输,我希望能被彻底打败。", }, }, "battle_girl": { "encounter": { - 1: "You don't have to try to impress me. You can lose against me.", + 1: "你不必试图勾引我。你可以输给我。", }, "victory": { - 1: "It's hard to say good-bye, but we are running out of time…", + 1: "很难说再见,但我们快没时间了……", }, }, "hiker": { "encounter": { - 1: "My middle-age spread has given me as much gravitas as the mountains I hike!", - 2: "I inherited this big-boned body from my parents… I'm like a living mountain range…", + 1: "人到中年后,我的身体和我爬过的山一样强壮!", + 2: "我从父母那里遗传了这副魁梧的身材…$就像一座活生生的山脉…", }, "victory": { - 1: "At least I cannot lose when it comes to BMI!", - 2: "It's not enough… It's never enough. My bad cholesterol isn't high enough…" + 1: "至少在BMI方面我不能输!", + 2: "这还不够……永远不够。$我的坏胆固醇还不够高……", }, }, "ranger": { "encounter": { - 1: "When I am surrounded by nature, most other things cease to matter.", - 2: "When I'm living without nature in my life, sometimes I'll suddenly feel an anxiety attack coming on." + 1: "当我身处大自然中,其他事情都不重要了。", + 2: "如果我生活中没有大自然,有时就会突然感到焦虑。", }, "victory": { - 1: "It doesn't matter to the vastness of nature whether I win or lose…", - 2: "Something like this is pretty trivial compared to the stifling feelings of city life." + 1: "无论我是赢是输,\n对广阔的大自然来说并不重要……", + 2: "与城市生活的窒息感相比,\n这种事情微不足道。", }, "defeat": { - 1: "I won the battle. But victory is nothing compared to the vastness of nature…", - 2: "I'm sure how you feel is not so bad if you compare it to my anxiety attacks…" + 1: "我赢了。但与浩瀚的大自然相比,\n胜利算不了什么…", + 2: "与我的焦虑症相比,我觉得你也不会怎样…", } }, "scientist": { "encounter": { - 1: "My research will lead this world to peace and joy.", + 1: "我的研究将引导这个世界走向和平与欢乐。", }, "victory": { - 1: "I am a genius… I am not supposed to lose against someone like you…", + 1: "我是个天才…我不应该输给你这样的人…", }, }, "school_kid": { "encounter": { - 1: "…Heehee. I'm confident in my calculations and analysis.", - 2: "I'm gaining as much experience as I can because I want to be a Gym Leader someday." + 1: "……嘿嘿。我对计算和分析很有信心。", + 2: "我正在尽可能地积累经验,$因为我希望有一天能成为道馆馆主。", }, "victory": { - 1: "Ohhhh… Calculation and analysis are perhaps no match for chance…", - 2: "Even difficult, trying experiences have their purpose, I suppose." + 1: "哦…计算和分析也许和个例不太匹配呀…", + 2: "我想,即使是艰难困苦的经历,也有存在的意义。", } }, "artist": { "encounter": { - 1: "I used to be popular, but now I am all washed up.", + 1: "我以前很受欢迎,但现在已经彻底过气了。", }, "victory": { - 1: "As times change, values also change. I realized that too late.", + 1: "随着时代的变迁,价值观也在变化。$我意识到这一点已经太晚了。", }, }, "guitarist": { "encounter": { - 1: "Get ready to feel the rhythm of defeat as I strum my way to victory!", + 1: "当我弹奏着走向胜利的旋律时,$准备好感受失败的节奏吧!", }, "victory": { - 1: "Silenced for now, but my melody of resilience will play on.", + 1: "暂时沉默了,但我不屈的旋律将继续演奏。", }, }, "worker": { "encounter": { - 1: "It bothers me that people always misunderstand me. I'm a lot more pure than everyone thinks.", + 1: "人们总误解我,这让我很烦。$我比大家想象的要干净得多。", }, "victory": { - 1: "I really don't want my skin to burn, so I want to stay in the shade while I work.", + 1: "我真的不想晒伤皮肤,所以我想在阴凉处工作。", }, }, "worker_female": { "encounter": { - 1: `It bothers me that people always misunderstand me. - $I'm a lot more pure than everyone thinks.` + 1: "人们总是误解我,这让我很烦。 $我比大家想象的要干净得多。", }, "victory": { - 1: "I really don't want my skin to burn, so I want to stay in the shade while I work." + 1: "我真的不想晒伤皮肤,\n所以我想在阴凉处工作。", }, "defeat": { - 1: "My body and mind aren't necessarily always in sync." - } + 1: "我的身体和心灵并不总同步。", + }, }, "worker_double": { "encounter": { - 1: "I'll show you we can break you. We've been training in the field!", + 1: "你会知道我们怎么击败你的。我们在工地训练过!", }, "victory": { - 1: "How strange… How could this be… I shouldn't have been outmuscled.", + 1: "真奇怪…怎么会这样…我不应该被打败的。", }, }, "hex_maniac": { "encounter": { - 1: "I normally only ever listen to classical music, but if I lose, I think I shall try a bit of new age!", - 2: "I grow stronger with each tear I cry." + 1: "我通常只听古典音乐,但如果我输了,$我想我应该试试新时代的音乐!", + 2: "我的每一滴眼泪都让我变得更加坚强。", }, "victory": { - 1: "Is this the dawning of the age of Aquarius?", - 2: "Now I can get even stronger. I grow with every grudge." + 1: "乐坛新时代的曙光就此出现了吗?", + 2: "现在我变得更强了。我随着他人怨恨而成长。", }, "defeat": { - 1: "New age simply refers to twentieth century classical composers, right?", - 2: "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself." + 1: "“新时代”指的是二十世纪的古典作曲家,对吧?", + 2: "不要纠结于悲伤或沮丧。$你可以用悲愤来激励自己。", } }, "psychic": { "encounter": { - 1: "Hi! Focus!", + 1: "嘿!集中!", }, "victory": { - 1: "Eeeeek!", + 1: "呃呃呃!", }, }, "officer": { "encounter": { - 1: "Brace yourself, because justice is about to be served!", - 2: "Ready to uphold the law and serve justice on the battlefield!" + 1: "准备好,因为正义即将得到伸张!", + 2: "准备好维护法律,在战场上伸张正义!", }, "victory": { - 1: "The weight of justice feels heavier than ever…", - 2: "The shadows of defeat linger in the precinct." + 1: "正义的分量比以往还要沉重……", + 2: "失败的阴影,在警局中徘徊。", } }, "beauty": { "encounter": { - 1: "My last ever battle… That's the way I'd like us to view this match…", + 1: "我最后的战斗…我就是这么看待这场对战的…", }, "victory": { - 1: "It's been fun… Let's have another last battle again someday…", + 1: "很有趣…有时间再来一场最后的战斗…", }, }, "baker": { "encounter": { - 1: "Hope you're ready to taste defeat!" + 1: "希望你准备好品尝失败的滋味!", }, "victory": { - 1: "I'll bake a comeback." + 1: "我会卷土重来的。", }, }, "biker": { "encounter": { - 1: "Time to rev up and leave you in the dust!" + 1: "是时候加速,把你甩在后面了!", }, "victory": { - 1: "I'll tune up for the next race." + 1: "我会为下一场比赛调整状态。", }, }, "firebreather": { "encounter": { - 1: "My flames shall devour you!", - 2: "My soul is on fire. I'll show you how hot it burns!", - 3: "Step right up and take a look!" + 1: "我的火焰会吞噬你!", + 2: "我的灵魂在燃烧,我要让你看看它有多滚烫!", + 3: "快来看看吧!" }, "victory": { - 1: "I burned down to ashes...", - 2: "Yow! That's hot!", - 3: "Ow! I scorched the tip of my nose!" + 1: "我燃成灰了…", + 2: "哟! 好烫!", + 3: "嗷! 我的鼻尖烧焦了!" }, }, "sailor": { "encounter": { - 1: "Matey, you're walking the plank if you lose!", - 2: "Come on then! My sailor's pride is at stake!", - 3: "Ahoy there! Are you seasick?" + 1: "伙计,如果你输了,你就得挨板子!", + 2: "来吧!这关系到我作为水手的尊严!", + 3: "你好啊!你晕船么?" }, "victory": { - 1: "Argh! Beaten by a kid!", - 2: "Your spirit sank me!", - 3: "I think it's me that's seasick..." + 1: "啊,被孩子打败了。", + 2: "你的精神让我沉沦!", + 3: "好像是我晕船了…" }, }, "brock": { "encounter": { - 1: "My expertise on Rock-type Pokémon will take you down! Come on!", - 2: "My rock-hard willpower will overwhelm you!", - 3: "Allow me to show you the true strength of my Pokémon!" + 1: "我对岩石属性宝可梦的专精会击败你!来吧!", + 2: "我磐石般的意志将压倒你!", + 3: "让我展示给你看看,我宝可梦真正的力量!", }, "victory": { - 1: "Your Pokémon's strength have overcome my rock-hard defenses!", - 2: "The world is huge! I'm glad to have had a chance to battle you.", - 3: "Perhaps I should go back to pursuing my dream as a Pokémon Breeder…" + 1: "你宝可梦的力量战胜了我坚如磐石的防御!", + 2: "世界很大!很高兴有机会和你战斗。", + 3: "也许我应该回去追寻我成为宝可梦饲养员的梦想……", }, "defeat": { - 1: "The best offense is a good defense!\nThat's my way of doing things!", - 2: "Come study rocks with me next time to better learn how to fight them!", - 3: "Hah, all my traveling around the regions is paying off!" - } + 1: "最好的进攻就是坚固的防守!$那是我做事的方式!", + 2: "下次来和我一起研究岩石属性,$更好地了解如何与它们对战!", + 3: "哈哈,我在各地的旅行有所回报了!", + }, }, "misty": { "encounter": { - 1: "My policy is an all out offensive with Water-type Pokémon!", - 2: "Hiya, I'll show you the strength of my aquatic Pokémon!", - 3: "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?" + 1: "我的战策就是使用水属性宝可梦全面进攻!", + 2: "嗨,我会让你见识我的水属性宝可梦的力量!", + 3: "我的梦想是踏上旅程,与强大的训练师战斗……$你能满足我吗?", }, "victory": { - 1: "You really are strong… I'll admit that you are skilled…", - 2: "Grrr… You know you just got lucky, right?!", - 3: "Wow, you're too much! I can't believe you beat me!" + 1: "你真的很强……我承认,你有技术的……", + 2: "哼……你知道你只是运气好,对吧?!", + 3: "哇,你太过分了!不敢相信你打败我了!", }, "defeat": { - 1: "Was the mighty Misty too much for you?", - 2: "I hope you saw my Pokémon's elegant swimming techniques!", - 3: "Your Pokémon were no match for my pride and joys!" - } + 1: "强大的小霞对你来说,太过分了吗?", + 2: "我希望你看到了我宝可梦优雅的游泳技巧!", + 3: "你的宝可梦无法匹敌我的心腹和骄傲!", + }, }, "lt_surge": { "encounter": { - 1: "My Electric Pokémon saved me during the war! I'll show you how!", - 2: "Ten-hut! I'll shock you into surrender!", - 3: "I'll zap you just like I do to all my enemies in battle!" + 1: "我的电属性宝可梦在战争中救了我!$我来给你展示一下!", + 2: "立正!我要电到你投降!", + 3: "我会像对待敌军一样,狠狠电你!", }, "victory": { - 1: "Whoa! Your team's the real deal, kid!", - 2: "Aaargh, you're strong! Even my electric tricks lost against you.", - 3: "That was an absolutely shocking loss!" + 1: "哇!你的队伍有真家伙,小子!", + 2: "啊啊,你很强!连我的电击技巧都输给了你。", + 3: "这失败真是把我给电麻了!", }, "defeat": { - 1: "Oh yeah! When it comes to Electric-type Pokémon, I'm number one in the world!", - 2: "Hahaha! That was an electrifying battle, kid!", - 3: "A Pokémon battle is war, and I have showed you first-hand combat!" - } + 1: "哦耶!我的电属性宝可梦是世界第一!", + 2: "哈哈哈!真是一场电动人心的战斗,小子!", + 3: "宝可梦对战等于战争,$我向你展示了军队中的格斗技巧!", + }, }, "erika": { "encounter": { - 1: "Ah, the weather is lovely here…\nOh, a battle? Very well then.", - 2: "My Pokémon battling skills rival that of my flower arranging skills.", - 3: "Oh, I hope the pleasant aroma of my Pokémon doesn't put me to sleep again…", - 4: "Seeing flowers in a garden is so soothing." + 1: "啊,这里天气真好…$哦,对战?那好吧。", + 2: "我在宝可梦对战上的造诣,$可以与我的插花技巧相媲美。", + 3: "哦,希望我宝可梦的宜人香气\n不会再让我睡着…", + 4: "看看花园里的花朵,如此令人心旷神怡。", }, "victory": { - 1: "Oh! I concede defeat.", - 2: "That match was most delightful.", - 3: "Ah, it appears it is my loss…", - 4: "Oh, my goodness." + 1: "哦!我认输啦~", + 2: "这场比赛非常愉快。", + 3: "啊,看来我输了…", + 4: "哦,我的天哪。", }, "defeat": { - 1: "I was afraid I would doze off…", - 2: "Oh my, it seems my Grass Pokémon overwhelmed you.", - 3: "That battle was such a soothing experience.", - 4: "Oh… Is that all?" - } + 1: "我怕我会打瞌睡…", + 2: "哦,我天。看来我的草属性宝可梦击败了你。", + 3: "那场战斗是如此令人心旷神怡。", + 4: "哦…这就完啦?", + }, }, "janine": { "encounter": { - 1: "I am mastering the art of poisonous attacks.\nI shall spar with you today!", - 2: "Father trusts that I can hold my own.\nI will prove him right!", - 3: "My ninja techniques are only second to my Father's!\nCan you keep up?" + 1: "我正在掌握毒属性攻击的艺术。$今天我来和你过过招!", + 2: "父亲相信我能独当一面。$我来证明他说的对!", + 3: "我的忍术,仅次于我的父亲!$你能跟的上吗?", }, "victory": { - 1: "Even now, I still need training… I understand.", - 2: "Your battle technique has outmatched mine.", - 3: "I'm going to really apply myself and improve my skills." + 1: "就算现在,我仍然需要继续训练…我明白了。", + 2: "你的战斗技巧,超过了我。", + 3: "我要好好努力提高我的技术。", }, "defeat": { - 1: "Fufufu… the poison has sapped all your strength to battle.", - 2: "Ha! You didn't stand a chance against my superior ninja skills!", - 3: "Father's faith in me has proven to not be misplaced." - } + 1: "呵呵…毒液耗尽了你所有的力量。", + 2: "哈!你根本无法抵挡我卓越的忍技!", + 3: "我没有辜负父亲对我的信任。", + }, }, "sabrina": { "encounter": { - 1: "Through my psychic ability, I had a vision of your arrival!", - 2: "I dislike fighting, but if you wish, I will show you my powers!", - 3: "I can sense great ambition in you. I shall see if it not unfounded." + 1: "我的超能力预见了你的到来!", + 2: "我不喜欢战斗,但如果你想,$我会展示我的实力!", + 3: "我能感觉到你的雄心壮志。$我倒要看看你是不是虚有其表。", }, "victory": { - 1: "Your power… It far exceeds what I foresaw…", - 2: "I failed to accurately predict your power.", - 3: "Even with my immense psychic powers, I cannot sense another as strong as you." + 1: "你的力量……远远超出了我的预知……", + 2: "我没有准确预测到你的实力。", + 3: "即使我强大的超能力也无法感知到你这样强大的人。", }, "defeat": { - 1: "This victory… It is exactly as I foresaw in my visions!", - 2: "Perhaps it was another I sensed a great desire in…", - 3: "Hone your abilities before recklessly charging into battle.\nYou never know what the future may hold if you do…" - } + 1: "这场胜利……和我看到的未来一样啊!", + 2: "也许我预感到有强大实力的人,是另一个……", + 3: "在你奋不顾身投入战斗之前,\n磨练你的能力。$如果你这样做,你才未来可期……", + }, }, "blaine": { "encounter": { - 1: "Hah! Hope you brought a Burn Heal!", - 2: "My fiery Pokémon will incinerate all challengers!", - 3: "Get ready to play with fire!" + 1: "哈!希望你带了烧伤治疗药!", + 2: "我火热的宝可梦将所有挑战者都焚烧殆尽!", + 3: "准备好玩火吧!", }, "victory": { - 1: "I have burned down to nothing! Not even ashes remain!", - 2: "Didn't I stoke the flames high enough?", - 3: "I'm all burned out… But this makes my motivation to improve burn even hotter!" + 1: "我已经焚烧殆尽了!甚至连灰烬都没有留下!", + 2: "我没有把火焰煽得足够高吗?", + 3: "我燃尽了……但这让我进步的动力燃烧得更旺了!", }, "defeat": { - 1: "My raging inferno cannot be quelled!", - 2: "My Pokémon have been powered up with the heat from this victory!", - 3: "Hah! My passion burns brighter than yours!" - } + 1: "我的熊熊烈火无法被扑灭!", + 2: "我的宝可梦因这次胜利而变得更加强大!", + 3: "哈!我的激情燃得比你的更热烈!", + }, }, "giovanni": { "encounter": { - 1: "I, the leader of Team Rocket, will make you feel a world of pain!", - 2: "My training here will be vital before I am to face my old associates again.", - 3: "I do not think you are prepared for the level of failure you are about to experience!" + 1: "我,火箭队的领袖,\n会让你的世界感受到痛苦!", + 2: "我在这里的训练在我再次面对老朋友之前至关重要。", + 3: "我认为你还没有准备好迎接你即将经历的失败!", }, "victory": { - 1: "WHAT! Me, lose?! There is nothing I wish to say to you!", - 2: "Hmph… You could never understand what I hope to achieve.", - 3: "This defeat is merely delaying the inevitable.\nI will rise Team Rocket from the ashes in due time." + 1: "什么!我输了?! 我没什么可和你说的!", + 2: "哼……你永远无法理解我希望实现的目标。", + 3: "这次失败只是暂时的。$我将找准时机,让火箭队浴火重生。", }, "defeat": { - 1: "Not being able to measure your own strength shows that you are still but a child.", - 2: "Do not try to interfere with me again.", - 3: "I hope you understand how foolish challenging me was." - } + 1: "不知自己几斤几两,\n说明你仍然只是一个孩子。", + 2: "不要再试图干涉我。", + 3: "我希望你明白挑战我是多么愚蠢。", + }, }, "roxanne": { "encounter": { - 1: "Would you kindly demonstrate how you battle?", - 2: "You can learn many things by battling many trainers.", - 3: "Oh, you caught me strategizing.\nWould you like to battle?" + 1: "您能否展示一下您是如何战斗的么?", + 2: "你可以和更多训练师战斗来学到很多东西。", + 3: "哦,被你抓到我正在用功了~$你想战斗吗?", }, "victory": { - 1: "Oh, I appear to have lost.\nI understand.", - 2: "It seems that I still have so much more to learn when it comes to battle.", - 3: "I'll take what I learned here today to heart." + 1: "哦,看来我输了。$我明白了。", + 2: "看来我在战斗方面还有更多东西要学。", + 3: "我会把今天在这里学到的东西铭记于心。", }, "defeat": { - 1: "I have learned many things from our battle.\nI hope you have too.", - 2: "I look forward to battling you again.\nI hope you'll use what you've learned here.", - 3: "I won due to everything I have learned." - } + 1: "从我们的对战中,我学到了很多。$希望你也是。", + 2: "我期待再次与你战斗。$希望你能运用在此学到的东西。", + 3: "我凭借我所学到的一切赢得了胜利。", + }, }, "brawly": { "encounter": { - 1: "Oh man, a challenger!\nLet's see what you can do!", - 2: "You seem like a big splash.\nLet's battle!", - 3: "Time to create a storm!\nLet's go!" + 1: "哦,伙计,挑战者!$让我看看你的能耐!", + 2: "你看起来很厉害嘛。$来对战吧!", + 3: "是时候掀起风暴了!$我们上吧!", }, "victory": { - 1: "Oh woah, you've washed me out!", - 2: "You surfed my wave and crashed me down!", - 3: "I feel like I'm lost in Granite Cave!" + 1: "哦哇,你把我冲走了!", + 2: "你驾驭了我的海浪,把我打败了!", + 3: "我觉得我就像是在武斗洞窟里迷路了!", }, "defeat": { - 1: "Haha, I surfed the big wave!\nChallenge me again sometime.", - 2: "Surf with me again some time!", - 3: "Just like the tides come in and out, I hope you return to challenge me again." - } + 1: "哈哈,我驾驭了大浪!$有时间再挑战我吧。", + 2: "再和我一起冲浪吧!", + 3: "就像潮水的涨落,\n我希望你也能再来挑战我。", + }, }, "wattson": { "encounter": { - 1: "Time to get shocked!\nWahahahaha!", - 2: "I'll make sparks fly!\nWahahahaha!", - 3: "I hope you brought Paralyz Heal!\nWahahahaha!" + 1: "是时候被电击了!$哈哈哈!", + 2: "我要让火星子飞蹦!$哈哈哈!", + 3: "我希望你带了麻痹药!$哇哈哈哈!", }, "victory": { - 1: "Seems like I'm out of charge!\nWahahahaha!", - 2: "You've completely grounded me!\nWahahahaha!", - 3: "Thanks for the thrill!\nWahahahaha!" + 1: "看来我的电量用完了!$哇哈哈哈!", + 2: "你完全接地了是吧!$哇哈哈哈!", + 3: "谢谢你给我电了一下!$哇哈哈哈!", }, "defeat": { - 1: "Recharge your batteries and challenge me again sometime!\nWahahahaha!", - 2: "I hope you found our battle electrifying!\nWahahahaha!", - 3: "Aren't you shocked I won?\nWahahahaha!" - } + 1: "电充充满,有时间再挑战我吧!$哇哈哈哈!", + 2: "我希望你觉得我们的战斗激情似电!$哇哈哈哈!", + 3: "你没想到我赢了吧?$哇哈哈哈!", + }, }, "flannery": { "encounter": { - 1: "Nice to meet you! Wait, no…\nI will crush you!", - 2: "I've only been a leader for a little while, but I'll smoke you!", - 3: "It's time to demonstrate the moves my grandfather has taught me! Let's battle!" + 1: "很高兴见到你!等等,不对……$我要粉碎你!", + 2: "我才当道馆主没多久,\n但我会让你灰飞烟灭!", + 3: "是时候展示爷爷教给我的招式了!来对战吧!", }, "victory": { - 1: "You remind me of my grandfather…\nNo wonder I lost.", - 2: "Am I trying too hard?\nI should relax, can't get too heated.", - 3: "Losing isn't going to smother me out.\nTime to reignite training!" + 1: "你让我想起了我的爷爷……$难怪我输了。", + 2: "我是不是太努力了?$我应该放松,不能太上头了。", + 3: "失败才不会呛到我。$是时候重新点燃训练了!", }, "defeat": { - 1: "I hope I've made my grandfather proud…\nLet's battle again some time.", - 2: "I…I can't believe I won!\nDoing things my way worked!", - 3: "Let's exchange burning hot moves again soon!" - } + 1: "我希望我让祖父感到骄傲了……$有时间我们再战斗吧。", + 2: "我……我简直不敢相信我赢了!$按照自己的方式做事奏效了!", + 3: "早点用炽热的招式再来交手吧!", + }, }, "norman": { "encounter": { - 1: "I'm surprised you managed to get here.\nLet's battle.", - 2: "I'll do everything in my power as a Gym Leader to win.\nLet's go!", - 3: "You better give this your all.\nIt's time to battle!" + 1: "我没想到你能一路来到这里。$我们来对战吧。", + 2: "作为道馆主,我会尽一切努力赢得胜利。$我们开始吧!", + 3: "你最好全力以赴。$对战的时候到了!", }, "victory": { - 1: "I lost to you…?\nRules are rules, though.", - 2: "Was moving from Olivine a mistake…?", - 3: "I can't believe it.\nThat was a great match." + 1: "我输给了你……?$但规则就是规则。", + 2: "难道我不该从城都搬家吗……?", + 3: "我不敢相信。$这是一场好对战。", }, "defeat": { - 1: "We both tried our best.\nI hope we can battle again soon.", - 2: "You should try challenging my kid instead.\nYou might learn something!", - 3: "Thank you for the excellent battle.\nBetter luck next time." - } + 1: "我们都尽力了。$希望我们不久之后能再对战。", + 2: "你应该尝试挑战我的孩子。$可能会有一些收获!", + 3: "谢谢你精彩的战斗。$下次好运。", + }, }, "winona": { "encounter": { - 1: "I've been soaring the skies looking for prey…\nAnd you're my target!", - 2: "No matter how our battle is, my Flying Pokémon and I will triumph with grace. Let's battle!", - 3: "I hope you aren't scared of heights.\nLet's ascend!" + 1: "我一直在天空中翱翔寻找猎物…$而你就是我的目标!", + 2: "不管战况如何,我都会和我的飞行宝可梦$以优雅的姿态获胜。来战斗吧!", + 3: "我希望你不怕高。$我们一起升上高空吧!", }, "victory": { - 1: "You're the first Trainer I've seen with more grace than I.\nExcellently played.", - 2: "Oh, my Flying Pokémon have plummeted!\nVery well.", - 3: "Though I may have fallen, my Pokémon will continue to fly!" + 1: "你是我见过的第一位比我更有风度的训练师。$打的非常出色。", + 2: "哦,我的飞行系宝可梦都已经坠落了!$好吧。", + 3: "尽管我倒下了,我的宝可梦将继续翱翔!", }, "defeat": { - 1: "My Flying Pokémon and I will forever dance elegantly!", - 2: "I hope you enjoyed our show.\nOur graceful dance is finished.", - 3: "Won't you come see our elegant choreography again?" + 1: "我与我的飞行系宝可梦,\n将永远优雅地起舞!", + 2: "我希望你喜欢我们的演出。$我们优雅的舞蹈已经落幕。", + 3: "你愿意再来观看我们优雅的编舞吗?", } }, "tate": { "encounter": { - 1: "Hehehe…\nWere you surprised to see me without my sister?", - 2: "I can see what you're thinking…\nYou want to battle!", - 3: "How can you defeat someone…\nWho knows your every move?" + 1: "嘿嘿嘿…$看到我没和妹妹在一起,很惊讶么?", + 2: "我可以读懂你在想什么…$你想要战斗!", + 3: "你如何击败一个…$读懂你一举一动的人?", }, "victory": { - 1: "It can't be helped…\nI miss Liza…", - 2: "Your bond with your Pokémon was stronger than mine.", - 3: "If I were with Liza, we would have won.\nWe can finish each other's thoughts!" + 1: "赢不了啊…$我想小南了…", + 2: "你和宝可梦之间的联系比我们更强。", + 3: "如果我和小南联手,我们会赢的。$我们可以了解彼此的想法!", }, "defeat": { - 1: "My Pokémon and I are superior!", - 2: "If you can't even defeat me, you'll never be able to defeat Liza either.", - 3: "It's all thanks to my strict training with Liza.\nI can make myself one with Pokémon." - } + 1: "我和我的宝可梦无与伦比!", + 2: "如果你连我都打不过,\n你肯定也打不过小南。", + 3: "这多亏了我和小南的严格训练。$我可以与宝可梦一心同体。", + }, }, "liza": { "encounter": { - 1: "Fufufu…\nWere you surprised to see me without my brother?", - 2: "I can determine what you desire…\nYou want to battle, don't you?", - 3: "How can you defeat someone…\nWho's one with their Pokémon?" + 1: "呵呵呵…$看到我没和哥哥一起,很惊讶吗?", + 2: "我可以读懂你渴望什么…$你想战斗,不是吗?", + 3: "你如何击败一个…$与宝可梦们一心同体的人?", }, "victory": { - 1: "It can't be helped…\nI miss Tate…", - 2: "Your bond with your Pokémon…\nIt's stronger than mine.", - 3: "If I were with Tate, we would have won.\nWe can finish each other's sentences!" + 1: "赢不了啊…$我想小枫了…", + 2: "你和宝可梦之间的联系…$比我强。", + 3: "如果我和小枫在一起,我们会赢的。$我们甚至可以接上彼此的话!", }, "defeat": { - 1: "My Pokémon and I are victorious.", - 2: "If you can't even defeat me, you'll never be able to defeat Tate either.", - 3: "It's all thanks to my strict training with Tate.\nI can synchronize myself with my Pokémon." - } + 1: "我和我的宝可梦势不可挡。", + 2: "如果你连我都打不过,\n你肯定也打不过小枫。", + 3: "这多亏了我和小枫的严格训练。$我可以与我的宝可梦一心同体。", + }, }, "juan": { "encounter": { - 1: "Now's not the time to act coy.\nLet's battle!", - 2: "Ahahaha, You'll be witness to my artistry with Water Pokémon!", - 3: "A typhoon approaches!\nWill you be able to test me?", - 4: "Please, you shall bear witness to our artistry.\nA grand illusion of water sculpted by my Pokémon and myself!" + 1: "别害羞啊。$我们来战斗吧!", + 2: "啊哈哈哈,敬请期待\n我和水属性宝可梦的盛大演出!", + 3: "我就是正在逼近的风暴!$你能经受住考验吗?", + 4: "请你见证我们的表演。$由我和宝可梦共同创造的宏伟水之幻境!", }, "victory": { - 1: "You may be a genius who can take on Wallace!", - 2: "I focused on elegance while you trained.\nIt's only natural that you defeated me.", - 3: "Ahahaha!\nVery well, You have won this time.", - 4: "From you, I sense the brilliant shine of skill that will overcome all." + 1: "你可能是一个能挑战米可利的天才!", + 2: "我专注于优雅,而你刻苦锻炼。$你能击败我是很正常的。", + 3: "啊哈哈哈!$好吧,这次你赢了。", + 4: "从你身上,我感受到了技巧的光辉,\n它将战胜一切。", }, "defeat": { - 1: "My Pokémon and I have sculpted an illusion of Water and come out victorious.", - 2: "Ahahaha, I have won, and you have lost.", - 3: "Shall I loan you my outfit? It may help you battle!\nAhahaha, I jest!", - 4: "I'm the winner! Which is to say, you lost." - } + 1: "宝可梦和我创造的水之幻境,让我取得了胜利。", + 2: "啊哈哈哈,我赢了,你输了。", + 3: "要我把我的服装借给你吗?\n可能能帮到你对战啊!$啊哈哈哈,我开玩笑的!", + 4: "我是赢家!也就是说,你输了。", + }, }, "crasher_wake": { "encounter": { - 1: "Crash! Crash! Watch out!\nCrasher Wake…is…heeere!", - 2: "Crash! Crash! Crasher Wake!", - 3: "I'm the tidal wave of power to wash you away!" + 1: "极限! 极限! 看好了!$极限假面…就此…登场!", + 2: "极限! 极限! 极限假面!", + 3: "我是滔滔巨浪,将你冲走!", }, "victory": { - 1: "That puts a grin on my face!\nGuhahaha! That was a blast!", - 2: "Hunwah! It's gone and ended!\nHow will I say this…\nI want more! I wanted to battle a lot more!", - 3: "WHAAAAT!?" + 1: "我真是笑得合不拢嘴啊!$哈哈哈!那真是太有趣了!", + 2: "呼哇!结束收尾了!$我该怎么说呢……$我还想再对战!我还想再继续战斗!", + 3: "啊啊啊啊啊!?", }, "defeat": { - 1: "Yeeeeah! That's right!", - 2: "I won, but I want more! I wanted to battle a lot more!", - 3: "So long!" - } + 1: "耶!就是这样!", + 2: "我赢了,但我还想要更多!\n我还想再更多地战斗!", + 3: "再见!", + }, }, "falkner": { "encounter": { - 1: "I'll show you the real power of the magnificent bird Pokémon!", - 2: "Winds, stay with me!", - 3: "Dad! I hope you're watching me battle from above!" + 1: "我将向你展示华丽的飞行宝可梦真正的力量!", + 2: "风啊,伴我同行!", + 3: "爸爸!我希望你能在空中注视着我的战斗!", }, "victory": { - 1: "I understand… I'll bow out gracefully.", - 2: "A defeat is a defeat. You are strong indeed.", - 3: "…Shoot! Yeah, I lost." + 1: "明白了……我会礼貌地退场。", + 2: "输了就是输了。你确实很强大。", + 3: "…行吧! 嗯, 我输了。", }, "defeat": { - 1: "Dad! I won with your cherished bird Pokémon…", - 2: "Bird Pokémon are the best after all!", - 3: "Feels like I'm catching up to my dad!" - } + 1: "爸爸!我用你珍爱的飞行宝可梦赢了……", + 2: "飞行系宝可梦才是最强的!", + 3: "感觉我正在追赶上我的父亲!", + }, }, "nessa": { "encounter": { - 1: "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", - 2: "I'm not here to chat. I'm here to win!", - 3: "This is a little gift from my Pokémon… I hope you can take it!" + 1: "无论你的小脑瓜子在搞什么阴谋诡计,$我和我的搭档都会确保它石沉大海。", + 2: "我来这里可不是为了闲聊,\n而是为了赢!", + 3: "这是我的宝可梦给你的一点小礼物……\n我希望你能接受!", }, "victory": { - 1: "You and your Pokémon are just too much…", - 2: "How…? How can this be?!", - 3: "I was totally washed away!" + 1: "你和你的宝可梦太过分了……", + 2: "怎么……?这怎么可能?!", + 3: "我完全被冲走了!", }, "defeat": { - 1: "The raging wave crashes again!", - 2: "Time to ride the wave of victory!", - 3: "Ehehe!" - } + 1: "汹涌的海浪再次袭来!", + 2: "是时候乘风破浪,取得胜利了!", + 3: "诶嘿嘿!", + }, }, "melony": { "encounter": { - 1: "I'm not going to hold back!", - 2: "All righty, I suppose we should get started.", - 3: "I'll freeze you solid!" + 1: "我不会手下留情!", + 2: "好吧,我想我们应该开始了。", + 3: "我会把你冻得结结实实的!", }, "victory": { - 1: "You… You're pretty good, huh?", - 2: "If you find Gordie around, be sure to give him a right trashing, would you?", - 3: "I think you took breaking the ice a little too literally…" + 1: "你……你可厉害了,是不是?", + 2: "如果你找到玛瓜,一定要好好教训他,好吗?", + 3: "你的破冰方式有点过于直接了呢……", }, "defeat": { - 1: "Now do you see how severe battles can be?", - 2: "Hee! Looks like I went and won again!", - 3: "Are you holding back?" - } + 1: "现在你知道战斗有多残酷了吧?", + 2: "嘿!看来我又赢了!", + 3: "你是在保留实力吗?", + }, }, "marlon": { "encounter": { - 1: "You look strong! Shoots! Let's start!", - 2: "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", - 3: "Oh ho, so I'm facing you! That's off the wall." + 1: "你看起来很强!来吧!让我们开始吧!", + 2: "我的强大像大海一样无边无际。$你会被我冲走,绝对的。", + 3: "哦豁,由我来面对你!这可不得了咯!", }, "victory": { - 1: "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", - 2: "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!", - 3: "You're strong as a gnarly wave!" + 1: "你太厉害了!\n你培养了一些非常强大的宝可梦啊,$你已经掌握了训练师的精髓!", + 2: "你不仅仅是看起来,\n你是真的强,真的!$呃,我也被冲走了!", + 3: "你像凶猛的波浪一样强壮!", }, "defeat": { - 1: "You're tough, but it's not enough to sway the sea, 'K!", - 2: "Hee! Looks like I went and won again!", - 3: "Sweet, sweet victory!" - } + 1: "你很强,但这还不足以动摇大海,懂?", + 2: "嘻!看来我又赢了!", + 3: "甜蜜的胜利!", + }, }, "shauntal": { "encounter": { - 1: "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", - 2: "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?", - 3: "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?" + 1: "打扰了。你是挑战者,对吗?$我是四天王的幽灵系宝可梦使用者,$婉龙,我将是你的对手。", + 2: "我非常喜欢描写来到这里的训练师,\n以及他们训练的宝可梦。$我可以用你和你的宝可梦作为主题吗?", + 3: "每个与宝可梦相处的人都有故事要讲。$接下来要讲的故事是怎样的呢?", }, "victory": { - 1: "Wow. I'm dumbstruck!", - 2: "S-sorry! First, I must apologize to my Pokémon…\n\nI'm really sorry you had a bad experience because of me!", - 3: "Even in light of that, I'm still one of the Elite Four!" + 1: "哇。我惊呆了!", + 2: "对…对不起!我必须先向我的宝可梦道歉……$都是因为我让你们有了不好的经历,真的很抱歉!", + 3: "你要知道,我仍然是四天王之一!", }, "defeat": { - 1: "Eheh.", - 2: "That gave me excellent material for my next novel!", - 3: "And so, another tale ends…" - } + 1: "额呵呵。", + 2: "给了我下一部小说的绝佳素材!", + 3: "就这样,又一篇故事来到尾声……", + }, }, "marshal": { "encounter": { - 1: "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", - 2: "Victory, decisive victory, is my intention! Challenger, here I come!", - 3: "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!" + 1: "我的师傅,阿戴克,\n看到了你作为训练师的潜力,$对你很有兴趣。$我要来考验你——挖掘你力量的极限。\n丹田发力!", + 2: "胜利,决定性的胜利,\n正是我所求!挑战者,我来了!", + 3: "在我的心中,我寻求着成为战士的力量,\n克服自身的所有弱点!$以我的信念,取胜!", }, "victory": { - 1: "Whew! Well done!", - 2: "As your battles continue, aim for even greater heights!", - 3: "The strength shown by you and your Pokémon has deeply impressed me…" + 1: "呼!干得好!", + 2: "不要停止战斗,追求更高的目标!", + 3: "你和你宝可梦展现的力量\n给我留下了深刻的印象……", }, "defeat": { - 1: "Hmm.", - 2: "That was good battle.", - 3: "Haaah! Haaah! Haiyaaaah!" + 1: "嗯…", + 2: "这真是场好战斗。", + 3: "哈啊!哈啊!嗨呀啊!", } }, "cheren": { "encounter": { - 1: "You remind me of an old friend. That makes me excited about this Pokémon battle!", - 2: `Pokémon battles have no meaning if you don't think why you battle. - $Or better said, it makes battling together with Pokémon meaningless.`, - 3: "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you." + 1: "你让我想起了一位老朋友。$这让我对这场宝可梦战斗感到兴奋!", + 2: "不考虑清楚这一点,\n宝可梦对战就没有了意义。$这就是失去了和宝可梦一同战斗的意义。", + 3: "我的名字是黑连!我是道馆馆主,\n也是老师!$很高兴认识你。", }, "victory": { - 1: "Thank you! I saw what was missing in me.", - 2: "Thank you! I feel like I saw a little of the way toward my ideals.", - 3: "Hmm… This is problematic." + 1: "谢谢……我又能发现自己的不足了。", + 2: "谢谢…接近理想的道路…我好像隐约看到了。", + 3: "嗯……这值得思考。", }, "defeat": { - 1: "As a Gym Leader, I aim to be a wall for you to overcome.", - 2: "All right!", - 3: "I made it where I am because Pokémon were by my side.\nPerhaps we need to think about why Pokémon help us not in terms of Pokémon and Trainers but as a relationship between living beings." + 1: "作为道馆馆主,我要成为你要跨越的壁垒!", + 2: "好吧!", + 3: "正因为有宝可梦,我们才能走到这里。$为什么宝可梦会帮助我们,\n这个恐怕不仅是宝可梦与训练家…$而是生命与生命之间的问题。", } }, "chili": { "encounter": { - 1: "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", - 2: "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", - 3: "I'm going to show you what me and my blazing Fire types can do!" + 1: "咿呀!是时候玩火了!!我是三兄弟中最强的!", + 2: "嗒哒!如火似焰的伯特——就是我\n——你接下来的对手!", + 3: "我将向你展示,\n我和我炽热的火系宝可梦的能耐!", }, "victory": { - 1: "You got me. I am… burned… out…", - 2: "Whoa ho! You're on fire!", - 3: "Augh! You got me!" + 1: "被你干掉了。我……燃尽了……", + 2: "哇吼!你燃起来了!", + 3: "啊!被你干碎了!", }, "defeat": { - 1: "I'm on fire! Play with me, and you'll get burned!", - 2: "When you play with fire, you get burned!", - 3: "I mean, c'mon, your opponent was me! You didn't have a chance!" + 1: "我燃起来啦!和我玩儿,你就会被烫伤!", + 2: "你要是玩儿火,就会被烫伤!", + 3: "我说,拜托,\n你的对手是我,没机会赢的!", } }, "cilan": { "encounter": { - 1: `Nothing personal... No hard feelings... Me and my Grass-type Pokémon will... - $Um... We're gonna battle come what may.`, - 2: "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", - 3: "OK… So, um, I'm Cilan, I like Grass-type Pokémon." + 1: "无关个人情感…也不会有艰难的感受…$我和我的草属性宝可梦会…$呃…不管什么样的对手我们都会应战的。", + 2: "所以,呃,如果你愿意的话,我会,\n呃,尽我所能做好,呃,你知道的,你的对手。", + 3: "好吧……所以,我是天桐,\n我喜欢草属性宝可梦。", }, "victory": { - 1: "Er… Is it over now?", - 2: `…What a surprise. You are very strong, aren't you? - $I guess my brothers wouldn't have been able to defeat you either…`, - 3: "…Huh. Looks like my timing was, um, off?" + 1: "呃……已经结束了吗?", + 2: "…真是太意外了。你真…强。$看起来就算是伯特或寇恩都赢不了你…", + 3: "…嗯。看起来我来的…不是时候?", }, "defeat": { - 1: "Huh? Did I win?", - 2: `I guess… - $I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.`, - 3: "It…it was quite a thrilling experience…" + 1: "哈?我赢了?", + 2: "我想…$我想我赢了,因为我一直在和我的兄弟伯特和寇恩竞争,\n我们都变得更强了。", + 3: "…这…这是一次非常吓人的经历呢…", } }, "roark": { "encounter": { - 1: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", - 2: "Here goes! These are my rocking Pokémon, my pride and joy!", - 3: "Rock-type Pokémon are simply the best!", - 4: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!" + 1: "我需要看看你作为训练师的潜力。$还有,我要看看与你并肩作战的宝可梦的坚韧!", + 2: "来吧!这些是我的岩石系宝可梦,我的骄傲!", + 3: "岩石属性宝可梦就是最强的!", + 4: "我要看看你作为训练师的潜力。$还要看看与你并肩作战的宝可梦的坚韧!", }, "victory": { - 1: "W-what? That can't be! My buffed-up Pokémon!", - 2: "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", - 3: "With skill like yours, it's natural for you to win.", - 4: "Wh-what?! It can't be! Even that wasn't enough?", - 5: "I blew it." + 1: "什么?不可能!我强化的宝可梦们!", + 2: "……我大脑过载了。$下次邀请你参加地下的化石挖掘比赛。", + 3: "有你这种技术,赢得胜利是很正常的。", + 4: "什么?!连这也不够?", + 5: "我搞砸了。", }, "defeat": { - 1: "See? I'm proud of my rocking battle style!", - 2: "Thanks! The battle gave me confidence that I may be able to beat my dad!", - 3: "I feel like I just smashed through a really stubborn boulder!" + 1: "看?我为我的摇滚战斗风格感到骄傲!", + 2: "谢谢!这场战斗给了我自信,$我感觉能够打败我父亲了!", + 3: "我感觉就像我砸穿了一块顽石!", } }, "morty": { "encounter": { - 1: `With a little more, I could see a future in which I meet the legendary Pokémon. - $You're going to help me reach that level!`, - 2: `It's said that a rainbow-hued Pokémon will come down to appear before a truly powerful Trainer. - $I believed that tale, so I have secretly trained here all my life. As a result, I can now see what others cannot. - $I see a shadow of the person who will make the Pokémon appear. - $I believe that person is me! You're going to help me reach that level!`, - 3: "Whether you choose to believe or not, mystic power does exist.", - 4: "You can bear witness to the fruits of my training.", - 5: "You must make your soul one with that of Pokémon. Can you do this?", - 6: "Say, do you want to be part of my training?" + 1: "只要我再多努力一点,我就能看到我遇到传说中的宝可梦的未来!$你会帮助我达到那个水平!", + 2: "据说,彩虹色的宝可梦会\n出现在真正强大的训练师面前。 $我一直相信着这个美丽的传说,\n所以,从出生开始,\n就在这里进行着秘密的修行。$因为这样,其他人看不到的东西\n我也能够看得到…$我看到的,是那个将传说中的宝可梦\n召唤到这片大地上的人的影子。$我一直相信,那就是我自己!\n希望你也能助我一臂之力!", + 3: "无论你相信还是不相信,神秘的力量确实存在。", + 4: "你可以见证我训练的成果。", + 5: "你必须让你与宝可梦的灵魂合二为一。你能做到吗?", + 6: "嘿,你想成为我训练的一部分吗?", }, "victory": { - 1: "I'm not good enough yet…", - 2: `I see… Your journey has taken you to far-away places and you have witnessed much more than I. - $I envy you for that…`, - 3: "How is this possible…", - 4: `I don't think our potentials are so different. - $But you seem to have something more than that… So be it.`, - 5: "Guess I need more training.", - 6: "That's a shame." + 1: "我还不够好……", + 2: "我明白了…你的旅程…去了遥远的地方,你见过的比我多得多。$我羡慕你…", + 3: "这怎么可能……", + 4: "我认为我们的潜力没什么不同。$但是,我觉得你并不简单,似乎还有什么……", + 5: "我想我需要更多的训练。", + 6: "那太遗憾了", }, "defeat": { - 1: "I moved… one step ahead again.", - 2: "Fufufu…", - 3: "Wh-what?! It can't be! Even that wasn't enough?", - 4: "I feel like I just smashed through a really stubborn boulder!", - 5: "Ahahahah!", - 6: "I knew I would win!" + 1: "我又向前迈进了一步。", + 2: "呵呵呵……", + 3: "什…么?!那还不够?", + 4: "我感觉就像我砸穿了一块顽石!", + 5: "哈哈哈啊!", + 6: "我知道我会赢!", } }, "crispin": { "encounter": { - 1: "I wanna win, so that's exactly what I'll do!", - 2: "I battle because I wanna battle! And you know what? That's how it should be!" + 1: "我想赢,所以接下来我正要赢!", + 2: "我想对战就对战!懂吗!就应该这样!", }, "victory": { - 1: "I wanted to win…but I lost!", - 2: "I lost…'cause I couldn't win!" + 1: "我想赢……但我还是输了!", + 2: "我输了……因为我赢不了!", }, "defeat": { - 1: "Hey, wait a sec. Did I just win? I think I just won! Talk about satisfying!", - 2: "Wooo! That was amazing!" + 1: "嘿,等一下。我是不是赢了?$我觉得我赢了!太满足了!", + 2: "哇哦!那太棒了!", } }, "amarys": { "encounter": { - 1: `I want to be the one to help a certain person. That being the case, I cannot afford to lose. - $… Our battle starts now.`, + 1: "我想帮助某个人。因此,我不能输。$…我们的战斗现在开始。", }, "victory": { - 1: "I am… not enough, I see." + 1: "我还不够,我明白了。", }, "defeat": { - 1: "Victory belongs to me. Well fought." + 1: "胜利属于我。打得好。", } }, "lacey": { "encounter": { - 1: "I'll be facing you with my usual party as a member of the Elite Four." + 1: "我将用我平时的队伍\n作为四天王的一员面对你。", }, "victory": { - 1: "That was a great battle!" + 1: "打得真好呀~", }, "defeat": { - 1: "Let's give your Pokémon a nice round of applause for their efforts!" + 1: "让我们为你宝可梦的努力给予热烈的掌声!", } }, "drayton": { "encounter": { - 1: `Man, I love chairs. Don't you love chairs? What lifesavers. - $I don't get why everyone doesn't just sit all the time. Standing up's tiring work!`, + 1: "哥们,我喜欢椅子。\n你喜欢椅子吗?简直是救星。$我不明白为什么大家不一直坐着。\n站着多累人!", }, "victory": { - 1: "Guess I should've expected that!" + 1: "我早该想到的!", }, "defeat": { - 1: "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?" + 1: "嘿嘿嘿!别介意我,\n我只是在这里小赢一下。$如果你不开心,我懂,\n但别因为我对乌栗发火,OK?", } }, "ramos": { "encounter": { - 1: `Did yeh enjoy the garden playground I made with all these sturdy plants o' mine? - $Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?`, + 1: "我用那些强壮的植物\n盖出来的游乐场精彩吗?$它们的力量象征著我这个园丁兼道馆馆主的实力,\n你真的确定能够与之抗衡吗?", }, "victory": { - 1: "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout." + 1: "你信任你的宝可梦,\n它们也信任你…不错的战斗,小豆芽。", }, "defeat": { - 1: "Hohoho… Indeed. Frail little blades o' grass'll break through even concrete." + 1: "呵呵呵…确实,\n脆弱的小草甚至能穿透混凝土。", } }, "viola": { "encounter": { - 1: `Whether it's the tears of frustration that follow a loss or the blossoming of joy that comes with victory… - $They're both great subjects for my camera! Fantastic! This'll be just fantastic! - $Now come at me!`, - 2: "My lens is always focused on victory--I won't let anything ruin this shot!" + 1: "败阵时的后悔,胜利的瞬间…$都是最棒的影象!很好呀,很好呀!$那么来吧!", + 2: "我的镜头总会聚焦在胜利上,\n我不会让任何事情破坏这个画面!", }, "victory": { - 1: "You and your Pokémon have shown me a whole new depth of field! Fantastic! Just fantastic!", - 2: `The world you see through a lens, and the world you see with a Pokémon by your side… - $The same world can look entirely different depending on your view.` + 1: "你和你的宝可梦向我展示了一个全新的镜头机位!\n很好呀,很好呀!", + 2: "你通过镜头看到的世界,\n和你与宝可梦并肩作战时看到的世界…$视角不同,即使是同一个世界看起来也完全不同。", }, "defeat": { - 1: "The photo from the moment of my victory will be a real winner, all right!", - 2: "Yes! I took some great photos!" - } + 1: "我胜利那一刻的照片,\n将是一个真正的赢家,对吧!", + 2: "是的!我拍了些很棒的照片!", + }, }, "candice": { "encounter": { - 1: `You want to challenge Candice? Sure thing! I was waiting for someone tough! - $But I should tell you, I'm tough because I know how to focus.`, - 2: `Pokémon, fashion, romance… It's all about focus! - $I'll show you just what I mean. Get ready to lose!` + 1: "向小菘我挑战吗?好啊!\n我就是在等待强者$但是我也气势高昂,很强哦?", + 2: "宝可梦也好,时尚也好,恋爱也好,\n无论做什么都气势高昂!$就说到这儿吧,让你见识一下我的气势,\n要做好觉悟哦!", }, "victory": { - 1: "I must say, I'm warmed up to you! I might even admire you a little.", - 2: `Wow! You're great! You've earned my respect! - $I think your focus and will bowled us over totally. ` + 1: "好厉害!我有点尊敬你了。", + 2: "好厉害!我有点尊敬你了!$嗯,感觉是被你的气势给压倒了。", }, "defeat": { - 1: "I sensed your will to win, but I don't lose!", - 2: "See? Candice's focus! My Pokémon's focus is great, too!" + 1: "你的气势我看到了,但我还是不会输的!", + 2: "怎么样?小菘我的气势!\n宝可梦们的气势满满哦!", } }, "gardenia": { "encounter": { - 1: "You have a winning aura about you. So, anyway, this will be fun. Let's have our battle!" + 1: "你身上有一种胜利的气息。\n那么不管怎样,$这应该会是场有趣的战斗。\n让我们对战吧!", }, "victory": { - 1: "Amazing! You're very good, aren't you?" + 1: "太棒了!你可擅长对战了,不是吗?", }, "defeat": { - 1: "Yes! My Pokémon and I are perfectly good!" - } + 1: "太好了!我的宝可梦和我都很棒!", + }, }, "aaron": { "encounter": { - 1: "Ok! Let me take you on!" + 1: "好的!让我来接受你的挑战!", }, "victory": { - 1: "Battling is a deep and complex affair…" + 1: "战斗是一件深刻而复杂的事情……", }, "defeat": { - 1: "Victory over an Elite Four member doesn't come easily." - } + 1: "战胜一位四天王并不容易。", + }, }, "cress": { "encounter": { - 1: "That is correct! It shall be I and my esteemed Water types that you must face in battle!" + 1: "没!错!你必须面对\n与我和我高贵的水属性的战斗!", }, "victory": { - 1: "Lose? Me? I don't believe this." + 1: "输了?我?我不敢相信。", }, "defeat": { - 1: "This is the appropriate result when I'm your opponent." + 1: "当你的对手是我时,这是必然的结果。", } }, "allister": { "encounter": { - 1: "'M Allister.\nH-here… I go…" + 1: "我是欧尼奥。$我…我来了……", }, "victory": { - 1: `I nearly lost my mask from the shock… That was… - $Wow. I can see your skill for what it is.`, + 1: "我差点被吓得丢了面具…那真是…$哇。我可以看清你真正的实力。", }, "defeat": { - 1: "Th-that was ace!" + 1: "这真是太棒了!", } }, "clay": { "encounter": { - 1: "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!" + 1: "咳咳! 让我好等,不是吗,孩子?$好吧,是时候看看你能做到什么了!", }, "victory": { - 1: "Man oh man… It feels good to go all out and still be defeated!" + 1: "真是的……我先说好,\n我可没有手下留情。", }, "defeat": { - 1: `What's important is how ya react to losin'. - $That's why folks who use losin' as fuel to get better are tough.`, + 1: "最重要的是输掉的时候该怎么办。$只要你能在失败中找到教训,\n就能够不断地成长!", } }, "kofu": { "encounter": { - 1: "I'mma serve you a full course o' Water-type Pokémon! Don't try to eat 'em, though!" + 1: "我会给你上一整道水系宝可梦大餐!\n但别真吃了它们!", }, "victory": { - 1: "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!" + 1: "吃了吗!你真是活力又新鲜啊,\n不是吗!$就是有点太鲜活了!", }, "defeat": { - 1: "You come back to see me again now, ya hear?" + 1: "你要再来找我,听见了吗?", } }, "tulip": { "encounter": { - 1: "Allow me to put my skills to use to make your cute little Pokémon even more beautiful!" + 1: "请让我运用我的化妆技巧,$让你可爱的小宝可梦变得更美丽!", }, "victory": { - 1: "Your strength has a magic to it that cannot be washed away." + 1: "你妆点的力量宛如魔法加固,\n完全冲洗不掉啊。", }, "defeat": { - 1: "You know, in my line of work, people who lack talent in one area or the other often fade away quickly—never to be heard of again." + 1: "你知道吗,在我这行,\n那些没天赋的人往往会很快消失,$再也不会被提起。", } }, "sidney": { "encounter": { - 1: `I like that look you're giving me. I guess you'll give me a good match. - $That's good! Looking real good! All right! - $You and me, let's enjoy a battle that can only be staged here!`, + 1: "你给我的印象不错,\n我猜这会是一场精彩的对战。$很棒!看起来真的很棒!$你和我,让我们享受一场\n只能在这里上演的战斗吧!", }, "victory": { - 1: "Well, how do you like that? I lost! Eh, it was fun, so it doesn't matter." + 1: "嗯,你觉得怎样?我输了!\n嗯,不过这很有趣,所以无所谓啊。", }, "defeat": { - 1: "No hard feelings, alright?" + 1: "别介意,OK?", } }, "phoebe": { "encounter": { - 1: `While I trained, I gained the ability to commune with Ghost-type Pokémon. - $Yes, the bond I developed with Pokémon is extremely tight. - $So, come on, just try and see if you can even inflict damage on my Pokémon!`, + 1: "过去我在修行时得到了\n能与幽灵宝可梦亲密交流的能力。$没错,我和宝可梦之间\n有著强烈的羁绊。$那么,来试试看你有没有能力\n伤到我的宝可梦吧!", }, "victory": { - 1: "Oh, darn. I've gone and lost." + 1: "哦,天呀。我输了。", }, "defeat": { - 1: "I look forward to battling you again sometime!" - } + 1: "我期待着下次再和你战斗!", + }, }, "glacia": { "encounter": { - 1: `All I have seen are challenges by weak Trainers and their Pokémon. - $What about you? It would please me to no end if I could go all out against you!`, + 1: "我在这儿见到的尽是些\n弱不禁风的训练家和宝可梦。$你又如何呢?如果你能让我不得不用\n上全力的话就再好不过了!", }, "victory": { - 1: `You and your Pokémon… How hot your spirits burn! - $The all-consuming heat overwhelms. - $It's no surprise that my icy skills failed to harm you.`, + 1: "你和你的宝可梦…\n你们的灵魂燃烧得多么热烈啊!$这股激烈的热能仿佛能征服一切。\n$难怪我的冰属性技巧也奈何不了你了。", }, "defeat": { - 1: "A fiercely passionate battle, indeed." - } + 1: "一场充满激情的战斗,确实。", + }, }, "drake": { "encounter": { - 1: `For us to battle with Pokémon as partners, do you know what it takes? Do you know what is needed? - $If you don't, then you will never prevail over me!`, + 1: "对于我们这些将宝可梦视为\n同伴一同战斗的训练家来说,$你知道怎样才能赢得胜利吗?\n你知道获得胜利的条件吗?$如果你不知道,\n那么你永远也无法战胜我!", }, "victory": { - 1: "Superb, it should be said." + 1: "干得漂亮,就是这样。", }, "defeat": { - 1: "I gave my all for that battle!" - } + 1: "我在这场战斗中全力以赴了!", + }, }, "wallace": { "encounter": { - 1: `There's something about you… A difference in your demeanor. - $I think I sense that in you. Now, show me. Show me the power you wield with your Pokémon. - $And I, in turn, shall present you with a performance of illusions in water by me and my Pokémon!`, + 1: "你的气质变了,\n我能感觉到这一点。$现在,把你和你的宝可梦\n的力量展现给我看吧。$作为回礼,就由我和我的宝可梦\n演出一场水之幻影吧!", }, "victory": { - 1: `Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. - $I find much joy in having met you and your Pokémon. You have proven yourself worthy.`, + 1: "精彩。此刻,我能从你身上感觉到\n身为宝可梦训练家的可靠与高贵。$我真荣幸能遇到你和你的宝可梦。", }, "defeat": { - 1: "A grand illusion!" - } + 1: "伟大的幻影!", + }, }, "lorelei": { "encounter": { - 1: `No one can best me when it comes to icy Pokémon! Freezing moves are powerful! - $Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?`, + 1: "只要能让我用冰属性宝可梦,\n就绝对没人能赢得过我!\n能冻住对方可是很厉害的哦!$因为如果被冻住,你的宝可梦就无法动弹了!\n啊哈哈!你做好觉悟了吧!", }, "victory": { - 1: "How dare you!" + 1: "你怎么敢!", }, "defeat": { - 1: "There's nothing you can do once you're frozen." - } + 1: "一旦你被冻结,你就什么都做不了。", + }, }, "will": { "encounter": { - 1: `I have trained all around the world, making my psychic Pokémon powerful. - $I can only keep getting better! Losing is not an option!`, + 1: "我曾经环游世界,\n日以继夜地做着超能力宝可梦的修行之旅。$我会不断变强!没理由会在这里输掉!", }, "victory": { - 1: "I… I can't… believe it…" + 1: "……不会吧……", }, "defeat": { - 1: "That was close. I wonder what it is that you lack." - } + 1: "就差一点。\n我想知道你缺少了什么。", + }, }, "malva": { "encounter": { - 1: `I feel like my heart might just burst into flames. - $I'm burning up with my hatred for you, runt!`, + 1: "我的内心可是一直燃烧着呢。$燃烧着对你的怒火!", }, "victory": { - 1: "What news… So a new challenger has defeated Malva!" + 1: "挑战者出色地击败了四天王之一,帕琦拉。", }, "defeat": { - 1: "I am delighted! Yes, delighted that I could squash you beneath my heel." - } + 1: "真开心啊,能将你彻底粉碎!", + }, }, "hala": { "encounter": { - 1: "Old Hala is here to make you holler!" + 1: "老哈拉让你放开嗓子!", }, "victory": { - 1: "I could feel the power you gained on your journey." + 1: "我能感受到你在旅途中获得的力量。", }, "defeat": { - 1: "Haha! What a delightful battle!" - } - }, - "molayne": { - "encounter": { - 1: `I gave the captain position to my cousin Sophocles, but I'm confident in my ability. - $My strength is like that of a supernova!`, + 1: "啊哈哈。多么有趣的战斗。", }, - "victory": { - 1: "I certainly found an interesting Trainer to face!" - }, - "defeat": { - 1: "Ahaha. What an interesting battle." - } }, "rika": { "encounter": { - 1: "I'd say I'll go easy on you, but… I'd be lying! Think fast!" + 1: "我要对你手下留情,但……骗你的啦!$好好动脑!", }, "victory": { - 1: "Not bad, kiddo." + 1: "不错,小子。", }, "defeat": { - 1: "Nahahaha! You really are something else, kiddo!" + 1: "啊哈哈哈哈!你真的很特别,小子!", + }, + }, + "molayne": { + "encounter": { + 1: "我将队长的位置让给了我的表弟马玛内,\n但我对自己的能力很有信心。 $我的力量就像超新星一样!", + }, + "victory": { + 1: "我发现了一个有趣的训练师对手!", + }, + "defeat": { + 1: "啊哈哈。多么有趣的战斗。", } }, "bruno": { "encounter": { - 1: "We will grind you down with our superior power! Hoo hah!" + 1: "我们将用势不可挡的力量磨灭你!呼哈!", }, "victory": { - 1: "Why? How could I lose?" + 1: "为什么?我怎么会输?", }, "defeat": { - 1: "You can challenge me all you like, but the results will never change!" + 1: "你可以随意挑战我,\n但结果永远不会改变!", } }, "bugsy": { "encounter": { - 1: "I'm Bugsy! I never lose when it comes to bug Pokémon!" + 1: "我是阿笔!\n对虫系宝可梦的熟悉不会输给任何人的!", }, "victory": { - 1: "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win." + 1: "哇,太棒了!\n你是个宝可梦专家!$我的研究还没有完成。\n好吧,你赢了。", }, "defeat": { - 1: "Thanks! Thanks to our battle, I was also able to make progress in my research!" + 1: "谢谢!多亏了我们的战斗,\n我的研究也取得了进展!", } }, "koga": { "encounter": { - 1: "Fwahahahaha! Pokémon are not merely about brute force--you shall see soon enough!" + 1: "哇哈哈哈哈!$宝可梦不仅仅是关于蛮力,拭目以待吧!", }, "victory": { - 1: "Ah! You've proven your worth!" + 1: "啊!你证明了自己!", }, "defeat": { - 1: "Have you learned to fear the techniques of the ninja?" + 1: "懂不懂要对忍者的技巧心神畏惧?", } }, "bertha": { "encounter": { - 1: "Well, would you show this old lady how much you've learned?" + 1: "啊,让老婆婆看看你学到了什么?", }, "victory": { - 1: `Well! Dear child, I must say, that was most impressive. - $Your Pokémon believed in you and did their best to earn you the win. - $Even though I've lost, I find myself with this silly grin!`, + 1: "好吧,亲爱的孩子,\n不得不说,那令人印象深刻。$你的宝可梦相信你并尽最大努力为你赢得胜利。$尽管我输了,\n我也止不住笑呢!", }, "defeat": { - 1: "Hahahahah! Looks like this old lady won!" + 1: "哈哈哈!看来老婆婆我赢了!", } }, "lenora": { "encounter": { - 1: "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!" + 1: "那么,挑战者,让我来研究$你与你精心养育的宝可梦要如何战斗!", }, "victory": { - 1: "My theory about you was correct. You're more than just talented… You're motivated! I salute you!" + 1: "我关于你的理论是正确的。$你不仅仅是有天赋……你很努力!\n我向你致敬!", }, "defeat": { - 1: "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!" + 1: "啊哈哈!如果你输了,\n一定要分析原因,$并在下一场战斗中运用那些知识!", } }, "siebold": { "encounter": { - 1: "As long as I am alive, I shall strive onward to seek the ultimate cuisine... and the strongest opponents in battle!" + 1: "只要我活着,我将不断努力寻求终极美食…$以及和最强的对手战斗!", }, "victory": { - 1: "I shall store my memory of you and your Pokémon forever away within my heart." + 1: "您的事迹,我志米铭记在心。", }, "defeat": { - 1: `Our Pokémon battle was like food for my soul. It shall keep me going. - $That is how I will pay my respects to you for giving your all in battle!`, + 1: "我们的宝可梦战斗就像我灵魂的养料。\n它将让我继续前进。$这就是我将向你表示敬意的方式,\n感谢你在战斗中全力以赴!", } }, "roxie": { "encounter": { - 1: "Get ready! I'm gonna knock some sense outta ya!" + 1: "准备好了吗!我要给你上一课!", }, "victory": { - 1: "Wild! Your reason's already more toxic than mine!" + 1: "够野的!你的想法比我的还要毒!", }, "defeat": { - 1: "Hey, c'mon! Get serious! You gotta put more out there!" + 1: "嘿,拜托!认真点!\n你要加把劲啊!", } }, "olivia": { "encounter": { - 1: "No introduction needed here. Time to battle me, Olivia!" + 1: "没什么开场白。\n是时候和我丽姿,战斗了!", }, "victory": { - 1: "Really lovely… Both you and your Pokémon…" + 1: "真的很可爱……你和你的宝可梦……", }, "defeat": { - 1: "Mmm-hmm." + 1: "嗯哼。", } }, "poppy": { "encounter": { - 1: "Oooh! Do you wanna have a Pokémon battle with me?" + 1: "哦!你想和我进行宝可梦对战么?", }, "victory": { - 1: "Uagh?! Mmmuuuggghhh…" + 1: "呜哇?!嘛……", }, "defeat": { - 1: `Yaaay! I did it! I de-feet-ed you! You can come for… For… An avenge match? - $Come for an avenge match anytime you want!`, + 1: "耶!我做到了!我击~败~了~你!\n你可以来…打…复仇之战?$只要你想,随时来打复仇之战吧!", } }, "agatha": { @@ -1330,906 +1289,795 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "flint": { "encounter": { - 1: "Hope you're warmed up, cause here comes the Big Bang!" + 1: "希望你已经热身完毕,\n因为这里即将大爆炸!", }, "victory": { - 1: "Incredible! Your moves are so hot, they make mine look lukewarm!" + 1: "不可思议!$你的动作如此火热,让我看起来温吞吞的!", }, "defeat": { - 1: "Huh? Is that it? I think you need a bit more passion." - } + 1: "嗯?就这吗?\n我觉得你得再激情点。", + }, }, "grimsley": { "encounter": { - 1: "The winner takes everything, and there's nothing left for the loser." + 1: "一无所有,\n或者,赢下所有!", }, "victory": { - 1: "When one loses, they lose everything… The next thing I'll look for will be victory, too!" + 1: "一旦失败,\n就意味着失去一切……$下一次我要追寻胜利!", }, "defeat": { - 1: "If somebody wins, the person who fought against that person will lose." + 1: "如果有人赢了,\n和他对战的人就会输。", } }, "caitlin": { "encounter": { - 1: `It's me who appeared when the flower opened up. You who have been waiting… - $You look like a Pokémon Trainer with refined strength and deepened kindness. - $What I look for in my opponent is superb strength… - $Please unleash your power to the fullest!`, + 1: "当花儿绽开时、我便出现。\n成为你在等待的人…$你似乎同时具备实力和善意$我所寻找的是拥有卓越力量的对手…$请用出你的全力吧!", }, "victory": { - 1: "My Pokémon and I learned so much! I offer you my thanks." + 1: "我和我的宝可梦学到了很多!非常感谢。", }, "defeat": { - 1: "I aspire to claim victory with elegance and grace." - } + 1: "我渴望以优雅的姿态取得胜利。", + }, }, "diantha": { "encounter": { - 1: `Battling against you and your Pokémon, all of you brimming with hope for the future… - $Honestly, it just fills me up with energy I need to keep facing each new day! It does!`, + 1: "与你的宝可梦对战\n让你充满了未来的希望…$说真的,这让我更有活力地面对新的一天,确实如此!", }, "victory": { - 1: "Witnessing the noble spirits of you and your Pokémon in battle has really touched my heart…" + 1: "拥有高尚灵魂的训练家和宝可梦的身姿,\n让我的心激烈地震颤…", }, "defeat": { - 1: "Oh, fantastic! What did you think? My team was pretty cool, right?" - } + 1: "哦,太棒了!你觉得怎么样?\n我的队伍很酷吧~对吧?", + }, }, "wikstrom": { "encounter": { - 1: `Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! - $Let the battle begin! En garde!`, + 1: "年轻的挑战者,幸会!\n我乃是著名的钢铁之刃,公爵雁铠! $让我们开始战斗吧!预备!", }, "victory": { - 1: "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!" + 1: "辉煌!你与你尊贵的\n宝可梦之间的信任居然胜过了我!", }, "defeat": { - 1: `What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! - $Winning against such a worthy opponent doth give my soul wings--thus do I soar!`, + 1: "哦哦哦!这是怎么回事,\n我的心止不住地在震颤! $与如此有价值的对手的胜利\n让我的灵魂飞翔——我心翱翔!", } }, "acerola": { "encounter": { - 1: "Battling is just plain fun! Come on, I can take you!" + 1: "对战只是找个乐子!来吧,我来会会你!", }, "victory": { - 1: "I'm… I'm speechless! How did you do it?!" + 1: "我……我说不出话!你是怎么做到的?!", }, "defeat": { - 1: "Ehaha! What an amazing victory!" + 1: "哈哈!真是吓人倒怪的胜利呀!", } }, "larry_elite": { "encounter": { - 1: `Hello there… It's me, Larry. - $I serve as a member of the Elite Four too, yes… Unfortunately for me.`, + 1: "……你好,我是青木。$麻烦的是我还要兼任四天王。", }, "victory": { - 1: "Well, that took the wind from under our wings…" + 1: "好吧,我们翅膀下的疾风止于你这了啊…", }, "defeat": { - 1: "It's time for a meeting with the boss." + 1: "是时候和老板开会了。", } }, "lance": { "encounter": { - 1: "I've been waiting for you. Allow me to test your skill.", - 2: "I thought that you would be able to get this far. Let's get this started." + 1: "我一直在等你。让我来试试你有几斤几两。", + 2: "我知道你能走这么远。让我们开始吧。", }, "victory": { - 1: "You got me. You are magnificent!", - 2: "I never expected another trainer to beat me… I'm surprised." + 1: "被你拿下了啊。你太出色了!", + 2: "我从没想到会有另一个训练师打败我……$我很惊讶。", }, "defeat": { - 1: "That was close. Want to try again?", - 2: "It's not that you are weak. Don't let it bother you." + 1: "就差一点。想再试一次吗?", + 2: "我没觉得你弱,别因此困扰。", } }, "karen": { "encounter": { - 1: "I am Karen. Would you care for a showdown with my Dark-type Pokémon?", - 2: "I am unlike those you've already met.", - 3: "You've assembled a charming team. Our battle should be a good one." + 1: "我是梨花,你想和我的恶属性宝可梦$来一场对决吗?", + 2: "我和你见过的那些人不一样。", + 3: "你组建了一支迷人的队伍。$我们的战斗应该会是场精彩的比赛。", }, "victory": { - 1: "No! I can't win. How did you become so strong?", - 2: "I will not stray from my chosen path.", - 3: "The Champion is looking forward to meeting you." + 1: "不!我赢不了。你是怎么做到变得这么强的?", + 2: "我不会偏离我所选择的道路。", + 3: "冠军正期待与你见面。", }, "defeat": { - 1: "That's about what I expected.", - 2: "Well, that was relatively entertaining.", - 3: "Come visit me anytime." + 1: "意料之中。", + 2: "嗯,还算有点意思。", + 3: "随时欢迎你来找我。", } }, "milo": { "encounter": { - 1: `Sure seems like you understand Pokémon real well. - $This is gonna be a doozy of a battle! - $I'll have to Dynamax my Pokémon if I want to win!`, + 1: "看起来你显然很了解宝可梦。$这会是一场激烈的战斗!$如果我想赢,我得让我的宝可梦极巨化!", }, "victory": { - 1: "The power of Grass has wilted… What an incredible Challenger!" + 1: "草的力量凋谢了…多么不可思议的挑战者!", }, "defeat": { - 1: "This'll really leave you in shock and awe." + 1: "这必将让你大吃一惊。", } }, "lucian": { "encounter": { - 1: `Just a moment, please. The book I'm reading has nearly reached its thrilling climax… - $The hero has obtained a mystic sword and is about to face their final trial… Ah, never mind. - $Since you've made it this far, I'll put that aside and battle you. - $Let me see if you'll achieve as much glory as the hero of my book!,` + 1: "请稍等,我正在读的书\n正要进入最精彩的部分…$英雄获得了一把神秘之剑,\n即将面临最后的考验…啊,算了。$既然你能走到这一步,\n我就不说这些了,和你战斗吧。$让我看看你是否\n能像我书中的主角一样荣耀!", }, "victory": { - 1: "I see… It appears you've put me in checkmate." + 1: "我明白了…看来你把我逼入了绝境。", }, "defeat": { - 1: "I have a reputation to uphold." + 1: "我得维护我的名誉。", } }, "drasna": { "encounter": { - 1: `You must be a strong Trainer. Yes, quite strong indeed… - $That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!` + 1: "你很厉害吧,\n而且相当相当地厉害呢。$我很高兴,能和这样的对手交手,\n就能更好地培养宝可梦们了。", }, "victory": { - 1: "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!" + 1: "哎呀,就这么结束了,\n不好意思,可以的话欢迎再来。", }, "defeat": { - 1: "How can this be?" + 1: "怎么会这样?", } }, "kahili": { "encounter": { - 1: "So, here you are… Why don't we see who the winds favor today, you… Or me?" + 1: "那么,既然来了……\n要不来看看今天的风更青睐谁?$是你……还是我?", }, "victory": { - 1: "It's frustrating to me as a member of the Elite Four, but it seems your strength is the real deal." + 1: "让我这个四天王都感到沮丧,$看来你的力量货真价实。", }, "defeat": { - 1: "That was an ace!" + 1: "那真是一记好球!", } }, "hassel": { "encounter": { - 1: "Prepare to learn firsthand how the fiery breath of ferocious battle feels!" + 1: "让你亲身感受一下什么叫做猛烈的对战气息吧!", }, "victory": { - 1: `Fortune smiled on me this time, but… - $Judging from how the match went, who knows if I will be so lucky next time.`, + 1: "这次幸运之神对我微笑了,但是……$谁知道我下次会不会这么幸运。", }, "defeat": { - 1: "That was an ace!" + 1: "那可真厉害!", } }, "blue": { "encounter": { - 1: "You must be pretty good to get this far." + 1: "能走到这里,你一定非常优秀。", }, "victory": { - 1: "I've only lost to him and now to you… Him? Hee, hee…" + 1: "我只输给过他,现在又是你……?$你问他是谁?哈哈哈……", }, "defeat": { - 1: "See? My power is what got me here." + 1: "看吧?我的实力就是我来到这里的原因。", } }, "piers": { "encounter": { - 1: "Get ready for a mosh pit with me and my party! Spikemuth, it's time to rock!" + 1: "准备好和我的队伍来个大狂欢吧!$尖钉镇,是时候嗨起来了!", }, "victory": { - 1: "Me an' my team gave it our best. Let's meet up again for a battle some time…" + 1: "我和我的队伍已经尽力了。$找个时间再来对战吧……", }, "defeat": { - 1: "My throat's ragged from shoutin'… But 'at was an excitin' battle!" - } + 1: "我的喉咙因为呼喊而变得沙哑……$但这是一场激动人心的战斗!", + }, }, "red": { "encounter": { - 1: "…!" + 1: "…!", }, "victory": { - 1: "…?" + 1: "…?", }, "defeat": { - 1: "…!" - } + 1: "…!", + }, }, "jasmine": { "encounter": { - 1: "Oh… Your Pokémon are impressive. I think I will enjoy this." + 1: "哦……你的宝可梦给人印象深刻。$我想我会享受这场战斗的。", }, "victory": { - 1: "You are truly strong. I'll have to try much harder, too." + 1: "你真的很强。我也得加把劲了。", }, "defeat": { - 1: "I never expected to win." - } + 1: "我从没想到会赢。", + }, }, "lance_champion": { "encounter": { - 1: "I am still the Champion. I won't hold anything back." + 1: "我依旧是冠军,所以我不会留情的。", }, "victory": { - 1: "This is the emergence of a new Champion." + 1: "这就是新冠军的崛起。", }, "defeat": { - 1: "I successfully defended my Championship." + 1: "我成功捍卫了冠军的头衔。", } }, "steven": { "encounter": { - 1: `Tell me… What have you seen on your journey with your Pokémon? - $What have you felt, meeting so many other Trainers out there? - $Traveling this rich land… Has it awoken something inside you? - $I want you to come at me with all that you've learned. - $My Pokémon and I will respond in turn with all that we know!`, + 1: "告诉我…你在和宝可梦的旅途过程中看到了什么?$邂逅了那么多的训练师,\n你都会有什么样的感受呢?$在这丰饶的大地上旅行…\n有没有唤醒你内在的某种东西?$你不如就用一场对战来告诉我你心中的答案吧。$我也会和我的宝可梦用这种方式\n将我们所知道的告诉你的!", }, "victory": { - 1: "So I, the Champion, fall in defeat…" + 1: "没想到连我这个联盟冠军\n都败在你的手上了呢…", }, "defeat": { - 1: "That was time well spent! Thank you!" + 1: "正如我所期待的。谢谢!", } }, "cynthia": { "encounter": { - 1: "I, Cynthia, accept your challenge! There won't be any letup from me!" + 1: "我,竹兰,接受你的挑战!\n我是不会手软的!", }, "victory": { - 1: "No matter how fun the battle is, it will always end sometime…" + 1: "无论对战多么有趣,\n它总会有结束的时候……", }, "defeat": { - 1: "Even if you lose, never lose your love of Pokémon." + 1: "即使你输了,\n也永远不要失去你对宝可梦的热爱。", } }, "iris": { "encounter": { - 1: `Know what? I really look forward to having serious battles with strong Trainers! - $I mean, come on! The Trainers who make it here are Trainers who desire victory with every fiber of their being! - #And they are battling alongside Pokémon that have been through countless difficult battles! - $If I battle with people like that, not only will I get stronger, my Pokémon will, too! - $And we'll get to know each other even better! OK! Brace yourself! - $I'm Iris, the Pokémon League Champion, and I'm going to defeat you!`, + 1: "你知道吗?\n我真的很期待和强大的训练师进行认真的战斗!$我的意思是,来吧!\n到达这里的是那些渴望胜利的训练师,$他们与经历过无数艰难\n战斗的宝可梦一起战斗!$如果我和那样的人战斗,\n不仅我会变得更强,我的宝可梦也会!$我们也会更好地了解彼此!\n好!做好准备吧!$我是艾莉丝,宝可梦联盟冠军,\n我,将打败你!", }, "victory": { - 1: "Aghhhh… I did my best, but we lost…" + 1: "啊……我尽力了,但我们输了……", }, "defeat": { - 1: "Yay! We won!" + 1: "耶!我们赢了!", } }, "hau": { "encounter": { - 1: `I wonder if a Trainer battles differently depending on whether they're from a warm region or a cold region. - $Let's test it out!`, + 1: "我想知道,训练师是否会根据他们是\n来自温暖地区还是寒冷地区而以不同的方式战斗。$让我们来测试一下!", }, "victory": { - 1: "That was awesome! I think I kinda understand your vibe a little better now!" + 1: "那太棒了!我觉得我现在有点了解你的感觉了!", }, "defeat": { - 1: "Ma-an, that was some kinda battle!" - } + 1: "老铁,这才叫战斗!", + }, }, "geeta": { "encounter": { - 1: `I decided to throw my hat in the ring once more. - $Come now… Show me the fruits of your training.`, + 1: "我决定再试一次。$来吧…让我看看你的训练成果。", }, "victory": { - 1: "I eagerly await news of all your achievements!" + 1: "我期待着你的成就!", }, "defeat": { - 1: "What's the matter? This isn't all, is it?" + 1: "怎么,这就结束了?", } }, "nemona": { "encounter": { - 1: "Yesss! I'm so psyched! Time for us to let loose!" + 1: "耶!我太兴奋了!让我们稍微放轻松!", }, "victory": { - 1: "Well, that stinks, but I still had fun! I'll getcha next time!" + 1: "好吧,太糟了,但我还是玩得很开心!$下次我一定会赢你!", }, "defeat": { - 1: "Well, that was a great battle! Fruitful for sure." + 1: "好吧,那是一场很棒的战斗!$肯定是会有收获的啦。", } }, "leon": { "encounter": { - 1: "We're gonna have an absolutely champion time!" + 1: "来享受一段冠军时刻吧!", }, "victory": { - 1: `My time as Champion is over… - $But what a champion time it's been! - $Thank you for the greatest battle I've ever had!`, + 1: "我的冠军生涯结束了……$但这是多么美好的冠军时刻啊!$谢谢你给了我最精彩的一战!", }, "defeat": { - 1: "An absolute champion time, that was!" + 1: "名副其实的冠军时刻!", } }, "whitney": { "encounter": { - 1: "Hey! Don't you think Pokémon are, like, super cute?" + 1: "嘿!你不认为宝可梦超级可爱吗?", }, "victory": { - 1: "Waaah! Waaah! You're so mean!" + 1: "哇啊!哇啊!你太坏了!", }, "defeat": { - 1: "And that's that!" + 1: "就是这样!", } }, "chuck": { "encounter": { - 1: "Hah! You want to challenge me? Are you brave or just ignorant?" + 1: "哈!你想挑战我?你是勇敢还是无知?", }, "victory": { - 1: "You're strong! Would you please make me your apprentice?" + 1: "你很强!能不能收我为徒?", }, "defeat": { - 1: "There. Do you realize how much more powerful I am than you?" - } + 1: "搞定。你明白我比你强得多了吗?", + }, }, "katy": { "encounter": { - 1: "Don't let your guard down unless you would like to find yourself knocked off your feet!" + 1: "不要放松警惕,除非你想被虫丝绊倒哦!", }, "victory": { - 1: "All of my sweet little Pokémon dropped like flies!" + 1: "我可爱的宝可梦们都像苍蝇一样坠落了!", }, "defeat": { - 1: "Eat up, my cute little Vivillon!" - } + 1: "开饭啦,我可爱的彩粉蝶!", + }, }, "pryce": { "encounter": { - 1: "Youth alone does not ensure victory! Experience is what counts." + 1: "年轻不代表能获得胜利!经验才是关键。", }, "victory": { - 1: "Outstanding! That was perfect. Try not to forget what you feel now." + 1: "无与伦比!赢得完美,试着不要忘记你现在的感受。", }, "defeat": { - 1: "Just as I envisioned." - } + 1: "正如我所料。", + }, }, "clair": { "encounter": { - 1: "Do you know who I am? And you still dare to challenge me?" + 1: "你知道我是谁吗?知道还敢挑战我?", }, "victory": { - 1: "I wonder how far you can get with your skill level. This should be fascinating." + 1: "我想知道以你现在的水平能走多远,有趣。", }, "defeat": { - 1: "That's that." + 1: "就是这样。", } }, "maylene": { "encounter": { - 1: `I've come to challenge you now, and I won't hold anything back. - $Please prepare yourself for battle!`, + 1: "我现在要挑战你,我不会保留任何实力。$请准备好战斗!", }, "victory": { - 1: "I admit defeat…" + 1: "是我输了…", }, "defeat": { - 1: "That was awesome." - } + 1: "太棒了。", + }, }, "fantina": { "encounter": { - 1: `You shall challenge me, yes? But I shall win. - $That is what the Gym Leader of Hearthome does, non?`, + 1: "你来挑战吧。我会胜利。$这就是家缘市的道馆馆主。", }, "victory": { - 1: "You are so fantastically strong. I know why I have lost." + 1: "你是最强的,我认输了。", }, "defeat": { - 1: "I am so, so, very happy!" - } + 1: "我非常,非常高兴!", + }, }, "byron": { "encounter": { - 1: `Trainer! You're young, just like my son, Roark. - $With more young Trainers taking charge, the future of Pokémon is bright! - $So, as a wall for young people, I'll take your challenge!`, + 1: "和我儿子瓢太一样的年轻人啊!$我相信培养年轻人\n关系到宝可梦光明的未来!$为此就让我来成为\n年轻人必须跨越的堡垒吧!", }, "victory": { - 1: "Hmm! My sturdy Pokémon--defeated!" + 1: "唔!我千锤百炼的宝可梦!", }, "defeat": { - 1: "Gwahahaha! How were my sturdy Pokémon?!" + 1: "哈哈哈哈!怎么样!我千锤百炼的宝可梦!", } }, "olympia": { "encounter": { - 1: "An ancient custom deciding one's destiny. The battle begins!" + 1: "战斗是决定命运的古老传统。让我们开始吧!", }, "victory": { - 1: "Create your own path. Let nothing get in your way. Your fate, your future." + 1: "创造你自己的道路。$不要让任何东西阻挡你的路、你的命运、你的未来。", }, "defeat": { - 1: "Our path is clear now." + 1: "我们的道路现在已经清晰了。", } }, "volkner": { "encounter": { - 1: `Since you've come this far, you must be quite strong… - $I hope you're the Trainer who'll make me remember how fun it is to battle!`, + 1: "能留到最后的训练家想必肯定是很强的…$希望你会是能让我回忆起\n宝可梦对战乐趣的训练家!", }, "victory": { - 1: `You've got me beat… - $Your desire and the noble way your Pokémon battled for you… - $I even felt thrilled during our match. That was a very good battle.`, + 1: "我输了…$你的心意,宝可梦的不顾一切。$战斗的时候就让我热血沸腾。", }, "defeat": { - 1: `It was not shocking at all… - $That is not what I wanted!`, - } + 1: "完全没感觉…$和我希望的完全不一样!", + }, }, "burgh": { "encounter": { - 1: `M'hm… If I win this battle, I feel like I can draw a picture unlike any before it. - $OK! I can hear my battle muse loud and clear. Let's get straight to it!`, - 2: `Of course, I'm really proud of all of my Pokémon! - $Well now… Let's get right to it!` + 1: "唔…我有预感,\n只要赢了这场战斗就能画出更好的画来…$嗯!战斗充满了幻象!那么,马上开始吧。", + 2: "当然,我对我所有的宝可梦都相当骄傲! $现在…让我们马上开始吧!", }, "victory": { - 1: "Is it over? Has my muse abandoned me?", - 2: "Hmm… It's over! You're incredible!" + 1: "结束了吗?我的女神抛弃我了吗?", + 2: "啊唔,输了……你还真是很强啊。", }, "defeat": { - 1: "Wow… It's beautiful somehow, isn't it…", - 2: `Sometimes I hear people say something was an ugly win. - $I think if you're trying your best, any win is beautiful.` - } + 1: "唔啊……好……好美啊!", + 2: "偶尔也有一些不是很好看的胜利,$但只要努力了,\n不管怎么样的战斗,都是很美丽的。", + }, }, "elesa": { "encounter": { - 1: `C'est fini! When I'm certain of that, I feel an electric jolt run through my body! - $I want to feel the sensation, so now my beloved Pokémon are going to make your head spin!`, + 1: "最后一击!\n在确信这一点的时候全身会流淌过电流!$为追求这个快感,\n我要用可爱的宝可梦们让你头晕眼花。", }, "victory": { - 1: "I meant to make your head spin, but you shocked me instead." + 1: "本想让你头晕的,\n结果我倒反被你电到了。", }, "defeat": { - 1: "That was unsatisfying somehow… Will you give it your all next time?" - } + 1: "感觉还不够啊……下次能使出全力来吗?", + }, }, "skyla": { "encounter": { - 1: `It's finally time for a showdown! That means the Pokémon battle that decides who's at the top, right? - $I love being on the summit! 'Cause you can see forever and ever from high places! - $So, how about you and I have some fun?`, + 1: "终于到决战了!\n这是决定顶点的宝可梦对战吧?$我最喜欢顶点了!\n在高的地方能看到很远很远!$好了!就让我和你好好地玩一场吧!", }, "victory": { - 1: "Being your opponent in battle is a new source of strength to me. Thank you!" + 1: "和你的战斗让我更强了……谢谢。", }, "defeat": { - 1: "Win or lose, you always gain something from a battle, right?" - } + 1: "不管是赢了还是输了,战斗都能得到一些东西。", + }, }, "brycen": { "encounter": { - 1: `There is also strength in being with other people and Pokémon. - $Receiving their support makes you stronger. I'll show you this power!`, + 1: "有其他的人和宝可梦在一起,$这份支持会让自己更强…\n让我来给你展示一下这样的强大吧!", }, "victory": { - 1: "The wonderful combination of you and your Pokémon! What a beautiful friendship!" + 1: "你和你的宝可梦!配合得天衣无缝!\n华丽的友情!", }, "defeat": { - 1: "Extreme conditions really test you and train you!" - } + 1: "尝试极限!锻炼!", + }, }, "drayden": { "encounter": { - 1: `What I want to find is a young Trainer who can show me a bright future. - $Let's battle with everything we have: your skill, my experience, and the love we've raised our Pokémon with!`, + 1: "现在我寻求的是\n能让我看到光明未来的年轻训练家。$你有多少实力,就让我用我的经验,\n我对宝可梦倾注的爱来验证吧!", }, "victory": { - 1: "This intense feeling that floods me after a defeat… I don't know how to describe it." + 1: "失败后涌现的这灼热的意志…\n该怎么说呢…", }, "defeat": { - 1: "Harrumph! I know your ability is greater than that!" - } + 1: "啊啊啊!你的实力就这种程度吗!", + }, }, "grant": { "encounter": { - 1: `There is only one thing I wish for. - $That by surpassing one another, we find a way to even greater heights.`, + 1: "我只期待一件事。. $通过超越彼此,\n我们找到通往更高境界的道路。", }, "victory": { - 1: "You are a wall that I am unable to surmount!" + 1: "你是一堵我无法逾越的墙!", }, "defeat": { - 1: `Do not give up. - $That is all there really is to it. - $The most important lessons in life are simple.`, + 1: "不要放弃。\n这就是人生的真谛。$大道至简。", } }, "korrina": { "encounter": { - 1: "Time for Lady Korrina's big appearance!" + 1: "小女子科尔尼来大显身手啦!", }, "victory": { - 1: "It's your very being that allows your Pokémon to evolve!" + 1: "正因为有你,\n才能让你的宝可梦进化!", }, "defeat": { - 1: "What an explosive battle!" - } + 1: "好劲爆的战斗呀!", + }, }, "clemont": { "encounter": { - 1: "Oh! I'm glad that we got to meet!" + 1: "哦!我很高兴我们能见面!", }, "victory": { - 1: "Your passion for battle inspires me!" + 1: "你对战斗的热情激励了我!", }, "defeat": { - 1: "Looks like my Trainer-Grow-Stronger Machine, Mach 2 is really working!" + 1: "看来我的训练师成长强化机-马克2号,\n真的起作用了!", } }, "valerie": { "encounter": { - 1: `Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. - $Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. - $The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.`, + 1: "哦,这不是一个年轻的训练师吗……\n能这样遇见你真是太好了。 $我想你已经获得了这场战斗的资格,\n作为对你努力的奖励。 $难以捉摸的妖精可能看起来像微风一样脆弱,\n像花朵一样精致,但很坚强。", }, "victory": { - 1: "I hope that you will find things worth smiling about tomorrow…" + 1: "我希望明天你也能找到一些值得会心微笑的事物……", }, "defeat": { - 1: "Oh goodness, what a pity…" - } + 1: "哦,天哪,这太遗憾了……", + }, }, "wulfric": { "encounter": { - 1: `You know what? We all talk big about what you learn from battling and bonds and all that… - $But really, I just do it 'cause it's fun. - $Who cares about the grandstanding? Let's get to battling!`, + 1: "你知道吗?\n我们都说战斗能学到东西,羁绊之类的,$但实际上,我这么做只是因为有趣。 $谁在乎那些华而不实的东西?\n我们来战斗吧!", }, "victory": { - 1: "Outstanding! I'm tough as an iceberg, but you smashed me through and through!" + 1: "杰出!我像冰山一样坚硬,但你彻底击溃了我!", }, "defeat": { - 1: "Tussle with me and this is what happens!" - } + 1: "和我干的结果就是这样!", + }, }, "kabu": { "encounter": { - 1: `Every Trainer and Pokémon trains hard in pursuit of victory. - $But that means your opponent is also working hard to win. - $In the end, the match is decided by which side is able to unleash their true potential.`, + 1: "每个训练师和宝可梦都在努力追求胜利。$但这意味着你的对手也在努力赢得胜利。$最终,比赛是由哪一方\n能够发挥出他们真正的潜力来决定的。", }, "victory": { - 1: "I'm glad I could battle you today!" + 1: "我很高兴今天能和你战斗!", }, "defeat": { - 1: "That's a great way for me to feel my own growth!" - } + 1: "这是我感觉自己的成长的好方式!", + }, }, "bea": { "encounter": { - 1: `Do you have an unshakable spirit that won't be moved, no matter how you are attacked? - $I think I'll just test that out, shall I?`, + 1: "你有没有一种不可动摇的精神,\n受到什么攻击都安如磐石? $就让我来试试吧?", }, "victory": { - 1: "I felt the fighting spirit of your Pokémon as you led them in battle." + 1: "我感受到了你的宝可梦\n在战斗中被你指挥时的战斗之魂。", }, "defeat": { - 1: "That was the best sort of match anyone could ever hope for." + 1: "每个人都希望能有一场这样的好比赛。", } }, "opal": { "encounter": { - 1: "Let me have a look at how you and your partner Pokémon behave!" + 1: "让我看看你和你的宝可梦的表现如何!", }, "victory": { - 1: "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon." + 1: "你不够粉嫩呀,\n但你是一个优秀的训练师,$还拥有着优秀的宝可梦。", }, "defeat": { - 1: "Too bad for you, I guess." - } + 1: "对你来说太惨了,我觉得。", + }, }, "bede": { "encounter": { - 1: "I suppose I should prove beyond doubt just how pathetic you are and how strong I am." + 1: "就让我来证明你有多可怜,我有多强大。", }, "victory": { - 1: "I see… Well, that's fine. I wasn't really trying all that hard anyway." + 1: "我懂了……好吧。其实我还没拿出全力呢。", }, "defeat": { - 1: "Not a bad job, I suppose." - } + 1: "我觉得我打的不错。", + }, }, "gordie": { "encounter": { - 1: "So, let's get this over with." + 1: "好了,我们来做个了结吧!", }, "victory": { - 1: "I just want to climb into a hole… Well, I guess it'd be more like falling from here." + 1: "我只想要挖一个洞爬进去……$好吧,现在更像是掉了进去。", }, "defeat": { - 1: "Battle like you always do, victory will follow!" + 1: "像往常一样战斗,胜利就会随之而来!", } }, "marnie": { "encounter": { - 1: `The truth is, when all's said and done… I really just wanna become Champion for myself! - $So don't take it personal when I kick your butt!`, + 1: "事实上,言而总之… \n人家自己也想当冠军呀! $所以别认为我在针对你!", }, "victory": { - 1: "OK, so I lost… But I got to see a lot of the good points of you and your Pokémon!" + 1: "好吧,我还是输了……\n但是我看到了很多你和你宝可梦的优点哦", }, "defeat": { - 1: "Hope you enjoyed our battle tactics." - } + 1: "希望你喜欢我们的战斗策略。", + }, }, "raihan": { "encounter": { - 1: "I'm going to defeat the Champion, win the whole tournament, and prove to the world just how strong the great Raihan really is!" + 1: "我打算击败冠军,赢得锦标赛,\n并向世界证明奇巴纳大人有多强!", }, "victory": { - 1: `I look this good even when I lose. - $It's a real curse. - $Guess it's time for another selfie!`, + 1: "就算输了我也好帅。$真是罪孽深重啊。$看来得再来张自拍了!", }, "defeat": { - 1: "Let's take a selfie to remember this." + 1: "为了纪念此刻,来张自拍吧!", } }, "brassius": { "encounter": { - 1: "I assume you are ready? Let our collaborative work of art begin!" + 1: "你应该准备好了吧,\一起完成这美丽的艺术作品吧!", }, "victory": { - 1: "Ahhh…vant-garde!" + 1: "啊……前卫!", }, "defeat": { - 1: "I will begin on a new piece at once!" + 1: "我将立即开始新的创作!", } }, "iono": { "encounter": { - 1: `How're ya feelin' about this battle? - $... - $Let's get this show on the road! How strong is our challenger? - $I 'unno! Let's find out together!`, + 1: "谁在奇述!是我奇树!\n做好准备了吗!$...$直播开始!\n今天的小挑战者有多强?$奇树不知道哦~\n让我们一起来看看吧!", }, "victory": { - 1: "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!" + 1: "你的闪耀如1000万伏特!朋友!", }, "defeat": { - 1: "Your eyeballs are MINE!" + 1: "奇树奇树捕获你的眼球!", } }, "larry": { "encounter": { - 1: "When all's said and done, simplicity is strongest." + 1: "归根结底,普普通通就是最强。", }, "victory": { - 1: "A serving of defeat, huh?" + 1: "哼,给我上了一道“战败”。", }, "defeat": { - 1: "I'll call it a day." - } + 1: "下班打卡,走了", + }, }, "ryme": { "encounter": { - 1: "Come on, baby! Rattle me down to the bone!" + 1: "宝贝, 一起! \n摇滚摇到骨子里!", }, "victory": { - 1: "You're cool, my friend—you move my SOUL!" + 1: "你好酷!我佩服!\n我的灵魂为你哭!", }, "defeat": { - 1: "Later, baby!" - } + 1: "再会, 宝贝!", + }, }, "grusha": { "encounter": { - 1: "All I need to do is make sure the power of my Pokémon chills you to the bone!" + 1: "我保证我宝可梦的力量\n会让你感到寒冷彻骨!", }, "victory": { - 1: "Your burning passion… I kinda like it, to be honest." + 1: "你燃烧的热情……老实说,我有点喜欢。", }, "defeat": { - 1: "Things didn't heat up for you." - } + 1: "你没有升温。", + }, }, "marnie_elite": { "encounter": { - 1: "You've made it this far, huh? Let's see if you can handle my Pokémon!", - 2: "I'll give it my best shot, but don't think I'll go easy on you!" + 1: "你已经走到这一步了?$哼~ 看看你能不能对付我的宝可梦!", + 2: "我将全力以赴, 别觉得我会手下留情哦~", }, "victory": { - 1: "I can't believe I lost... But you deserved that win. Well done!", - 2: "Looks like I've still got a lot to learn. Great battle, though!" + 1: "不敢相信…我输掉了… $但是你确实赢得好,干得漂亮捏~", + 2: "看来我还要多多学习呀,\n不过你打的很不错哦~", }, "defeat": { - 1: "You put up a good fight, but I've got the edge! Better luck next time!", - 2: "Seems like my training's paid off. Thanks for the battle!" - } + 1: "你打得不错,但是我更胜一筹!$祝你下次好运啦~", + 2: "看来我的练习有所回报了。\n感谢一战!", + }, }, "nessa_elite": { "encounter": { - 1: "The tides are turning in my favor. Ready to get swept away?", - 2: "Let's make some waves with this battle! I hope you're prepared!" + 1: "海流正在朝着对我有利的方向转变。$准备好被卷走了吗?", + 2: "让我们在这场战斗中掀起波澜!$我希望你做好准备!", }, "victory": { - 1: "You navigated those waters perfectly... Well done!", - 2: "Looks like my currents were no match for you. Great job!" + 1: "你完美地渡过了这片水域......干得好!", + 2: "看来我现在无法与你匹敌。干得好!", }, "defeat": { - 1: "Water always finds a way. That was a refreshing battle!", - 2: "You fought well, but the ocean's power is unstoppable!" - } + 1: "水总能找到出路。\n真是爽快的一战!", + 2: "你打得很好,\n但海洋的力量是不可阻挡的!", + }, }, "bea_elite": { "encounter": { - 1: "Prepare yourself! My fighting spirit burns bright!", - 2: "Let's see if you can keep up with my relentless pace!" + 1: "做好准备!我的斗志熊熊燃烧!", + 2: "让我们看看你是否能跟上我永不停歇的节奏!", }, "victory": { - 1: "Your strength... It's impressive. You truly deserve this win.", - 2: "I've never felt this intensity before. Amazing job!" + 1: "你的实力......令人印象深刻。\n你真的值得这场胜利。", + 2: "我以前从未感受过这种强度。\n太棒了!", }, "defeat": { - 1: "Another victory for my intense training regimen! Well done!", - 2: "You've got strength, but I trained harder. Great battle!" - } + 1: "我的高强度训练又带来胜利了!\n干得好!", + 2: "你有实力,但我的训练更努力。\n精彩的战斗!", + }, }, "allister_elite": { "encounter": { - 1: "Shadows fall... Are you ready to face your fears?", - 2: "Let's see if you can handle the darkness that I command." + 1: "黑暗降临...你准备好面对你的恐惧了吗?", + 2: "让我们看看你能否应对我所操控的黑暗。", }, "victory": { - 1: "You've dispelled the shadows... For now. Well done.", - 2: "Your light pierced through my darkness. Great job." + 1: "你已经驱散了阴影......\n暂时。干得很好。", + 2: "你的光芒刺穿了我的黑暗。干得好。", }, "defeat": { - 1: "The shadows have spoken... Your strength isn't enough.", - 2: "Darkness triumphs... Maybe next time you'll see the light." - } + 1: "黑影在轻语...\n你的力量还不够。", + 2: "黑暗获胜了......\n也许下次你会看到光明。", + }, }, "raihan_elite": { "encounter": { - 1: "Storm's brewing! Let's see if you can weather this fight!", - 2: "Get ready to face the eye of the storm!" + 1: "风暴来临!你能挺过这场战斗吗!", + 2: "准备好面对风暴之眼!", }, "victory": { - 1: "You've bested the storm... Incredible job!", - 2: "You rode the winds perfectly... Great battle!" + 1: "你战胜了风暴...难以置信!", + 2: "你完美地驾驭了风……打得好!", }, "defeat": { - 1: "Another storm weathered, another victory claimed! Well fought!", - 2: "You got caught in my storm! Better luck next time!" + 1: "又一场风暴袭来,又一场胜利!打得好!", + 2: "你被我的风暴卷入了!祝你下次好运!", } }, "rival": { "encounter": { - 1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye… - $@c{smile_eclosed}So you're really pursuing your dream after all?\n I almost can't believe it. - $@c{serious_smile_fists}Since we're here, how about a battle?\nAfter all, I want to make sure you're ready. - $@c{serious_mopen_fists}Don't hold back, I want you to give me everything you've got!` + 1: "@c{smile}嘿,我在找你呢!我知道你急着上路,\n但至少说个再见吧…$@c{smile_eclosed}所以你终于要开始追逐梦想了?\n我几乎不敢相信。$@c{serious_smile_fists}来都来了,来一场对战怎么样?\n毕竟,我想看看你是不是准备周全了。$@c{serious_mopen_fists}不要手下留情,我想让你全力以赴!", }, "victory": { - 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? - $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. - $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there!` + 1: "@c{shock}哇…你彻底击败了我。\n你是真初学者吗?$@c{smile}也许是靠点运气,但是…\n谁知道,你可能真的能一路走下去。$顺便说一下,博士让我给你这些东西。它们看起来可牛了。$@c{serious_smile_fists}祝你好运!", }, }, "rival_female": { "encounter": { - 1: `@c{smile_wave}There you are! I've been looking everywhere for you!\n@c{angry_mopen}Did you forget to say goodbye to your best friend? - $@c{smile_ehalf}You're going after your dream, huh?\nThat day is really today isn't it… - $@c{smile}Anyway, I'll forgive you for forgetting me, but on one condition. @c{smile_wave_wink}You have to battle me! - $@c{angry_mopen}Give it your all! Wouldn't want your adventure to be over before it started, right?` + 1: "@c{smile_wave}你在这儿啊!我到处找你呢!$@c{angry_mopen}你忘了和你最好的朋友说再见了吗?$@c{smile_ehalf}你要去追逐梦想了,对吧?\n从今天开始,是不是…$@c{smile}不管怎样,忘了我的事就原谅你吧,\n但有个条件。@c{smile_wave_wink}你必须和我对战!$@c{angry_mopen}全力以赴!\n你也不想让你的冒险在开始之前就结束了,对吧?", }, "victory": { - 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? - $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. - $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you!` + 1: "@c{shock}你刚开始就已经这么强了?!@d{96}$@c{angry}你是不是开了?$@c{smile_wave_wink}只是开个玩笑啦!@d{64} @c{smile_eclosed}我输地心服口服了…\n我感觉你出去挺有天赋的。$@c{smile}顺便说一下,博士想让我给你一些东西。\n希望它们能帮上忙!$@c{smile_wave}像往常一样尽力而为!\n我相信你!", }, }, "rival_2": { "encounter": { - 1: `@c{smile}Hey, you're here too?\n@c{smile_eclosed}Still a perfect record, huh…? - $@c{serious_mopen_fists}I know it kind of looks like I followed you here, but that's mostly not true. - $@c{serious_smile_fists}Honestly though, I've been itching for a rematch since you beat me back at home. - $I've been doing a lot of my own training so I'll definitely put up a fight this time. - $@c{serious_mopen_fists}Don't hold back, just like before!\nLet's go!` + 1: "@c{smile}嘿,你也在这里吗?$@c{smile_eclosed}一路过关斩将,是吧?$@c{serious_mopen_fists}我知道看起来好像我尾随着你来到这里,\n怎么可能啦。$@c{serious_smile_fists}说真的,自从你在老家打败我后,\n我就一直很渴望再比一场。$我自己也进行了很多训练,\n所以这次我肯定会好好打一场。$@c{serious_mopen_fists}不要手下留情,就像以前一样!$让我们开始吧!", }, "victory": { - 1: `@c{neutral_eclosed}Oh. I guess I was overconfident. - $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n - $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n - $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care!` + 1: "@c{neutral_eclosed}哦。我过于自信了。$@c{smile}不过没关系。我猜到可能会这样。$@c{serious_mopen_fists}这只意味着我下次需要更努力!$$@c{smile}呃,不是特意帮你,我正好有多余的这个,\n我觉得你可能想要。$$@c{serious_smile_fists}不过这次之后别指望再有了!$我不能一直给我的对手优势。$@c{smile}反正,保重!", }, }, "rival_2_female": { "encounter": { - 1: `@c{smile_wave}Oh, fancy meeting you here. Looks like you're still undefeated. @c{angry_mopen}Huh… Not bad! - $@c{angry_mopen}I know what you're thinking, and no, I wasn't creeping on you. @c{smile_eclosed}I just happened to be in the area. - $@c{smile_ehalf}I'm happy for you but I just want to let you know that it's OK to lose sometimes. - $@c{smile}We learn from our mistakes, often more than we would if we kept succeeding. - $@c{angry_mopen}In any case, I've been training hard for our rematch, so you'd better give it your all!` + 1: "@c{smile_wave}哦,真巧,在这里遇见你。\n看来你还没输过嘛。@c{angry_mopen}哈……好家伙!$@c{angry_mopen}我知道你在想什么,\n不,我才不会跟踪你什么呢。 @c{smile_eclosed}我只是碰巧在附近。$@c{smile_ehalf}我为你感到高兴,但我只想让你知道\n有时输了是可以接受的。$@c{smile}我们从错误中学到的东西\n往往比我们一直成功时学到的还要多。$@c{angry_mopen}无论如何,我为了我们的复赛已经努力训练了\n所以你最好全力以赴!", }, "victory": { - 1: `@c{neutral}I… wasn't supposed to lose that time… - $@c{smile}Aw well. That just means I'll have to train even harder for next time! - $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. - $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it!` + 1: "@c{neutral}我……没打算会输来着……$@c{smile}嗷……好吧。看来我要再更加努力训练了!$@c{smile_wave}我还给你带了个这个$@c{smile_wave_wink}不用谢我哦~.$@c{angry_mopen}不过,这是最后一个啦!\n 你可别想再从我这赚小便宜了~$@c{smile_wave}要保重哦!", }, "defeat": { - 1: "It's OK to lose sometimes…" + 1: "输了有时候也不要紧的…", } }, "rival_3": { "encounter": { - 1: `@c{smile}Hey, look who it is! It's been a while.\n@c{neutral}You're… still undefeated? Huh. - $@c{neutral_eclosed}Things have been kind of… strange.\nIt's not the same back home without you. - $@c{serious}I know it's selfish, but I need to get this off my chest.\n@c{neutral_eclosed}I think you're in over your head here. - $@c{serious}Never losing once is just unrealistic.\nWe need to lose sometimes in order to grow. - $@c{neutral_eclosed}You've had a great run but there's still so much ahead, and it only gets harder. @c{neutral}Are you prepared for that? - $@c{serious_mopen_fists}If so, prove it to me.` + 1: "@c{smile}}嘿,看看这是谁!好久不见啊。$@c{neutral}你……还是没输过?哈…$@c{neutral_eclosed}这有点……不太对劲。$没有你一起,回家的感觉有很不一样。$@c{serious}虽然我知道这挺别扭的,但我就直说了。$@c{neutral_eclosed}我觉得你有点儿难以理喻。$@c{serious}没有人能够战无不胜。$失败乃成功之母。$@c{neutral_eclosed}你已经赢得了够好的成绩,\n但前面道阻且长,只会愈发艰难。 @c{neutral}你做好准备了没?$@c{serious_mopen_fists}如果做好了,证明给我看吧。", }, "victory": { - 1: "@c{angry_mhalf}This is ridiculous… I've hardly stopped training…\nHow are we still so far apart?" + 1: "@c{angry_mhalf}这太离谱了……我几乎从没停下训练……$我们之间的差距怎么还是这么大?", }, }, "rival_3_female": { "encounter": { - 1: `@c{smile_wave}Long time no see! Still haven't lost, huh.\n@c{angry}You're starting to get on my nerves. @c{smile_wave_wink}Just kidding! - $@c{smile_ehalf}But really, don't you miss home by now? Or… me?\nI… I mean, we've really missed you. - $@c{smile_eclosed}I support you in your dream and everything, but the reality is you're going to lose sooner or later. - $@c{smile}And when you do, I'll be there for you like always.\n@c{angry_mopen}Now, let me show you how strong I've become!` + 1: "@c{smile_wave}好久不见!还没输过,对吧。$@c{angry}我觉得你点烦了。@c{smile_wave_wink}开玩笑啦!$@c{smile_ehalf}但说真的,你现在不想家吗?\n 不想…我吗?$我……我的意思是,我们真的很想你。$@c{smile_eclosed}我支持你的一切,包括你的梦想。\n但现实就是你早晚会经历失败。$@c{smile}当你失败的时候,我想像往常一样陪在你身边。$@c{angry_mopen}}现在,给你看看我变得多强了吧!", }, "victory": { - 1: "@c{shock}After all that… it wasn't enough…?\nYou'll never come back at this rate…" - + 1: "@c{shock}都这样了……还是不够吗?$这样下去,你就永远不会回来了……", }, "defeat": { - 1: "You gave it your best, now let's go home." - } + 1: "你尽力了,现在让我们回家吧。", + }, }, "rival_4": { "encounter": { - 1: `@c{neutral}Hey. - $I won't mince words or pleasantries with you.\n@c{neutral_eclosed}I'm here to win, plain and simple. - $@c{serious_mhalf_fists}I've learned to maximize my potential by putting all my time into training. - $@c{smile}You get a lot of extra time when you cut out the unnecessary sleep and social interaction. - $@c{serious_mopen_fists}None of that matters anymore, not until I win. - $@c{neutral_eclosed}I've even reached the point where I don't lose anymore.\n@c{smile_eclosed}I suppose your philosophy wasn't so wrong after all. - $@c{angry_mhalf}Losing is for the weak, and I'm not weak anymore. - $@c{serious_mopen_fists}Prepare yourself.` + 1: "@c{neutral}嘿。$我不会对你说什么拐弯抹角的客套话。$@c{neutral_eclosed}我来,就是为了赢,简单明了。$@c{serious_mhalf_fists}我将所有时间都投入到训练中,\n掌握了如何发挥我的潜力。$@c{smile}当你削减掉不必要的睡眠和社交后,\n你会得到很多额外的时间。$@c{serious_mopen_fists}但在我获胜之前,这些都不重要了。$@c{neutral_eclosed}我甚至已经到达了战无不败的境地。$@c{smile_eclosed}我觉得你的思路倒是也没毛病。$@c{angry_mhalf}失败是属于弱者的,\n我已经不再软弱了。$@c{serious_mopen_fists}准备好吧。", }, "victory": { - 1: "@c{neutral}What…@d{64} What are you?" + 1: "@c{neutral}你…@d{64} 你是人吗?", }, }, "rival_4_female": { "encounter": { - 1: `@c{neutral}It's me! You didn't forget about me again… did you? - $@c{smile}You should be proud of how far you made it. Congrats!\nBut it looks like it's the end of your journey. - $@c{smile_eclosed}You've awoken something in me I never knew was there.\nIt seems like all I do now is train. - $@c{smile_ehalf}I hardly even eat or sleep now, I just train my Pokémon all day, getting stronger every time. - $@c{neutral}In fact, I… hardly recognize myself. - $And now, I've finally reached peak performance.\nI don't think anyone could beat me now. - $And you know what? It's all because of you.\n@c{smile_ehalf}I don't know whether to thank you or hate you. - $@c{angry_mopen}Prepare yourself.` + 1: "@c{neutral}是我哦!没又把我忘了吧……是吗?$@c{smile}你应该为自己走了这么远感到骄傲。恭喜你!$但看来你的旅程到此为止了。$@c{smile_eclosed}你唤醒了我体内一些我从未有过的东西。\n就像我现在满脑子除了训练还是训练。$@c{smile_ehalf}我几乎已经没空吃饭睡觉了,\n我没日没夜训练我的宝可梦,每次都能变得更强。$@c{neutral}事实上,我……几乎不认识自己了。$现在,我终于达到了巅峰。\n我感觉我已经战无不胜了。$而且你知道吗?这一切都是因为你。$@c{smile_ehalf}我不知道到底是该感谢你还是恨你。$@c{angry_mopen}做好准备…", }, "victory": { - 1: "@c{neutral}What…@d{64} What are you?" - + 1: "@c{neutral}你…@d{64} 你是人吗?", }, "defeat": { - 1: "$@c{smile}You should be proud of how far you made it." + 1: "@c{smile}你应该为自己走了这么远感到骄傲。", } }, "rival_5": { @@ -2254,46 +2102,18 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rival_6": { "encounter": { - 1: `@c{smile_eclosed}We meet again. - $@c{neutral}I've had some time to reflect on all this.\nThere's a reason this all seems so strange. - $@c{neutral_eclosed}Your dream, my drive to beat you…\nIt's all a part of something greater. - $@c{serious}This isn't about me, or about you… This is about the world, @c{serious_mhalf_fists}and it's my purpose to push you to your limits. - $@c{neutral_eclosed}Whether I've fulfilled that purpose I can't say, but I've done everything in my power. - $@c{neutral}This place we ended up in is terrifying… Yet somehow I feel unphased, like I've been here before. - $@c{serious_mhalf_fists}You feel the same, don't you? - $@c{serious}…and it's like something here is speaking to me.\nThis is all the world's known for a long time now. - $Those times we cherished together that seem so recent are nothing but a distant memory. - $@c{neutral_eclosed}Who can say whether they were ever even real in the first place. - $@c{serious_mopen_fists}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. - $@c{serious_smile_fists}I hardly know what any of this means, I just know that it's true. - $@c{serious_mopen_fists}If you can't defeat me here and now, you won't stand a chance.` + 1: "@c{smile_eclosed}又见面了。$@c{neutral}我花了点时间思考反思\n有理由说明为什么这一切都显得如此奇妙。$@c{neutral_eclosed}你所追逐的梦想,我想击败你的决心…$这都是某种庞大使命的一部分。$@c{serious}这不仅仅是关于我和你… 而是关于这个世界, @c{serious_mhalf_fists}我的使命就是将你推向极限。$@c{neutral_eclosed}我是否达成了那个使命,我说不上来,但我已尽我所能。$@c{neutral}我们最终到达的这个地方看起来很可怕\n 然而不知何故,我心中毫无畏惧,好像我早就来过这里。$@c{serious_mhalf_fists}你也有同样的感觉,对吧?$@c{serious}……这里好像有什么东西在呼唤我。\n这是世界早已记录的一切。$那些我们经历过的时光,那些记忆犹新的过去,\n其实只是遥远的回忆。$@c{neutral_eclosed}谁能保证它们是否真的发生过。$@c{serious_mopen_fists}你必须继续前进,不然的话,这一切将永无止境。\n这件事而只有你能办成。$@c{serious_smile_fists}我不清楚这一切意味着什么,但我知道……$@c{serious_mopen_fists}如果现在你不能就此击败我,\n你将毫无机会可言。", }, "victory": { - 1: `@c{smile_eclosed}It looks like my work is done here. - $I want you to promise me one thing.\n@c{smile}After you heal the world, please come home.` + 1: "@c{smile_eclosed}看来我的使命在这里已经完成了。\n我想让你答应我一件事。$@c{smile}在你拯救世界之后,要回家。", }, }, "rival_6_female": { "encounter": { - 1: `@c{smile_ehalf}So it's just us again. - $@c{smile_eclosed}You know, I keep going around and around in my head… - $@c{smile_ehalf}There's something to all this, why everything seems so strange now… - $@c{smile}You have your dream, and I have this ambition in me… - $I just can't help but feel there's a greater purpose to all this, to what we're doing, you and I. - $@c{smile_eclosed}I think I'm supposed to push you… to your limits. - $@c{smile_ehalf}I'm not sure if I've been doing a good job at that, but I've tried my best up to now. - $It's something about this strange and dreadful place… Everything seems so clear… - $This… is all the world's known for a long time now. - $@c{smile_eclosed}It's like I can barely remember the memories we cherished together. - $@c{smile_ehalf}Were they even real? They seem so far away now… - $@c{angry_mopen}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. - $@c{smile_ehalf}I… don't know what all this means… but I feel it's true. - $@c{neutral}If you can't defeat me here and now, you won't stand a chance.` + 1: "@c{smile_ehalf}又只有我们两个人了。$@c{smile_eclosed}你知道吗,我在心里想啊想,\n想了好久……$@c{smile_ehalf}这一切背后是有什么原因吗,\n为什么一切现在看起来都这么奇怪……$@c{smile}你有你的梦想,而我内心有这个抱负……$我不禁感觉这一切背后有一个更庞大的力量,$掌控者我们所做的一切,你和我之间。$@c{smile_eclosed}}我想我注定要推动你……到你的极限。$@c{smile_ehalf}我不清楚我是否一直做得很好,\n但到现在为止,我已经尽力了。$这个奇怪而可怕的地方……\n一切看起来都那么清晰……$这是世界早已记录的一切。$@c{smile_eclosed}我好像记不清我们一起度过的日子了。$@c{smile_ehalf}那些回忆到底是真的吗?\n怎么感觉这么久远……$@c{angry_mopen}你得继续前进,不然的话,这一切将永无止境。\n你是唯一能做到这件事的。$@c{smile_ehalf}}我……不知道这一切意味着什么……\n但我明白$@c{neutral}如果你现在不能就此击败我,\n你将毫无机会可言。", }, "victory": { - 1: `@c{smile_ehalf}I… I think I fulfilled my purpose… - $@c{smile_eclosed}Promise me… After you heal the world… Please… come home safe. - $@c{smile_ehalf}…Thank you.` + 1: "@c{smile_ehalf}我……\n我想我完成了我的使命……$@c{smile_eclosed}答应我……在你拯救世界之后\n……要……平安到家。$@c{smile_ehalf}……谢谢你。", }, }, @@ -2305,17 +2125,17 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; // Dialogue of the endboss of the game when the player character is male (Or unset) export const PGMbattleSpecDialogue: SimpleTranslationEntries = { - "encounter": `It appears the time has finally come once again.\nYou know why you have come here, do you not? - $You were drawn here, because you have been here before.\nCountless times. - $Though, perhaps it can be counted.\nTo be precise, this is in fact your 5,643,853rd cycle. - $Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain. - $Until now you have yet to succeed, but I sense a different presence in you this time.\n - $You are the only one here, though it is as if there is… another. - $Will you finally prove a formidable challenge to me?\nThe challenge I have longed for for millennia? - $We begin.`, - "firstStageWin": `I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back. - $Do not disappoint me.`, - "secondStageWin": "…Magnificent." + "encounter": `看来终于又到了那个时候。\n你知道自己为何会来到这里,不是吗? + $你被吸引到这里,因为你以前就来过这里。\n无数次。 + $尽管,或许可以数一数。\n准确地说,这实际上是你的第5,643,853次循环。 + $每一次循环,你的思想都会恢复到之前的状态。\n即便如此,不知何故,你之前自我的残留仍然存在。 + $直到现在,你仍未成功,但我感觉这次你身上有一种异样的气息。\n + $你是这里唯一的人,尽管感觉上还有……另一个人。 + $你最终会成为对我来的一个硬茬吗?\n我渴望了数千年的挑战? + $我们,开始。`, + "firstStageWin": `我明白了。我所感觉到的气息确实是真实的。\n看来我不再需要保留实力了。 + $别让我失望。`, + "secondStageWin": "…漂亮。" }; // Dialogue of the endboss of the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMbattleSpecDialogue. @@ -2324,21 +2144,21 @@ export const PGFbattleSpecDialogue: SimpleTranslationEntries = PGMbattleSpecDial // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is male export const PGMmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. - $@c{smile}It's over.@d{64} You ended the loop. - $@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once. - $@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it? - $@c{serious_smile_fists}Your legend will always live on in our hearts. - $@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home. - $@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.`, + `@c{smile}哦?你赢了?@d{96} @c{smile_eclosed}我应该早猜到了\n你回来了。 + $@c{smile}结束了。@d{64} 你终结了这个循环。 + $@c{serious_smile_fists}你也完成了自己的梦想,不是吗?\n你甚至一次都没失败。 + $@c{neutral}我是唯一能够记得你所作所为的人@d{96}\n我觉得这应该也还行吧? + $@c{serious_smile_fists}你的传奇将永远留存于我们心中。 + $@c{smile_eclosed}不管了,我真是受够这个地方了,你也一样吗?我们回家吧。 + $@c{serious_smile_fists}可能等我们回家以后,再打一场?\n要是你想的话`, "ending_female": - `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. - $@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop. - $@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once. - $I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget! - $@c{smile_wave_wink}Just kidding!@d{64} @c{smile}I'd never forget.@d{32}\nYour legend will live on in our hearts. - $@c{smile_wave}Anyway,@d{64} it's getting late…@d{96} I think?\nIt's hard to tell in this place. - $Let's go home. @c{smile_wave_wink}Maybe tomorrow, we can have another battle, for old time's sake?`, + `@c{shock}你回来了?@d{32} 也就是说…@d{96} 你赢了呀!?\n@c{smile_ehalf}我应该早料到了。 + $@c{smile_eclosed}当然…我一直有这种感觉\n@c{smile}一切都结束了,对么? 你打破了循环。 + $@c{smile_ehalf}你也完成了自己的梦想,不是吗?\n你甚至一次都没失败。 + $我是唯一能够记得你所作所为的人\n@c{angry_mopen}我会努力不忘掉哒! + $@c{smile_wave_wink}开玩笑啦,@d{64} @c{smile}我才不会忘呢。@d{32}\n你的传奇将永远留存于我们心中。 + $@c{smile_wave}不管了,@d{64} 时候不早了@d{96} ,应该吧?\n在这地方还真搞不清楚。 + $一起回家吧。 @c{smile_wave_wink}可能明天,我们再来打一场,为了重温回忆嘛~`, }; // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMmiscDialogue. export const PGFmiscDialogue: SimpleTranslationEntries = PGMmiscDialogue; @@ -2348,113 +2168,82 @@ export const PGFmiscDialogue: SimpleTranslationEntries = PGMmiscDialogue; export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { "blue_red_double": { "encounter": { - 1: `Blue: Hey Red, let's show them what we're made of! - $Red: ... - $Blue: This is Pallet Town Power!`, + 1: "青绿:嘿,赤红,\n让这家伙看看我们是什么来头!$赤红: ...$青绿: 见识下真新镇的实力!", }, "victory": { - 1: `Blue: That was a great battle! - $Red: ...`, + 1: "青绿:打得真不错$赤红: ...", }, }, "red_blue_double": { "encounter": { - 1: `Red: ...! - $Blue: He never talks much. - $Blue: But dont let that fool you! He is a champ after all!`, + 1: "赤红: ...!$青绿: 他人狠话不多。$青绿: 但别被他耍了,\n毕竟他可是个冠军!", }, "victory": { - 1: `Red: ...! - $Blue: Next time we will beat you!`, + 1: "赤红: ...!$青绿: 下次我们一定会赢你!", }, }, "tate_liza_double": { "encounter": { - 1: `Tate: Are you suprised? - $Liza: We are two gym leaders at once! - $Tate: We are twins! - $Liza: We dont need to talk to understand each other! - $Tate: Twice the power... - $Liza: Can you handle it?`, + 1: "小枫:嘿嘿嘿……你惊讶吗?$小南: 这里有两个道馆馆主?$小枫: 我们是双胞胎!$小南: 我们无需交谈,因为……$我们可以通晓彼此的想法$小枫: 我们的组合……$小南: 你能打败吗?", }, "victory": { - 1: `Tate: What? Our combination was perfect! - $Liza: Looks like we need to train more...`, + 1: "小枫:什么?我们的组合……$小南:被瓦解了!", }, }, "liza_tate_double": { "encounter": { - 1: `Liza: Hihihi... Are you suprised? - $Tate: Yes, we are really two gym leaders at once! - $Liza: This is my twin brother Tate! - $Tate: And this is my twin sister Liza! - $Liza: Don't you think we are a perfect combination?` + 1: "小南:呵呵呵……你惊讶吧?$小枫:这里有两个道馆馆主?$小南:我们可以通晓……$小枫:彼此的想法……$小南:全在我们脑中!$小枫:我们的组合……$小南:你能打败吗?", }, "victory": { - 1: `Liza: Are we... - $Tate: ...not as strong as we thought?`, + 1: "小枫:你和你的宝可梦……$小南:简直像亲兄弟姐妹!", }, }, "wallace_steven_double": { "encounter": { - 1: `Steven: Wallace, let's show them the power of the champions! - $Wallace: We will show you the power of Hoenn! - $Steven: Let's go!`, + 1: "大吾:米可利, 展现冠军的实力吧!$米可利:我们将展示丰缘的实力!$大吾:要上了!", }, "victory": { - 1: `Steven: That was a great battle! - $Wallace: We will win next time!`, + 1: "大吾:打得真不错!$米可利:我们下次会赢的!", }, }, "steven_wallace_double": { "encounter": { - 1: `Steven: Do you have any rare pokémon? - $Wallace: Steven... We are here for a battle, not to show off our pokémon. - $Steven: Oh... I see... Let's go then!`, + 1: "大吾:你有什么稀有的宝可梦吗?$米可利:大吾……我们是来对战的,\n不是来炫耀宝可梦的。$大吾:哦……知道了… 那么要上了!", }, "victory": { - 1: `Steven: Now that we are done with the battle, let's show off our pokémon! - $Wallace: Steven...`, + 1: "大吾:战斗结束了,\n来看看我的稀有宝可梦!$米可利:大吾……", }, }, "alder_iris_double": { "encounter": { - 1: `Alder: We are the strongest trainers in Unova! - $Iris: Fights against strong trainers are the best!`, + 1: "阿戴克:我们俩是合众最强的训练家!$艾莉丝:与最强来一场最激烈的战斗吧!", }, "victory": { - 1: `Alder: Wow! You are super strong! - $Iris: We will win next time!`, + 1: "阿戴克:哇哦!你真是超级厉害!$艾莉丝:我们下次会赢的啦!", }, }, "iris_alder_double": { "encounter": { - 1: `Iris: Welcome Challenger! I am THE Unova Champion! - $Alder: Iris, aren't you a bit too excited?`, + 1: "艾莉丝:欢迎!挑战者,\n合众地区最强的冠军大驾光临!$阿戴克:艾莉丝,你是不是有点太兴奋了…", }, "victory": { - 1: `Iris: A loss like this is not easy to take... - $Alder: But we will only get stronger with every loss!`, + 1: "艾莉丝:这样的失败可不好受啊…$阿戴克:但是只有失败才能让我们变强!", }, }, "piers_marnie_double": { "encounter": { - 1: `Marnie: Brother, let's show them the power of Spikemuth! - $Piers: We bring darkness!`, + 1: "玛俐:哥哥,给他们展现尖钉镇的实力!$聂梓:我们带来黑暗!", }, "victory": { - 1: `Marnie: You brought light to our darkness! - $Piers: Its too bright...`, + 1: "玛俐:你的强光亮瞎我们的黑暗了啦……$聂梓:实在太亮了…", }, }, "marnie_piers_double": { "encounter": { - 1: `Piers: Ready for a concert? - $Marnie: Brother... They are here to fight, not to sing...`, + 1: "聂梓: 台下准备好了吗!$玛俐: 哥哥,我们是来对战的,\n不是来唱歌的……", }, "victory": { - 1: `Piers: Now that was a great concert! - $Marnie: Brother...`, + 1: "聂梓:这首歌献给大家!$玛俐:哥哥……", }, }, }; diff --git a/src/locales/zh_CN/game-mode.ts b/src/locales/zh_CN/game-mode.ts new file mode 100644 index 00000000000..be342b4c390 --- /dev/null +++ b/src/locales/zh_CN/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classic", + "endless": "Endless", + "endlessSpliced": "Endless (Spliced)", + "dailyRun": "Daily Run", + "unknown": "Unknown", + "challenge": "Challenge", +} as const; diff --git a/src/locales/zh_CN/menu.ts b/src/locales/zh_CN/menu.ts index d8cad6b05af..39d8e5e3a04 100644 --- a/src/locales/zh_CN/menu.ts +++ b/src/locales/zh_CN/menu.ts @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "每周排名", "noRankings": "无排名", "loading": "加载中...", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "在线玩家", - "empty": "空", "yes": "是", "no": "否", "disclaimer": "DISCLAIMER", diff --git a/src/locales/zh_CN/modifier-type.ts b/src/locales/zh_CN/modifier-type.ts index f07a464f539..92617e39741 100644 --- a/src/locales/zh_CN/modifier-type.ts +++ b/src/locales/zh_CN/modifier-type.ts @@ -4,11 +4,11 @@ export const modifierType: ModifierTypeTranslationEntries = { ModifierType: { "AddPokeballModifierType": { name: "{{modifierCount}}x {{pokeballName}}", - description: "获得 {{pokeballName}} x{{modifierCount}} (已有:{{pokeballAmount}}) \n捕捉倍率:{{catchRate}}", + description: "获得 {{pokeballName}} x{{modifierCount}} (已有:{{pokeballAmount}}) \n捕捉倍率:{{catchRate}}。", }, "AddVoucherModifierType": { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "获得 {{voucherTypeName}} x{{modifierCount}}", + description: "获得 {{voucherTypeName}} x{{modifierCount}}。", }, "PokemonHeldItemModifierType": { extra: { @@ -17,63 +17,63 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonHpRestoreModifierType": { - description: "为一只宝可梦回复 {{restorePoints}} HP 或 {{restorePercent}}% HP,取较大值", + description: "为一只宝可梦回复 {{restorePoints}} HP 或 {{restorePercent}}% HP,取较大值。", extra: { - "fully": "为一只宝可梦回复全部HP", - "fullyWithStatus": "为一只宝可梦回复全部HP并消除所有负面\n状态", + "fully": "为一只宝可梦回复全部HP。", + "fullyWithStatus": "为一只宝可梦回复全部HP并消除所有负面\n状态。", } }, "PokemonReviveModifierType": { - description: "复活一只宝可梦并回复 {{restorePercent}}% HP", + description: "复活一只宝可梦并回复 {{restorePercent}}% HP。", }, "PokemonStatusHealModifierType": { - description: "为一只宝可梦消除所有负面状态", + description: "为一只宝可梦消除所有负面状态。", }, "PokemonPpRestoreModifierType": { - description: "为一只宝可梦的一个招式回复 {{restorePoints}} PP", + description: "为一只宝可梦的一个招式回复 {{restorePoints}} PP。", extra: { - "fully": "完全回复一只宝可梦一个招式的PP", + "fully": "完全回复一只宝可梦一个招式的PP。", } }, "PokemonAllMovePpRestoreModifierType": { - description: "为一只宝可梦的所有招式回复 {{restorePoints}} PP", + description: "为一只宝可梦的所有招式回复 {{restorePoints}} PP。", extra: { - "fully": "为一只宝可梦的所有招式回复所有PP", + "fully": "为一只宝可梦的所有招式回复所有PP。", } }, "PokemonPpUpModifierType": { - description: "为一只宝可梦的一个招式永久增加{{upPoints}}点\nPP每5点当前最大PP (最多3点)", + description: "为一只宝可梦的一个招式永久增加{{upPoints}}点\nPP每5点当前最大PP (最多3点)。", }, "PokemonNatureChangeModifierType": { name: "{{natureName}}薄荷", - description: "将一只宝可梦的性格改为{{natureName}}并为该宝可\n梦永久解锁该性格.", + description: "将一只宝可梦的性格改为{{natureName}}并为该宝可\n梦永久解锁该性格。", }, "DoubleBattleChanceBoosterModifierType": { - description: "接下来的{{battleCount}}场战斗是双打的概率翻倍", + description: "接下来的{{battleCount}}场战斗是双打的概率翻倍。", }, "TempBattleStatBoosterModifierType": { - description: "为所有成员宝可梦提升一级{{tempBattleStatName}},持续5场战斗", + description: "为所有成员宝可梦提升一级{{tempBattleStatName}},持续5场战斗。", }, "AttackTypeBoosterModifierType": { - description: "一只宝可梦的{{moveType}}系招式威力提升20%", + description: "一只宝可梦的{{moveType}}系招式威力提升20%。", }, "PokemonLevelIncrementModifierType": { - description: "一只宝可梦等级提升1级", + description: "一只宝可梦等级提升1级。", }, "AllPokemonLevelIncrementModifierType": { - description: "所有成员宝可梦等级提升1级", + description: "所有成员宝可梦等级提升1级。", }, "PokemonBaseStatBoosterModifierType": { - description: "增加持有者的{{statName}}10%,个体值越高堆叠\n上限越高.", + description: "增加持有者的{{statName}}10%,个体值越高堆叠\n上限越高。", }, "AllPokemonFullHpRestoreModifierType": { - description: "所有宝可梦完全回复HP", + description: "所有宝可梦完全回复HP。", }, "AllPokemonFullReviveModifierType": { - description: "复活所有濒死宝可梦,完全回复HP", + description: "复活所有濒死宝可梦,完全回复HP。", }, "MoneyRewardModifierType": { - description: "获得{{moneyMultiplier}}金钱 (₽{{moneyAmount}})", + description: "获得{{moneyMultiplier}}金钱 (₽{{moneyAmount}})。", extra: { "small": "少量", "moderate": "中等", @@ -81,62 +81,62 @@ export const modifierType: ModifierTypeTranslationEntries = { }, }, "ExpBoosterModifierType": { - description: "经验值获取量增加{{boostPercent}}%", + description: "经验值获取量增加{{boostPercent}}%。", }, "PokemonExpBoosterModifierType": { - description: "持有者经验值获取量增加{{boostPercent}}%", + description: "持有者经验值获取量增加{{boostPercent}}%。", }, "PokemonFriendshipBoosterModifierType": { - description: "每场战斗获得的好感度提升50%", + description: "每场战斗获得的好感度提升50%。", }, "PokemonMoveAccuracyBoosterModifierType": { - description: "招式命中率增加{{accuracyAmount}} (最大100)", + description: "招式命中率增加{{accuracyAmount}} (最大100)。", }, "PokemonMultiHitModifierType": { - description: "攻击造成一次额外伤害,每次堆叠额外伤害\n分别衰减60/75/82.5%", + description: "攻击造成一次额外伤害,每次堆叠额外伤害\n分别衰减60/75/82.5%。", }, "TmModifierType": { name: "招式学习器 {{moveId}} - {{moveName}}", - description: "教会一只宝可梦{{moveName}}", + description: "教会一只宝可梦{{moveName}}。", }, "TmModifierTypeWithInfo": { name: "招式学习器 {{moveId}} - {{moveName}}", - description: "教会一只宝可梦{{moveName}}\n(Hold C or Shift for more info)", + description: "教会一只宝可梦{{moveName}}\n(Hold C or Shift for more info)。", }, "EvolutionItemModifierType": { - description: "使某些宝可梦进化", + description: "使某些宝可梦进化。", }, "FormChangeItemModifierType": { - description: "使某些宝可梦更改形态", + description: "使某些宝可梦更改形态。", }, "FusePokemonModifierType": { - description: "融合两只宝可梦 (改变特性, 平分基础点数\n和属性, 共享招式池)", + description: "融合两只宝可梦 (改变特性, 平分基础点数\n和属性, 共享招式池)。", }, "TerastallizeModifierType": { name: "{{teraType}}太晶碎块", - description: "持有者获得{{teraType}}太晶化10场战斗", + description: "持有者获得{{teraType}}太晶化10场战斗。", }, "ContactHeldItemTransferChanceModifierType": { - description: "攻击时{{chancePercent}}%概率偷取对手物品", + description: "攻击时{{chancePercent}}%概率偷取对手物品。", }, "TurnHeldItemTransferModifierType": { - description: "持有者每回合从对手那里获得一个持有的物品", + description: "持有者每回合从对手那里获得一个持有的物品。", }, "EnemyAttackStatusEffectChanceModifierType": { - description: "攻击时{{chancePercent}}%概率造成{{statusEffect}}", + description: "攻击时{{chancePercent}}%概率造成{{statusEffect}}。", }, "EnemyEndureChanceModifierType": { - description: "增加{{chancePercent}}%遭受攻击的概率", + description: "增加{{chancePercent}}%遭受攻击的概率。", }, "RARE_CANDY": { name: "神奇糖果" }, "RARER_CANDY": { name: "超神奇糖果" }, - "MEGA_BRACELET": { name: "超级手镯", description: "能让携带着超级石战斗的宝可梦进行\n超级进化" }, - "DYNAMAX_BAND": { name: "极巨腕带", description: "能让携带着极巨菇菇战斗的宝可梦进行\n极巨化" }, - "TERA_ORB": { name: "太晶珠", description: "能让携带着太晶碎块战斗的宝可梦进行\n太晶化" }, + "MEGA_BRACELET": { name: "超级手镯", description: "能让携带着超级石战斗的宝可梦进行\n超级进化。" }, + "DYNAMAX_BAND": { name: "极巨腕带", description: "能让携带着极巨菇菇战斗的宝可梦进行\n极巨化。" }, + "TERA_ORB": { name: "太晶珠", description: "能让携带着太晶碎块战斗的宝可梦进行\n太晶化。" }, - "MAP": { name: "地图", description: "允许你在切换宝可梦群落时选择目的地"}, + "MAP": { name: "地图", description: "允许你在切换宝可梦群落时选择目的地。"}, "POTION": { name: "伤药" }, "SUPER_POTION": { name: "好伤药" }, @@ -151,7 +151,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "圣灰" }, - "REVIVER_SEED": { name: "复活种子", description: "恢复1只濒死宝可梦的HP至1/2" }, + "REVIVER_SEED": { name: "复活种子", description: "恢复1只濒死宝可梦的HP至1/2。" }, "ETHER": { name: "PP单项小补剂" }, "MAX_ETHER": { name: "PP单项全补剂" }, @@ -166,12 +166,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SUPER_LURE": { name: "白银香水" }, "MAX_LURE": { name: "黄金香水" }, - "MEMORY_MUSHROOM": { name: "回忆蘑菇", description: "回忆一个宝可梦已经遗忘的招式" }, + "MEMORY_MUSHROOM": { name: "回忆蘑菇", description: "回忆一个宝可梦已经遗忘的招式。" }, - "EXP_SHARE": { name: "学习装置", description: "未参加对战的宝可梦获得20%的经验值" }, - "EXP_BALANCE": { name: "均衡型学习装置", description: "队伍中的低级宝可梦获得更多经验值" }, + "EXP_SHARE": { name: "学习装置", description: "未参加对战的宝可梦获得20%的经验值。" }, + "EXP_BALANCE": { name: "均衡型学习装置", description: "队伍中的低级宝可梦获得更多经验值。" }, - "OVAL_CHARM": { name: "圆形护符", description: "当多只宝可梦参与战斗,分别获得总经验值\n10%的额外经验值" }, + "OVAL_CHARM": { name: "圆形护符", description: "当多只宝可梦参与战斗,分别获得总经验值\n10%的额外经验值。" }, "EXP_CHARM": { name: "经验护符" }, "SUPER_EXP_CHARM": { name: "超级经验护符" }, @@ -182,62 +182,62 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "安抚之铃" }, - "SOUL_DEW": { name: "心之水滴", description: "增加宝可梦性格影响10% (加算)" }, + "SOUL_DEW": { name: "心之水滴", description: "增加宝可梦性格影响10% (加算)。" }, "NUGGET": { name: "金珠" }, "BIG_NUGGET": { name: "巨大金珠" }, "RELIC_GOLD": { name: "古代金币" }, - "AMULET_COIN": { name: "护符金币", description: "金钱奖励增加20%" }, - "GOLDEN_PUNCH": { name: "黄金拳头", description: "将50%造成的伤害转换为金钱" }, - "COIN_CASE": { name: "代币盒", description: "每十场战斗, 获得自己金钱10%的利息" }, + "AMULET_COIN": { name: "护符金币", description: "金钱奖励增加20%。" }, + "GOLDEN_PUNCH": { name: "黄金拳头", description: "将50%造成的伤害转换为金钱。" }, + "COIN_CASE": { name: "代币盒", description: "每十场战斗, 获得自己金钱10%的利息。" }, - "LOCK_CAPSULE": { name: "上锁的容器", description: "允许在刷新物品时锁定物品稀有度" }, + "LOCK_CAPSULE": { name: "上锁的容器", description: "允许在刷新物品时锁定物品稀有度。" }, "GRIP_CLAW": { name: "紧缠钩爪" }, "WIDE_LENS": { name: "广角镜" }, "MULTI_LENS": { name: "多重镜" }, - "HEALING_CHARM": { name: "治愈护符", description: "HP回复量增加10% (不含复活)" }, - "CANDY_JAR": { name: "糖果罐", description: "神奇糖果提供的升级额外增加1级" }, + "HEALING_CHARM": { name: "治愈护符", description: "HP回复量增加10% (不含复活)。" }, + "CANDY_JAR": { name: "糖果罐", description: "神奇糖果提供的升级额外增加1级。" }, - "BERRY_POUCH": { name: "树果袋", description: "使用树果时有30%的几率不会消耗树果" }, + "BERRY_POUCH": { name: "树果袋", description: "使用树果时有30%的几率不会消耗树果。" }, - "FOCUS_BAND": { name: "气势头带", description: "携带该道具的宝可梦有10%几率在受到\n攻击而将陷入濒死状态时,保留1点HP不陷入濒死状态" }, + "FOCUS_BAND": { name: "气势头带", description: "携带该道具的宝可梦有10%几率在受到\n攻击而将陷入濒死状态时,保留1点HP不陷入濒死状态。" }, - "QUICK_CLAW": { name: "先制之爪", description: "有10%的几率无视速度优先使出招式\n(先制技能优先)" }, + "QUICK_CLAW": { name: "先制之爪", description: "有10%的几率无视速度优先使出招式\n(先制技能优先)。" }, - "KINGS_ROCK": { name: "王者之证", description: "携带该道具的宝可梦使用任意原本不会造成\n畏缩状态的攻击招式并造成伤害时,有\n10%几率使目标陷入畏缩状态" }, + "KINGS_ROCK": { name: "王者之证", description: "携带该道具的宝可梦使用任意原本不会造成\n畏缩状态的攻击招式并造成伤害时,有\n10%几率使目标陷入畏缩状态。" }, - "LEFTOVERS": { name: "吃剩的东西", description: "携带该道具的宝可梦在每个回合结束时恢复\n最大HP的1/16" }, - "SHELL_BELL": { name: "贝壳之铃", description: "携带该道具的宝可梦在攻击对方成功造成伤\n害时,携带者的HP会恢复其所造成伤害\n的1/8" }, + "LEFTOVERS": { name: "吃剩的东西", description: "携带该道具的宝可梦在每个回合结束时恢复\n最大HP的1/16。" }, + "SHELL_BELL": { name: "贝壳之铃", description: "携带该道具的宝可梦在攻击对方成功造成伤\n害时,携带者的HP会恢复其所造成伤害\n的1/8。" }, - "TOXIC_ORB": { name: "Toxic Orb", description: "It's a bizarre orb that exudes toxins when touched and will badly poison the holder during battle" }, - "FLAME_ORB": { name: "Flame Orb", description: "It's a bizarre orb that gives off heat when touched and will affect the holder with a burn during battle" }, + "TOXIC_ORB": { name: "Toxic Orb", description: "触碰后会放出毒的神奇宝珠。携带后,在战斗时会变成剧毒状态。" }, + "FLAME_ORB": { name: "Flame Orb", description: "触碰后会放出热量的神奇宝珠。携带后,在战斗时会变成灼伤状态。" }, - "BATON": { name: "接力棒", description: "允许在切换宝可梦时保留能力变化, 对陷阱\n同样生效" }, + "BATON": { name: "接力棒", description: "允许在切换宝可梦时保留能力变化, 对陷阱\n同样生效。" }, - "SHINY_CHARM": { name: "闪耀护符", description: "显著增加野生宝可梦的闪光概率" }, - "ABILITY_CHARM": { name: "特性护符", description: "显著增加野生宝可梦有隐藏特性的概率" }, + "SHINY_CHARM": { name: "闪耀护符", description: "显著增加野生宝可梦的闪光概率。" }, + "ABILITY_CHARM": { name: "特性护符", description: "显著增加野生宝可梦有隐藏特性的概率。" }, - "IV_SCANNER": { name: "个体值探测器", description: "允许扫描野生宝可梦的个体值。可叠加,每多拥有一个多显示\n2项个体值. 最好的个体值优先显示" }, + "IV_SCANNER": { name: "个体值探测器", description: "允许扫描野生宝可梦的个体值。可叠加,每多拥有一个多显示\n2项个体值. 最好的个体值优先显示。" }, "DNA_SPLICERS": { name: "基因之楔" }, "MINI_BLACK_HOLE": { name: "迷你黑洞" }, - "GOLDEN_POKEBALL": { name: "黄金精灵球", description: "在每场战斗结束后增加一个额外物品选项" }, + "GOLDEN_POKEBALL": { name: "黄金精灵球", description: "在每场战斗结束后增加一个额外物品选项。" }, - "ENEMY_DAMAGE_BOOSTER": { name: "伤害硬币", description: "增加5%造成伤害" }, - "ENEMY_DAMAGE_REDUCTION": { name: "防御硬币", description: "减少2.5%承受伤害" }, - "ENEMY_HEAL": { name: "回复硬币", description: "每回合回复2%最大HP" }, + "ENEMY_DAMAGE_BOOSTER": { name: "伤害硬币", description: "增加5%造成伤害。" }, + "ENEMY_DAMAGE_REDUCTION": { name: "防御硬币", description: "减少2.5%承受伤害。" }, + "ENEMY_HEAL": { name: "回复硬币", description: "每回合回复2%最大HP。" }, "ENEMY_ATTACK_POISON_CHANCE": { name: "剧毒硬币" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "麻痹硬币" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "灼烧硬币" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "万灵药硬币", description: "增加2.5%每回合治愈异常状态的概率" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "万灵药硬币", description: "增加2.5%每回合治愈异常状态的概率。" }, "ENEMY_ENDURE_CHANCE": { name: "忍受硬币" }, - "ENEMY_FUSED_CHANCE": { name: "融合硬币", description: "增加1%野生融合宝可梦出现概率" }, + "ENEMY_FUSED_CHANCE": { name: "融合硬币", description: "增加1%野生融合宝可梦出现概率。" }, }, TempBattleStatBoosterItem: { "x_attack": "力量强化", @@ -388,5 +388,43 @@ export const modifierType: ModifierTypeTranslationEntries = { "BURN_DRIVE": "火焰卡带", "CHILL_DRIVE": "冰冻卡带", "DOUSE_DRIVE": "水流卡带", + + "FIST_PLATE": "拳头石板", + "SKY_PLATE": "蓝天石板", + "TOXIC_PLATE": "剧毒石板", + "EARTH_PLATE": "大地石板", + "STONE_PLATE": "岩石石板", + "INSECT_PLATE": "玉虫石板", + "SPOOKY_PLATE": "妖怪石板", + "IRON_PLATE": "钢铁石板", + "FLAME_PLATE": "火球石板", + "SPLASH_PLATE": "水滴石板", + "MEADOW_PLATE": "碧绿石板", + "ZAP_PLATE": "雷电石板", + "MIND_PLATE": "神奇石板", + "ICICLE_PLATE": "冰柱石板", + "DRACO_PLATE": "龙之石板", + "DREAD_PLATE": "恶颜石板", + "PIXIE_PLATE": "妖精石板", + "BLANK_PLATE": "净空石板", + "LEGEND_PLATE": "传说石板", + "FIGHTING_MEMORY": "战斗存储碟", + "FLYING_MEMORY": "飞翔存储碟", + "POISON_MEMORY": "毒存储碟", + "GROUND_MEMORY": "大地存储碟", + "ROCK_MEMORY": "岩石存储碟", + "BUG_MEMORY": "虫子存储碟", + "GHOST_MEMORY": "幽灵存储碟", + "STEEL_MEMORY": "钢铁存储碟", + "FIRE_MEMORY": "火焰存储碟", + "WATER_MEMORY": "清水存储碟", + "GRASS_MEMORY": "青草存储碟", + "ELECTRIC_MEMORY": "电子存储碟", + "PSYCHIC_MEMORY": "精神存储碟", + "ICE_MEMORY": "冰雪存储碟", + "DRAGON_MEMORY": "龙存储碟", + "DARK_MEMORY": "黑暗存储碟", + "FAIRY_MEMORY": "妖精存储碟", + "BLANK_MEMORY": "空白存储碟", }, } as const; diff --git a/src/locales/zh_CN/party-ui-handler.ts b/src/locales/zh_CN/party-ui-handler.ts index 9d3c7baa9ae..6f4f4f4c88a 100644 --- a/src/locales/zh_CN/party-ui-handler.ts +++ b/src/locales/zh_CN/party-ui-handler.ts @@ -1,10 +1,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const partyUiHandler: SimpleTranslationEntries = { - "SEND_OUT": "Send Out", - "SUMMARY": "Summary", - "CANCEL": "Cancel", - "RELEASE": "Release", - "APPLY": "Apply", - "TEACH": "Teach" + "SEND_OUT": "上场", + "SUMMARY": "概要", + "CANCEL": "取消", + "RELEASE": "放生", + "APPLY": "应用", + "TEACH": "教授" } as const; diff --git a/src/locales/zh_CN/save-slot-select-ui-handler.ts b/src/locales/zh_CN/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..0d657235e49 --- /dev/null +++ b/src/locales/zh_CN/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Overwrite the data in the selected slot?", + "loading": "正在加载中...", + "wave": "Wave", + "lv": "Lv", + "empty": "空", +} as const; diff --git a/src/locales/zh_CN/starter-select-ui-handler.ts b/src/locales/zh_CN/starter-select-ui-handler.ts index 9491438bb13..803e64e0439 100644 --- a/src/locales/zh_CN/starter-select-ui-handler.ts +++ b/src/locales/zh_CN/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "选择要替换成的招式", "unlockPassive": "解锁被动", "reduceCost": "降低花费", - "cycleShiny": "R: 切换闪光", - "cycleForm": "F: 切换形态", - "cycleGender": "G: 切换性别", - "cycleAbility": "E: 切换特性", - "cycleNature": "N: 切换性格", - "cycleVariant": "V: 切换变种", + "cycleShiny": ": 闪光", + "cycleForm": ": 形态", + "cycleGender": ": 性别", + "cycleAbility": ": 特性", + "cycleNature": ": 性格", + "cycleVariant": ": 变种", "enablePassive": "启用被动", "disablePassive": "禁用被动", "locked": "未解锁", diff --git a/src/locales/zh_TW/achv.ts b/src/locales/zh_TW/achv.ts index 42b1995bcde..bf1bfc295e8 100644 --- a/src/locales/zh_TW/achv.ts +++ b/src/locales/zh_TW/achv.ts @@ -1,6 +1,7 @@ import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; -export const achv: AchievementTranslationEntries = { +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { "Achievements": { name: "Achievements", }, @@ -168,4 +169,102 @@ export const achv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Mono NORMAL", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Mono FLYING", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Mono GROUND", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "Sting Like A Beedrill", + }, + "MONO_GHOST": { + name: "Who you gonna call?", + }, + "MONO_STEEL": { + name: "Mono STEEL", + }, + "MONO_FIRE": { + name: "Mono FIRE", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Mono GRASS", + }, + "MONO_ELECTRIC": { + name: "Mono ELECTRIC", + }, + "MONO_PSYCHIC": { + name: "Mono PSYCHIC", + }, + "MONO_ICE": { + name: "Mono ICE", + }, + "MONO_DRAGON": { + name: "Mono DRAGON", + }, + "MONO_DARK": { + name: "It's just a phase", + }, + "MONO_FAIRY": { + name: "Mono FAIRY", + }, } as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts index 4255aeaef99..d8f0d1059b2 100644 --- a/src/locales/zh_TW/battle.ts +++ b/src/locales/zh_TW/battle.ts @@ -4,7 +4,7 @@ export const battle: SimpleTranslationEntries = { "bossAppeared": "{{bossName}} 出現了.", "trainerAppeared": "{{trainerName}}\n想要和你對戰!", "trainerAppearedDouble": "{{trainerName}}\n想要和你對戰!", - "singleWildAppeared": "一只野生的 {{pokemonName}} 出現了!", + "singleWildAppeared": "一隻野生的 {{pokemonName}} 出現了!", "multiWildAppeared": "野生的 {{pokemonName1}}\n和 {{pokemonName2}} 出現了!", "playerComeBack": "回來吧, {{pokemonName}}!", "trainerComeBack": "{{trainerName}} 收回了 {{pokemonName}}!", diff --git a/src/locales/zh_TW/challenges.ts b/src/locales/zh_TW/challenges.ts new file mode 100644 index 00000000000..c98b68137ad --- /dev/null +++ b/src/locales/zh_TW/challenges.ts @@ -0,0 +1,67 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const challenges: SimpleTranslationEntries = { + "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": "你只能使用妖精屬性的寶可夢", +} as const; diff --git a/src/locales/zh_TW/config.ts b/src/locales/zh_TW/config.ts index c7045da3d97..49e82f3b436 100644 --- a/src/locales/zh_TW/config.ts +++ b/src/locales/zh_TW/config.ts @@ -1,10 +1,11 @@ import { ability } from "./ability"; import { abilityTriggers } from "./ability-trigger"; -import { achv } from "./achv"; +import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { berry } from "./berry"; import { biome } from "./biome"; +import { challenges } from "./challenges"; import { commandUiHandler } from "./command-ui-handler"; import { PGFbattleSpecDialogue, @@ -18,6 +19,7 @@ import { } from "./dialogue"; import { egg } from "./egg"; import { fightUiHandler } from "./fight-ui-handler"; +import { gameMode } from "./game-mode"; import { gameStatsUiHandler } from "./game-stats-ui-handler"; import { growth } from "./growth"; import { menu } from "./menu"; @@ -29,6 +31,7 @@ import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; import { pokemonInfoContainer } from "./pokemon-info-container"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; import { splashMessages } from "./splash-messages"; import { starterSelectUiHandler } from "./starter-select-ui-handler"; import { titles, trainerClasses, trainerNames } from "./trainers"; @@ -40,12 +43,14 @@ import { partyUiHandler } from "./party-ui-handler"; export const zhTwConfig = { ability: ability, abilityTriggers: abilityTriggers, - achv: achv, battle: battle, battleMessageUiHandler: battleMessageUiHandler, berry: berry, biome: biome, + challenges: challenges, commandUiHandler: commandUiHandler, + PGMachv: PGMachv, + PGFachv: PGFachv, PGMdialogue: PGMdialogue, PGFdialogue: PGFdialogue, PGMbattleSpecDialogue: PGMbattleSpecDialogue, @@ -56,6 +61,7 @@ export const zhTwConfig = { PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, egg: egg, fightUiHandler: fightUiHandler, + gameMode: gameMode, gameStatsUiHandler: gameStatsUiHandler, growth: growth, menu: menu, @@ -67,6 +73,7 @@ export const zhTwConfig = { pokemon: pokemon, pokemonInfo: pokemonInfo, pokemonInfoContainer: pokemonInfoContainer, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, splashMessages: splashMessages, starterSelectUiHandler: starterSelectUiHandler, titles: titles, diff --git a/src/locales/zh_TW/dialogue.ts b/src/locales/zh_TW/dialogue.ts index 5e79471f771..ed66e946cc9 100644 --- a/src/locales/zh_TW/dialogue.ts +++ b/src/locales/zh_TW/dialogue.ts @@ -4,2232 +4,2080 @@ import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/plugins export const PGMdialogue: DialogueTranslationEntries = { "youngster": { "encounter": { - 1: "Hey, wanna battle?", - 2: "Are you a new trainer too?", - 3: "Hey, I haven't seen you before. Let's battle!", - 4: "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", - 5: "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!", - 6: "All right! Let's go!", - 7: "All right! Here I come! I'll show you my power!", - 8: "Haw haw haw... I'll show you how hawesome my Pokémon are!", - 9: "No need to waste time saying hello. Bring it on whenever you're ready!", - 10: "Don't let your guard down, or you may be crying when a kid beats you.", - 11: "I've raised my Pokémon with great care. You're not allowed to hurt them!", - 12: "Glad you made it! It won't be an easy job from here.", - 13: "The battles continue forever! Welcome to the world with no end!" + 1: "嘿,想來對戰嗎?", + 2: "你也是新人訓練師嗎?", + 3: "嘿,我之前沒見過你。我們來對戰吧!", + 4: "我剛輸了,所以我正在尋找更多的寶可夢。$等等!你看起來很弱!\n來吧,我們對戰吧!", + 5: "我們見過面嗎?我記不太清了。$嗯,不管怎樣,很高興見到你!", + 6: "好的!我們上吧!", + 7: "好的!我來啦!我會向你展示我的實力!", + 8: "嚯嚯嚯...我會向你展示我的寶可夢有多厲害!", + 9: "不要浪費時間打招呼。你準備好了就放馬過來!", + 10: "別掉以輕心,$否則你可能會被小朋友打到哭鼻子哦。", + 11: "我精心培養了我的寶可夢。不許你傷害它們!", + 12: "恭喜你成功了!從這以後可不輕鬆哦。", + 13: "戰鬥永無止境!歡迎來到沒有盡頭的世界!", }, "victory": { - 1: "Wow! You're strong!", - 2: "I didn't stand a chance, huh?", - 3: "I'll find you again when I'm older and beat you!", - 4: "Ugh. I don't have any more Pokémon.", - 5: "No way… NO WAY! How could I lose again…", - 6: "No! I lost!", - 7: "Whoa! You are incredible! I'm amazed and surprised!", - 8: "Could it be… How… My Pokémon and I are the strongest, though…", - 9: "I won't lose next time! Let's battle again sometime!", - 10: "Sheesh! Can't you see that I'm just a kid! It wasn't fair of you to go all out like that!", - 11: "Your Pokémon are more amazing! Trade with me!", - 12: "I got a little carried away earlier, but what job was I talking about?", - 13: "Ahaha! There it is! That's right! You're already right at home in this world!" + 1: "哇!你很強!", + 2: "我根本沒機會贏,對吧?", + 3: "我會等長大了再來打敗你!", + 4: "呃。我沒有更多寶可夢了。", + 5: "不可能…不可能!我怎麼可能又輸了…", + 6: "不!我輸了!", + 7: "哇!你真是太不可思議了!我既驚訝又欽佩!", + 8: "這怎麼…怎麼可能…$明明我和我的寶可夢是最強大的…", + 9: "下次我不會輸了!我們找時間再對戰吧!", + 10: "天哪!你看不出我還只是個小孩子嗎!$你那樣全力以赴太賴了!", + 11: "你的寶可夢更棒啊!和我交換吧!", + 12: "我之前有點上頭,我說了什麼來著?", + 13: "啊哈哈!就是這樣!$對!你已經熟悉這個世界了!", } }, "lass": { "encounter": { - 1: "Let's have a battle, shall we?", - 2: "You look like a new trainer. Let's have a battle!", - 3: "I don't recognize you. How about a battle?", - 4: "Let's have a fun Pokémon battle!", - 5: "I'll show you the ropes of how to really use Pokémon!", - 6: "A serious battle starts from a serious beginning! Are you sure you're ready?", - 7: "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.", - 8: "You'd better go easy on me, OK? Though I'll be seriously fighting!", - 9: "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time." + 1: "我們來對戰吧,好嗎?", + 2: "你看起來像是個新人訓練師。我們來戰鬥吧!", + 3: "我不認識你。來對戰怎麼樣?", + 4: "讓我們來進行一場有趣的寶可夢對戰吧!", + 5: "我會向你展示如何真正使用寶可夢!", + 6: "一場認真的對戰從始於認真的開場白!$你確定你準備好了嗎?", + 7: "花無重開日,人無再少年。$你在對戰中只有一次機會。$很快,你就只能活在回憶中了。", + 8: "你最好對我手下留情,好嗎?$當然我會認真對戰的!", + 9: "學校很無聊,我無事可做。$*哈欠*…我只是來對戰打發時間。", }, "victory": { - 1: "That was impressive! I've got a lot to learn.", - 2: "I didn't think you'd beat me that bad…", - 3: "I hope we get to have a rematch some day.", - 4: "That was pretty amazingly fun! You've totally exhausted me…", - 5: "You actually taught me a lesson! You're pretty amazing!", - 6: "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", - 7: "I don't need memories like this. Deleting memory…", - 8: "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", - 9: "I'm actually getting tired of battling… There's gotta be something new to do…" + 1: "那真是令人印象深刻!我還有很多要學習。", + 2: "我沒想到你會這麼輕易地打敗我…", + 3: "我希望有一天,我們能再進行一場對戰。", + 4: "那真是場非常有趣的對戰!$你讓我精疲力盡了…", + 5: "你給我上了一課!你真是太棒了!", + 6: "說真的,我輸了。$這,怎麼說,真的好難過,但你也真的很厲害。", + 7: "我不需要像這樣的記憶。刪除記憶中…", + 8: "嘿!我告訴過你要對我手下留情!$不過,當你認真的時候,你真的很酷。", + 9: "實際上,我開始厭倦對戰了…$一定有新的事情可以做…", } }, "breeder": { "encounter": { - 1: "Obedient Pokémon, selfish Pokémon… Pokémon have unique characteristics.", - 2: "Even though my upbringing and behavior are poor, I've raised my Pokémon well.", - 3: "Hmm, do you discipline your Pokémon? Pampering them too much is no good.", + 1: "聽話的寶可夢,自私的寶可夢…$寶可夢有獨特的性格呢。", + 2: "儘管我出生貧寒,但我的寶可夢培養的很好。", + 3: "嗯,你有沒有管教你的寶可夢?$過度溺愛是不好的。", }, "victory": { - 1: "It is important to nurture and train each Pokémon's characteristics.", - 2: "Unlike my diabolical self, these are some good Pokémon.", - 3: "Too much praise can spoil both Pokémon and people.", + 1: "對每個寶可夢因材施教是很重要的。", + 2: "不像一無是處的我…這些寶可夢都很優秀。", + 3: "過度的讚美會寵壞寶可夢和人。", }, "defeat": { - 1: "You should not get angry at your Pokémon, even if you lose a battle.", - 2: "Right? Pretty good Pokémon, huh? I'm suited to raising things.", - 3: "No matter how much you love your Pokémon, you still have to discipline them when they misbehave." + 1: "即使輸了,也不應該對你的寶可夢發火。", + 2: "相當好的寶可夢,對吧?我很會養東西。", + 3: "無論你多麼愛你的寶可夢,$你仍要在它沒做好時管教它們。", } }, "breeder_female": { "encounter": { - 1: "Pokémon never betray you. They return all the love you give them.", - 2: "Shall I give you a tip for training good Pokémon?", - 3: "I have raised these very special Pokémon using a special method." + 1: "寶可夢永遠不會背叛你。$它們會回報你對它們的愛。", + 2: "要我教教你訓練優秀寶可夢的技巧嗎?", + 3: "特別的寶可夢有特別的培育技巧。", }, "victory": { - 1: "Ugh… It wasn't supposed to be like this. Did I administer the wrong blend?", - 2: "How could that happen to my Pokémon… What are you feeding your Pokémon?", - 3: "If I lose, that tells you I was just killing time. It doesn't damage my ego at all." + 1: "呃…事情不應該是這樣的。$我是不是用錯了能量方塊?", + 2: "這怎麼會發生在我的寶可夢身上…$你給你的寶可夢餵了什麼?", + 3: "如果我輸了,我告訴你我只是在消磨時間。$你根本不會傷害到我的自尊心。", }, "defeat": { - 1: "This proves my Pokémon have accepted my love.", - 2: "The real trick behind training good Pokémon is catching good Pokémon.", - 3: "Pokémon will be strong or weak depending on how you raise them." + 1: "這證明了我的寶可夢已經接受了我的愛。", + 2: "訓出好寶可夢的真正技巧是捉到好的寶可夢。", + 3: "寶可夢的強弱取決於你的飼養方式。", } }, "fisherman": { "encounter": { - 1: "Aack! You made me lose a bite!\nWhat are you going to do about it?", - 2: "Go away! You're scaring the Pokémon!", - 3: "Let's see if you can reel in a victory!", + 1: "啊!你讓我錯過了一次咬鉤!$你打算怎麼辦?", + 2: "走開!你嚇跑了寶可夢!", + 3: "讓我看看你能否贏得勝利!", }, "victory": { - 1: "Just forget about it.", - 2: "Next time, I'll be reelin' in the triumph!", - 3: "Guess I underestimated the currents this time.", + 1: "算了吧。", + 2: "下一次,我將捲土重來,凱旋而歸!", + 3: "我想這次我低估了海流。", }, }, "fisherman_female": { "encounter": { - 1: "Woah! I've hooked a big one!", - 2: "Line's in, ready to reel in success!", - 3: "Ready to make waves!" + 1: "哇!我釣到了一條大魚!", + 2: "線已收好,準備提竿!", + 3: "準備製造波浪!", }, "victory": { - 1: "I'll be back with a stronger hook.", - 2: "I'll reel in victory next time.", - 3: "I'm just sharpening my hooks for the comeback!" + 1: "我會帶著更強大的魚鉤回來。", + 2: "下次我會贏得勝利。", + 3: "我只是在為回歸磨利我的魚鉤!", }, }, "swimmer": { "encounter": { - 1: "Time to dive in!", - 2: "Let's ride the waves of victory!", - 3: "Ready to make a splash!", + 1: "是時候潛水了!", + 2: "讓我們一起乘風破浪,贏得勝利!", + 3: "該一鳴驚人了!", }, "victory": { - 1: "Drenched in defeat!", - 2: "A wave of defeat!", - 3: "Back to shore, I guess.", + 1: "沉浸在失敗中!", + 2: "失敗的波浪!", + 3: "後浪死在沙灘上,我猜。", }, }, "backpacker": { "encounter": { - 1: "Pack up, game on!", - 2: "Let's see if you can keep pace!", - 3: "Gear up, challenger!", - 4: "I've spent 20 years trying to find myself… But where am I?" + 1: "收拾行李,開始遊戲!", + 2: "讓我看看你是否能跟上!", + 3: "全副武裝,挑戰者!", + 4: "我花了20年時間試圖找到自己……但我在哪裡?", }, "victory": { - 1: "Tripped up this time!", - 2: "Oh, I think I'm lost.", - 3: "Dead end!", - 4: "Wait up a second! Hey! Don't you know who I am?" + 1: "這次絆倒了!", + 2: "哦,我覺得我迷路了。", + 3: "死路!", + 4: "等一下!嘿!你不知道我是誰嗎?", }, }, "ace_trainer": { "encounter": { - 1: "You seem quite confident.", - 2: "Your Pokémon… Show them to me…", - 3: "Because I'm an Ace Trainer, people think I'm strong.", - 4: "Are you aware of what it takes to be an Ace Trainer?" + 1: "你看起來挺自信的。", + 2: "你的寶可夢…… 讓我看看……", + 3: "因為我是王牌訓練師,人們認為我很強。", + 4: "你知道成為王牌訓練師需要什麼嗎?", }, "victory": { - 1: "Yes… You have good Pokémon…", - 2: "What?! But I'm a battling genius!", - 3: "Of course, you are the main character!", - 4: "OK! OK! You could be an Ace Trainer!" + 1: "是的…… 你的寶可夢很棒……", + 2: "什麼?!我是戰鬥天才啊!", + 3: "理所應當,你才是主角!", + 4: "好好好!你可以成為王牌訓練師!", }, "defeat": { - 1: "I am devoting my body and soul to Pokémon battles!", - 2: "All within my expectations… Nothing to be surprised about…", - 3: "I thought I'd grow up to be a frail person who looked like they would break if you squeezed them too hard.", - 4: "Of course I'm strong and don't lose. It's important that I win gracefully." + 1: "我將把我的身體和靈魂全都奉獻給寶可夢對戰!", + 2: "一切都在我的預料之中… \n沒有什麼好驚訝的…", + 3: "我覺得我長大後有點玻璃心,$你太壓力我我會垮的……", + 4: "我當然很強大,不會輸。$而且重要的是我要優雅地贏。", } }, "parasol_lady": { "encounter": { - 1: "Time to grace the battlefield with elegance and poise!", + 1: "是時候用優雅和從容來為戰鬥添彩了!", }, "victory": { - 2: "My elegance remains unbroken!", + 1: "我的優雅依然完好無損!", } }, "twins": { "encounter": { - 1: "Get ready, because when we team up, it's double the trouble!", - 2: "Two hearts, one strategy – let's see if you can keep up with our twin power!", - 3: "Hope you're ready for double trouble, because we're about to bring the heat!" + 1: "準備好囉,因為我們聯手,\n麻煩雙倍!", + 2: "兩顆心,一條繩$讓我們看看你能否跟上我們雙胞胎的力量!", + 3: "希望你準備好了面對雙倍的麻煩,$因為我們即將燃起來啦!", }, "victory": { - 1: "We may have lost this round, but our bond remains unbreakable!", - 2: "Our twin spirit won't be dimmed for long.", - 3: "We'll come back stronger as a dynamic duo!" + 1: "雖然我們在這一輪輸了,$但我們的羈絆依然堅不可摧!", + 2: "我們的雙胞胎精神,才不會就此熄滅。", + 3: "我們會作為充滿活力的二人組,$捲土重來,變得更強!", }, "defeat": { - 1: "Twin power reigns supreme!", - 2: "Two hearts, one triumph!", - 3: "Double the smiles, double the victory dance!" + 1: "雙胞胎的力量至高無上!", + 2: "兩顆心,一起贏!", + 3: "笑容成雙,共舞成雙!", } }, "cyclist": { "encounter": { - 1: "Get ready to eat my dust!", - 2: "Gear up, challenger! I'm about to leave you in the dust!", - 3: "Pedal to the metal, let's see if you can keep pace!" + 1: "準備好在我後面吃土吧!", + 2: "挑戰者,準備好!我要把你打得落花流水!", + 3: "全速前進,讓我看看你能不能跟得上!", }, "victory": { - 1: "Spokes may be still, but determination pedals on.", - 2: "Outpaced!", - 3: "The road to victory has many twists and turns yet to explore." + 1: "輪子可能不轉了,但我的決心沒有停下。", + 2: "被超越了!", + 3: "通往勝利的道路還有許多曲折等待探索。", }, }, "black_belt": { "encounter": { - 1: "I praise your courage in challenging me! For I am the one with the strongest kick!", - 2: "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?" + 1: "我讚揚你挑戰我的勇氣!$因為我是踢力最強的人!", + 2: "哦,我明白了。你想被切成碎片嗎?$或者你更喜歡當個沙袋?", }, "victory": { - 1: "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.", - 2: "Hmmm… If I was going to lose anyway, I was hoping to get totally messed up in the process." + 1: "哦。是寶可夢在戰鬥。$我強大的踢擊一點忙都沒幫上。", + 2: "嗯…如果我無論如何都會輸,我希望能被徹底打敗。", }, }, "battle_girl": { "encounter": { - 1: "You don't have to try to impress me. You can lose against me.", + 1: "你不必試圖勾引我。你可以輸給我。", }, "victory": { - 1: "It's hard to say good-bye, but we are running out of time…", + 1: "很難說再見,但我們快沒時間了……", }, }, "hiker": { "encounter": { - 1: "My middle-age spread has given me as much gravitas as the mountains I hike!", - 2: "I inherited this big-boned body from my parents… I'm like a living mountain range…", + 1: "人到中年後,我的身體和我爬過的山一樣強壯!", + 2: "我從父母那裡遺傳了這副魁梧的身材…$就像一座活生生的山脈…", }, "victory": { - 1: "At least I cannot lose when it comes to BMI!", - 2: "It's not enough… It's never enough. My bad cholesterol isn't high enough…" + 1: "至少在BMI方面我不能輸!", + 2: "這還不夠……永遠不夠。$我的壞膽固醇還不夠高……", }, }, "ranger": { "encounter": { - 1: "When I am surrounded by nature, most other things cease to matter.", - 2: "When I'm living without nature in my life, sometimes I'll suddenly feel an anxiety attack coming on." + 1: "當我身處大自然中,其他事情都不重要了。", + 2: "如果我生活中沒有大自然,有時就會突然感到焦慮。", }, "victory": { - 1: "It doesn't matter to the vastness of nature whether I win or lose…", - 2: "Something like this is pretty trivial compared to the stifling feelings of city life." + 1: "無論我是贏是輸,\n對廣闊的大自然來說並不重要……", + 2: "與城市生活的窒息感相比,\n這種事情微不足道。", }, "defeat": { - 1: "I won the battle. But victory is nothing compared to the vastness of nature…", - 2: "I'm sure how you feel is not so bad if you compare it to my anxiety attacks…" + 1: "我贏了。但與浩瀚的大自然相比,\n勝利算不了什麼…", + 2: "與我的焦慮症相比,我覺得你也不會怎樣…", } }, "scientist": { "encounter": { - 1: "My research will lead this world to peace and joy.", + 1: "我的研究將引導這個世界走向和平與歡樂。", }, "victory": { - 1: "I am a genius… I am not supposed to lose against someone like you…", + 1: "我是個天才…我不應該輸給你這樣的人…", }, }, "school_kid": { "encounter": { - 1: "…Heehee. I'm confident in my calculations and analysis.", - 2: "I'm gaining as much experience as I can because I want to be a Gym Leader someday." + 1: "……嘿嘿。我對計算和分析很有信心。", + 2: "我正在盡可能地積累經驗,$因為我希望有一天能成為道館館主。", }, "victory": { - 1: "Ohhhh… Calculation and analysis are perhaps no match for chance…", - 2: "Even difficult, trying experiences have their purpose, I suppose." + 1: "哦…計算和分析也許和個例不太匹配呀…", + 2: "我想,即使是艱難困苦的經歷,也有存在的意義。", } }, "artist": { "encounter": { - 1: "I used to be popular, but now I am all washed up.", + 1: "我以前很受歡迎,但現在已經徹底過氣了。", }, "victory": { - 1: "As times change, values also change. I realized that too late.", + 1: "隨著時代的變遷,價值觀也在變化。$我意識到這一點已經太晚了。", }, }, "guitarist": { "encounter": { - 1: "Get ready to feel the rhythm of defeat as I strum my way to victory!", + 1: "當我彈奏著走向勝利的旋律時,$準備好感受失敗的節奏吧!", }, "victory": { - 1: "Silenced for now, but my melody of resilience will play on.", + 1: "暫時沉默了,但我不屈的旋律將繼續演奏。", }, }, "worker": { "encounter": { - 1: "It bothers me that people always misunderstand me. I'm a lot more pure than everyone thinks.", + 1: "人們總誤解我,這讓我很煩。$我比大家想象的要乾淨得多。", }, "victory": { - 1: "I really don't want my skin to burn, so I want to stay in the shade while I work.", + 1: "我真的不想曬傷皮膚,所以我想在陰涼處工作。", }, }, "worker_female": { "encounter": { - 1: `It bothers me that people always misunderstand me. - $I'm a lot more pure than everyone thinks.` + 1: "人們總是誤解我,這讓我很煩。 $我比大家想象的要乾淨得多。", }, "victory": { - 1: "I really don't want my skin to burn, so I want to stay in the shade while I work." + 1: "我真的不想曬傷皮膚,\n所以我想在陰涼處工作。", }, "defeat": { - 1: "My body and mind aren't necessarily always in sync." + 1: "我的身體和心靈並不總同步。", } }, "worker_double": { "encounter": { - 1: "I'll show you we can break you. We've been training in the field!", + 1: "你會知道我們怎麼擊敗你的。我們在工地訓練過!", }, "victory": { - 1: "How strange… How could this be… I shouldn't have been outmuscled.", + 1: "真奇怪…怎麼會這樣…我不應該被打敗的。", }, }, "hex_maniac": { "encounter": { - 1: "I normally only ever listen to classical music, but if I lose, I think I shall try a bit of new age!", - 2: "I grow stronger with each tear I cry." + 1: "我通常只聽古典音樂,但如果我輸了,$我想我應該試試新時代的音樂!", + 2: "我的每一滴眼淚都讓我變得更加堅強。", }, "victory": { - 1: "Is this the dawning of the age of Aquarius?", - 2: "Now I can get even stronger. I grow with every grudge." + 1: "樂壇新時代的曙光就此出現了嗎?", + 2: "現在我變得更強了。我隨著他人怨恨而成長。", }, "defeat": { - 1: "New age simply refers to twentieth century classical composers, right?", - 2: "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself." + 1: "“新時代”指的是二十世紀的古典作曲家,對吧?", + 2: "不要糾結於悲傷或沮喪。$你可以用悲憤來激勵自己。", } }, "psychic": { "encounter": { - 1: "Hi! Focus!", + 1: "嘿!集中!", }, "victory": { - 1: "Eeeeek!", + 1: "呃呃呃!", }, }, "officer": { "encounter": { - 1: "Brace yourself, because justice is about to be served!", - 2: "Ready to uphold the law and serve justice on the battlefield!" + 1: "準備好,因為正義即將得到伸張!", + 2: "準備好維護法律,在戰場上伸張正義!", }, "victory": { - 1: "The weight of justice feels heavier than ever…", - 2: "The shadows of defeat linger in the precinct." + 1: "正義的分量比以往還要沉重……", + 2: "失敗的陰影,在警局中徘徊。", } }, "beauty": { "encounter": { - 1: "My last ever battle… That's the way I'd like us to view this match…", + 1: "我最後的戰鬥…我就是這麼看待這場對戰的…", }, "victory": { - 1: "It's been fun… Let's have another last battle again someday…", + 1: "很有趣…有時間再來一場最後的戰鬥…", }, }, "baker": { "encounter": { - 1: "Hope you're ready to taste defeat!" + 1: "希望你準備好品嚐失敗的滋味!", }, "victory": { - 1: "I'll bake a comeback." + 1: "我會捲土重來的。", }, }, "biker": { "encounter": { - 1: "Time to rev up and leave you in the dust!" + 1: "是時候加速,把你甩在後面了!", }, "victory": { - 1: "I'll tune up for the next race." + 1: "我會為下一場比賽調整狀態。", }, }, "firebreather": { "encounter": { - 1: "My flames shall devour you!", - 2: "My soul is on fire. I'll show you how hot it burns!", - 3: "Step right up and take a look!" + 1: "我的火焰會吞噬你!", + 2: "我的靈魂在燃燒,我要讓你看看它有多滾燙!", + 3: "快來看看吧!" }, "victory": { - 1: "I burned down to ashes...", - 2: "Yow! That's hot!", - 3: "Ow! I scorched the tip of my nose!" + 1: "我燃成灰了…", + 2: "哟! 好燙!", + 3: "嗷! 我的鼻尖燒焦了!" }, }, "sailor": { "encounter": { - 1: "Matey, you're walking the plank if you lose!", - 2: "Come on then! My sailor's pride is at stake!", - 3: "Ahoy there! Are you seasick?" + 1: "夥計,如果你輸了,你就得挨板子!", + 2: "來吧!這關係到我作為水手的尊嚴!", + 3: "你好啊!你暈船麼?" }, "victory": { - 1: "Argh! Beaten by a kid!", - 2: "Your spirit sank me!", - 3: "I think it's me that's seasick..." + 1: "啊,被孩子打敗了。", + 2: "你的精神讓我沉淪!", + 3: "好像是我暈船了…" }, }, "brock": { "encounter": { - 1: "My expertise on Rock-type Pokémon will take you down! Come on!", - 2: "My rock-hard willpower will overwhelm you!", - 3: "Allow me to show you the true strength of my Pokémon!" + 1: "我對岩石屬性寶可夢的專精會擊敗你!來吧!", + 2: "我磐石般的意志將壓倒你!", + 3: "讓我展示給你看看,我寶可夢真正的力量!", }, "victory": { - 1: "Your Pokémon's strength have overcome my rock-hard defenses!", - 2: "The world is huge! I'm glad to have had a chance to battle you.", - 3: "Perhaps I should go back to pursuing my dream as a Pokémon Breeder…" + 1: "你寶可夢的力量戰勝了我堅如磐石的防禦!", + 2: "世界很大!很高興有機會和你戰鬥。", + 3: "也許我應該回去追尋我成為寶可夢飼養員的夢想……", }, "defeat": { - 1: "The best offense is a good defense!\nThat's my way of doing things!", - 2: "Come study rocks with me next time to better learn how to fight them!", - 3: "Hah, all my traveling around the regions is paying off!" + 1: "最好的進攻就是堅固的防守!$那是我做事的方式!", + 2: "下次來和我一起研究岩石屬性,$更好地了解如何與它們對戰!", + 3: "哈哈,我在各地的旅行有所回報了!", } }, "misty": { "encounter": { - 1: "My policy is an all out offensive with Water-type Pokémon!", - 2: "Hiya, I'll show you the strength of my aquatic Pokémon!", - 3: "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?" + 1: "我的戰策就是使用水屬性寶可夢全面進攻!", + 2: "嗨,我會讓你見識我的水屬性寶可夢的力量!", + 3: "我的夢想是踏上旅程,與強大的訓練師戰鬥……$你能滿足我嗎?", }, "victory": { - 1: "You really are strong… I'll admit that you are skilled…", - 2: "Grrr… You know you just got lucky, right?!", - 3: "Wow, you're too much! I can't believe you beat me!" + 1: "你真的很強……我承認,你有技術的……", + 2: "哼……你知道你只是運氣好,對吧?!", + 3: "哇,你太過分了!不敢相信你打敗我了!", }, "defeat": { - 1: "Was the mighty Misty too much for you?", - 2: "I hope you saw my Pokémon's elegant swimming techniques!", - 3: "Your Pokémon were no match for my pride and joys!" + 1: "強大的小霞對你來說,太過分了嗎?", + 2: "我希望你看到了我寶可夢優雅的游泳技巧!", + 3: "你的寶可夢無法匹敵我的心腹和驕傲!", } }, "lt_surge": { "encounter": { - 1: "My Electric Pokémon saved me during the war! I'll show you how!", - 2: "Ten-hut! I'll shock you into surrender!", - 3: "I'll zap you just like I do to all my enemies in battle!" + 1: "我的電屬性寶可夢在戰爭中救了我!$我來給你展示一下!", + 2: "立正!我要電到你投降!", + 3: "我會像對待敵軍一樣,狠狠電你!", }, "victory": { - 1: "Whoa! Your team's the real deal, kid!", - 2: "Aaargh, you're strong! Even my electric tricks lost against you.", - 3: "That was an absolutely shocking loss!" + 1: "哇!你的隊伍有真傢伙,小子!", + 2: "啊啊,你很強!連我的電擊技巧都輸給了你。", + 3: "這失敗真是把我給電麻了!", }, "defeat": { - 1: "Oh yeah! When it comes to Electric-type Pokémon, I'm number one in the world!", - 2: "Hahaha! That was an electrifying battle, kid!", - 3: "A Pokémon battle is war, and I have showed you first-hand combat!" + 1: "哦耶!我的電屬性寶可夢是世界第一!", + 2: "哈哈哈!真是一場電動人心的戰鬥,小子!", + 3: "寶可夢對戰等於戰爭,$我向你展示了軍隊中的格鬥技巧!", } }, "erika": { "encounter": { - 1: "Ah, the weather is lovely here…\nOh, a battle? Very well then.", - 2: "My Pokémon battling skills rival that of my flower arranging skills.", - 3: "Oh, I hope the pleasant aroma of my Pokémon doesn't put me to sleep again…", - 4: "Seeing flowers in a garden is so soothing." + 1: "啊,這裡天氣真好…$哦,對戰?那好吧。", + 2: "我在寶可夢對戰上的造詣,$可以與我的插花技巧相媲美。", + 3: "哦,希望我寶可夢的宜人香氣\n不會再讓我睡著…", + 4: "看看花園裡的花朵,如此令人心曠神怡。", }, "victory": { - 1: "Oh! I concede defeat.", - 2: "That match was most delightful.", - 3: "Ah, it appears it is my loss…", - 4: "Oh, my goodness." + 1: "哦!我認輸啦~", + 2: "這場比賽非常愉快。", + 3: "啊,看來我輸了…", + 4: "哦,我的天哪。", }, "defeat": { - 1: "I was afraid I would doze off…", - 2: "Oh my, it seems my Grass Pokémon overwhelmed you.", - 3: "That battle was such a soothing experience.", - 4: "Oh… Is that all?" + 1: "我怕我會打瞌睡…", + 2: "哦,我天。看來我的草屬性寶可夢擊敗了你。", + 3: "那場戰鬥是如此令人心曠神怡。", + 4: "哦…這就完啦?", } }, "janine": { "encounter": { - 1: "I am mastering the art of poisonous attacks.\nI shall spar with you today!", - 2: "Father trusts that I can hold my own.\nI will prove him right!", - 3: "My ninja techniques are only second to my Father's!\nCan you keep up?" + 1: "我正在掌握毒屬性攻擊的藝術。$今天我來和你過過招!", + 2: "父親相信我能獨當一面。$我來證明他說的對!", + 3: "我的忍術,僅次於我的父親!$你能跟的上嗎?", }, "victory": { - 1: "Even now, I still need training… I understand.", - 2: "Your battle technique has outmatched mine.", - 3: "I'm going to really apply myself and improve my skills." + 1: "就算現在,我仍然需要繼續訓練…我明白了。", + 2: "你的戰鬥技巧,超過了我。", + 3: "我要好好努力提高我的技術。", }, "defeat": { - 1: "Fufufu… the poison has sapped all your strength to battle.", - 2: "Ha! You didn't stand a chance against my superior ninja skills!", - 3: "Father's faith in me has proven to not be misplaced." + 1: "呵呵…毒液耗盡了你所有的力量。", + 2: "哈!你根本無法抵擋我卓越的忍技!", + 3: "我沒有辜負父親對我的信任。", } }, "sabrina": { "encounter": { - 1: "Through my psychic ability, I had a vision of your arrival!", - 2: "I dislike fighting, but if you wish, I will show you my powers!", - 3: "I can sense great ambition in you. I shall see if it not unfounded." + 1: "我的超能力預見了你的到來!", + 2: "我不喜歡戰鬥,但如果你想,$我會展示我的實力!", + 3: "我能感覺到你的雄心壯志。$我倒要看看你是不是虛有其表。", }, "victory": { - 1: "Your power… It far exceeds what I foresaw…", - 2: "I failed to accurately predict your power.", - 3: "Even with my immense psychic powers, I cannot sense another as strong as you." + 1: "你的力量……遠遠超出了我的預知……", + 2: "我沒有準確預測到你的實力。", + 3: "即使我強大的超能力也無法感知到你這樣強大的人。", }, "defeat": { - 1: "This victory… It is exactly as I foresaw in my visions!", - 2: "Perhaps it was another I sensed a great desire in…", - 3: "Hone your abilities before recklessly charging into battle.\nYou never know what the future may hold if you do…" + 1: "這場勝利……和我看到的未來一樣啊!", + 2: "也許我預感到有強大實力的人,是另一個……", + 3: "在你奮不顧身投入戰鬥之前,\n磨練你的能力。$如果你這樣做,你才未來可期……", } }, "blaine": { "encounter": { - 1: "Hah! Hope you brought a Burn Heal!", - 2: "My fiery Pokémon will incinerate all challengers!", - 3: "Get ready to play with fire!" + 1: "哈!希望你帶了燒傷治療藥!", + 2: "我火熱的寶可夢將所有挑戰者都焚燒殆盡!", + 3: "準備好玩火吧!", }, "victory": { - 1: "I have burned down to nothing! Not even ashes remain!", - 2: "Didn't I stoke the flames high enough?", - 3: "I'm all burned out… But this makes my motivation to improve burn even hotter!" + 1: "我已經焚燒殆盡了!甚至連灰燼都沒有留下!", + 2: "我沒有把火焰煽得足夠高嗎?", + 3: "我燃盡了……但這讓我進步的動力燃燒得更旺了!", }, "defeat": { - 1: "My raging inferno cannot be quelled!", - 2: "My Pokémon have been powered up with the heat from this victory!", - 3: "Hah! My passion burns brighter than yours!" + 1: "我的熊熊烈火無法被撲滅!", + 2: "我的寶可夢因這次勝利而變得更加強大!", + 3: "哈!我的激情燃得比你的更熱烈!", } }, "giovanni": { "encounter": { - 1: "I, the leader of Team Rocket, will make you feel a world of pain!", - 2: "My training here will be vital before I am to face my old associates again.", - 3: "I do not think you are prepared for the level of failure you are about to experience!" + 1: "我,火箭隊的領袖,\n會讓你的世界感受到痛苦!", + 2: "我在這裡的訓練在我再次面對老朋友之前至關重要。", + 3: "我認為你還沒有準備好迎接你即將經歷的失敗!", }, "victory": { - 1: "WHAT! Me, lose?! There is nothing I wish to say to you!", - 2: "Hmph… You could never understand what I hope to achieve.", - 3: "This defeat is merely delaying the inevitable.\nI will rise Team Rocket from the ashes in due time." + 1: "什麼!我輸了?! 我沒什麼可和你說的!", + 2: "哼……你永遠無法理解我希望實現的目標。", + 3: "這次失敗只是暫時的。$我將找準時機,讓火箭隊浴火重生。", }, "defeat": { - 1: "Not being able to measure your own strength shows that you are still but a child.", - 2: "Do not try to interfere with me again.", - 3: "I hope you understand how foolish challenging me was." + 1: "不知自己幾斤幾兩,\n說明你仍然只是一個孩子。", + 2: "不要再試圖干涉我。", + 3: "我希望你明白挑戰我是多麼愚蠢。", } }, "roxanne": { "encounter": { - 1: "Would you kindly demonstrate how you battle?", - 2: "You can learn many things by battling many trainers.", - 3: "Oh, you caught me strategizing.\nWould you like to battle?" + 1: "您能否展示一下您是如何戰鬥的麼?", + 2: "你可以和更多訓練師戰鬥來學到很多東西。", + 3: "哦,被你抓到我正在用功了~$你想戰鬥嗎?", }, "victory": { - 1: "Oh, I appear to have lost.\nI understand.", - 2: "It seems that I still have so much more to learn when it comes to battle.", - 3: "I'll take what I learned here today to heart." + 1: "哦,看來我輸了。$我明白了。", + 2: "看來我在戰鬥方面還有更多東西要學。", + 3: "我會把今天在這裡學到的東西銘記於心。", }, "defeat": { - 1: "I have learned many things from our battle.\nI hope you have too.", - 2: "I look forward to battling you again.\nI hope you'll use what you've learned here.", - 3: "I won due to everything I have learned." + 1: "從我們的對戰中,我學到了很多。$希望你也是。", + 2: "我期待再次與你戰鬥。$希望你能運用在此學到的東西。", + 3: "我憑借我所學到的一切贏得了勝利。", } }, "brawly": { "encounter": { - 1: "Oh man, a challenger!\nLet's see what you can do!", - 2: "You seem like a big splash.\nLet's battle!", - 3: "Time to create a storm!\nLet's go!" + 1: "哦,夥計,挑戰者!$讓我看看你的能耐!", + 2: "你看起來很厲害嘛。$來對戰吧!", + 3: "是時候掀起風暴了!$我們上吧!", }, "victory": { - 1: "Oh woah, you've washed me out!", - 2: "You surfed my wave and crashed me down!", - 3: "I feel like I'm lost in Granite Cave!" + 1: "哦哇,你把我沖走了!", + 2: "你駕馭了我的海浪,把我打敗了!", + 3: "我覺得我就像是在武鬥洞窟裡迷路了!", }, "defeat": { - 1: "Haha, I surfed the big wave!\nChallenge me again sometime.", - 2: "Surf with me again some time!", - 3: "Just like the tides come in and out, I hope you return to challenge me again." + 1: "哈哈,我駕馭了大浪!$有時間再挑戰我吧。", + 2: "再和我一起衝浪吧!", + 3: "就像潮水的漲落,\n我希望你也能再來挑戰我。", } }, "wattson": { "encounter": { - 1: "Time to get shocked!\nWahahahaha!", - 2: "I'll make sparks fly!\nWahahahaha!", - 3: "I hope you brought Paralyz Heal!\nWahahahaha!" + 1: "是時候被電擊了!$哈哈哈!", + 2: "我要讓火星子飛蹦!$哈哈哈!", + 3: "我希望你帶了麻痺藥!$哇哈哈哈!", }, "victory": { - 1: "Seems like I'm out of charge!\nWahahahaha!", - 2: "You've completely grounded me!\nWahahahaha!", - 3: "Thanks for the thrill!\nWahahahaha!" + 1: "看來我的電量用完了!$哇哈哈哈!", + 2: "你完全接地了是吧!$哇哈哈哈!", + 3: "謝謝你給我電了一下!$哇哈哈哈!", }, "defeat": { - 1: "Recharge your batteries and challenge me again sometime!\nWahahahaha!", - 2: "I hope you found our battle electrifying!\nWahahahaha!", - 3: "Aren't you shocked I won?\nWahahahaha!" + 1: "電充充滿,有時間再挑戰我吧!$哇哈哈哈!", + 2: "我希望你覺得我們的戰鬥激情似電!$哇哈哈哈!", + 3: "你沒想到我贏了吧?$哇哈哈哈!", } }, "flannery": { "encounter": { - 1: "Nice to meet you! Wait, no…\nI will crush you!", - 2: "I've only been a leader for a little while, but I'll smoke you!", - 3: "It's time to demonstrate the moves my grandfather has taught me! Let's battle!" + 1: "很高興見到你!等等,不對……$我要粉碎你!", + 2: "我才當道館主沒多久,\n但我會讓你灰飛煙滅!", + 3: "是時候展示爺爺教給我的招式了!來對戰吧!", }, "victory": { - 1: "You remind me of my grandfather…\nNo wonder I lost.", - 2: "Am I trying too hard?\nI should relax, can't get too heated.", - 3: "Losing isn't going to smother me out.\nTime to reignite training!" + 1: "你讓我想起了我的爺爺……$難怪我輸了。", + 2: "我是不是太努力了?$我應該放鬆,不能太上頭了。", + 3: "失敗才不會嗆到我。$是時候重新點燃訓練了!", }, "defeat": { - 1: "I hope I've made my grandfather proud…\nLet's battle again some time.", - 2: "I…I can't believe I won!\nDoing things my way worked!", - 3: "Let's exchange burning hot moves again soon!" + 1: "我希望我讓祖父感到驕傲了……$有時間我們再戰鬥吧。", + 2: "我……我簡直不敢相信我贏了!$按照自己的方式做事奏效了!", + 3: "早點用炙熱的招式再來交手吧!", } }, "norman": { "encounter": { - 1: "I'm surprised you managed to get here.\nLet's battle.", - 2: "I'll do everything in my power as a Gym Leader to win.\nLet's go!", - 3: "You better give this your all.\nIt's time to battle!" + 1: "我沒想到你能一路來到這裡。$我們來對戰吧。", + 2: "作為道館主,我會盡一切努力贏得勝利。$我們開始吧!", + 3: "你最好全力以赴。$對戰的時候到了!", }, "victory": { - 1: "I lost to you…?\nRules are rules, though.", - 2: "Was moving from Olivine a mistake…?", - 3: "I can't believe it.\nThat was a great match." + 1: "我輸給了你……?$但規則就是規則。", + 2: "難道我不該從城都搬家嗎……?", + 3: "我不敢相信。$這是一場好對戰。", }, "defeat": { - 1: "We both tried our best.\nI hope we can battle again soon.", - 2: "You should try challenging my kid instead.\nYou might learn something!", - 3: "Thank you for the excellent battle.\nBetter luck next time." + 1: "我們都盡力了。$希望我們不久之後能再對戰。", + 2: "你應該嘗試挑戰我的孩子。$可能會有一些收穫!", + 3: "謝謝你精彩的戰鬥。$下次好運。", } }, "winona": { "encounter": { - 1: "I've been soaring the skies looking for prey…\nAnd you're my target!", - 2: "No matter how our battle is, my Flying Pokémon and I will triumph with grace. Let's battle!", - 3: "I hope you aren't scared of heights.\nLet's ascend!" + 1: "我一直在天空中翱翔尋找獵物…$而你就是我的目標!", + 2: "不管戰況如何,我都會和我的飛行寶可夢$以優雅的姿態獲勝。來戰鬥吧!", + 3: "我希望你不怕高。$我們一起升上高空吧!", }, "victory": { - 1: "You're the first Trainer I've seen with more grace than I.\nExcellently played.", - 2: "Oh, my Flying Pokémon have plummeted!\nVery well.", - 3: "Though I may have fallen, my Pokémon will continue to fly!" + 1: "你是我見過的第一位比我更有風度的訓練師。$打的非常出色。", + 2: "哦,我的飛行系寶可夢都已經墜落了!$好吧。", + 3: "儘管我倒下了,我的寶可夢將繼續翱翔!", }, "defeat": { - 1: "My Flying Pokémon and I will forever dance elegantly!", - 2: "I hope you enjoyed our show.\nOur graceful dance is finished.", - 3: "Won't you come see our elegant choreography again?" + 1: "我與我的飛行系寶可夢,\n將永遠優雅地起舞!", + 2: "我希望你喜歡我們的演出。$我們優雅的舞蹈已經落幕。", + 3: "你願意再來觀看我們優雅的編舞嗎?", } }, "tate": { "encounter": { - 1: "Hehehe…\nWere you surprised to see me without my sister?", - 2: "I can see what you're thinking…\nYou want to battle!", - 3: "How can you defeat someone…\nWho knows your every move?" + 1: "嘿嘿嘿…$看到我沒和妹妹在一起,很驚訝麼?", + 2: "我可以讀懂你在想什麼…$你想要戰鬥!", + 3: "你如何擊敗一個…$讀懂你一舉一動的人?", }, "victory": { - 1: "It can't be helped…\nI miss Liza…", - 2: "Your bond with your Pokémon was stronger than mine.", - 3: "If I were with Liza, we would have won.\nWe can finish each other's thoughts!" + 1: "贏不了啊…$我想小南了…", + 2: "你和寶可夢之間的聯繫比我們更強。", + 3: "如果我和小南聯手,我們會贏的。$我們可以了解彼此的想法!", }, "defeat": { - 1: "My Pokémon and I are superior!", - 2: "If you can't even defeat me, you'll never be able to defeat Liza either.", - 3: "It's all thanks to my strict training with Liza.\nI can make myself one with Pokémon." + 1: "我和我的寶可夢無與倫比!", + 2: "如果你連我都打不過,\n你肯定也打不過小南。", + 3: "這多虧了我和小南的嚴格訓練。$我可以與寶可夢一心同體。", } }, "liza": { "encounter": { - 1: "Fufufu…\nWere you surprised to see me without my brother?", - 2: "I can determine what you desire…\nYou want to battle, don't you?", - 3: "How can you defeat someone…\nWho's one with their Pokémon?" + 1: "呵呵呵…$看到我沒和哥哥一起,很驚訝嗎?", + 2: "我可以讀懂你渴望什麼…$你想戰鬥,不是嗎?", + 3: "你如何擊敗一個…$與寶可夢們一心同體的人?", }, "victory": { - 1: "It can't be helped…\nI miss Tate…", - 2: "Your bond with your Pokémon…\nIt's stronger than mine.", - 3: "If I were with Tate, we would have won.\nWe can finish each other's sentences!" + 1: "贏不了啊…$我想小楓了…", + 2: "你和寶可夢之間的聯繫…$比我強。", + 3: "如果我和小楓在一起,我們會贏的。$我們甚至可以接上彼此的話!", }, "defeat": { - 1: "My Pokémon and I are victorious.", - 2: "If you can't even defeat me, you'll never be able to defeat Tate either.", - 3: "It's all thanks to my strict training with Tate.\nI can synchronize myself with my Pokémon." + 1: "我和我的寶可夢勢不可擋。", + 2: "如果你連我都打不過,\n你肯定也打不過小楓。", + 3: "這多虧了我和小楓的嚴格訓練。$我可以與我的寶可夢一心同體。", } }, "juan": { "encounter": { - 1: "Now's not the time to act coy.\nLet's battle!", - 2: "Ahahaha, You'll be witness to my artistry with Water Pokémon!", - 3: "A typhoon approaches!\nWill you be able to test me?", - 4: "Please, you shall bear witness to our artistry.\nA grand illusion of water sculpted by my Pokémon and myself!" + 1: "別害羞啊。$我們來戰鬥吧!", + 2: "啊哈哈哈,敬請期待\n我和水屬性寶可夢的盛大演出!", + 3: "我就是正在逼近的風暴!$你能經受住考驗嗎?", + 4: "請你見證我們的表演。$由我和寶可夢共同創造的宏偉水之幻境!", }, "victory": { - 1: "You may be a genius who can take on Wallace!", - 2: "I focused on elegance while you trained.\nIt's only natural that you defeated me.", - 3: "Ahahaha!\nVery well, You have won this time.", - 4: "From you, I sense the brilliant shine of skill that will overcome all." + 1: "你可能是一個能挑戰米可利的天才!", + 2: "我專注於優雅,而你刻苦鍛鍊。$你能擊敗我是很正常的。", + 3: "啊哈哈哈!$好吧,這次你贏了。", + 4: "從你身上,我感受到了技巧的光輝,\n它將戰勝一切。", }, "defeat": { - 1: "My Pokémon and I have sculpted an illusion of Water and come out victorious.", - 2: "Ahahaha, I have won, and you have lost.", - 3: "Shall I loan you my outfit? It may help you battle!\nAhahaha, I jest!", - 4: "I'm the winner! Which is to say, you lost." + 1: "寶可夢和我創造的水之幻境,讓我取得了勝利。", + 2: "啊哈哈哈,我贏了,你輸了。", + 3: "要我把我的服裝借給你嗎?\n可能能幫到你對戰啊!$啊哈哈哈,我開玩笑的!", + 4: "我是贏家!也就是說,你輸了。", } }, "crasher_wake": { "encounter": { - 1: "Crash! Crash! Watch out!\nCrasher Wake…is…heeere!", - 2: "Crash! Crash! Crasher Wake!", - 3: "I'm the tidal wave of power to wash you away!" + 1: "極限! 極限! 看好了!$極限假面…就此…登場!", + 2: "極限! 極限! 極限假面!", + 3: "我是滔滔巨浪,將你沖走!", }, "victory": { - 1: "That puts a grin on my face!\nGuhahaha! That was a blast!", - 2: "Hunwah! It's gone and ended!\nHow will I say this…\nI want more! I wanted to battle a lot more!", - 3: "WHAAAAT!?" + 1: "我真是笑得合不攏嘴啊!$哈哈哈!那真是太有趣了!", + 2: "呼哇!結束收尾了!$我該怎麼說呢……$我還想再對戰!我還想再繼續戰鬥!", + 3: "啊啊啊啊啊!?", }, "defeat": { - 1: "Yeeeeah! That's right!", - 2: "I won, but I want more! I wanted to battle a lot more!", - 3: "So long!" + 1: "耶!就是這樣!", + 2: "我贏了,但我還想要更多!\n我還想再更多地戰鬥!", + 3: "再見!", } }, "falkner": { "encounter": { - 1: "I'll show you the real power of the magnificent bird Pokémon!", - 2: "Winds, stay with me!", - 3: "Dad! I hope you're watching me battle from above!" + 1: "我將向你展示華麗的飛行寶可夢真正的力量!", + 2: "風啊,伴我同行!", + 3: "爸爸!我希望你能在空中注視著我的戰鬥!", }, "victory": { - 1: "I understand… I'll bow out gracefully.", - 2: "A defeat is a defeat. You are strong indeed.", - 3: "…Shoot! Yeah, I lost." + 1: "明白了……我會禮貌地退場。", + 2: "輸了就是輸了。你確實很強大。", + 3: "…行吧! 嗯, 我輸了。", }, "defeat": { - 1: "Dad! I won with your cherished bird Pokémon…", - 2: "Bird Pokémon are the best after all!", - 3: "Feels like I'm catching up to my dad!" + 1: "爸爸!我用你珍愛的飛行寶可夢贏了……", + 2: "飛行系寶可夢才是最強的!", + 3: "感覺我正在追趕上我的父親!", } }, "nessa": { "encounter": { - 1: "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", - 2: "I'm not here to chat. I'm here to win!", - 3: "This is a little gift from my Pokémon… I hope you can take it!" + 1: "無論你的小腦瓜子在搞什麼陰謀詭計,$我和我的搭檔都會確保它石沉大海。", + 2: "我來這裡可不是為了閒聊,\n而是為了贏!", + 3: "這是我的寶可夢給你的一點小禮物……\n我希望你能接受!", }, "victory": { - 1: "You and your Pokémon are just too much…", - 2: "How…? How can this be?!", - 3: "I was totally washed away!" + 1: "你和你的寶可夢太過分了……", + 2: "怎麼……?這怎麼可能?!", + 3: "我完全被沖走了!", }, "defeat": { - 1: "The raging wave crashes again!", - 2: "Time to ride the wave of victory!", - 3: "Ehehe!" + 1: "洶湧的海浪再次襲來!", + 2: "是時候乘風破浪,取得勝利了!", + 3: "誒嘿嘿!", } }, "melony": { "encounter": { - 1: "I'm not going to hold back!", - 2: "All righty, I suppose we should get started.", - 3: "I'll freeze you solid!" + 1: "我不會手下留情!", + 2: "好吧,我想我們應該開始了。", + 3: "我會把你凍得結結實實的!", }, "victory": { - 1: "You… You're pretty good, huh?", - 2: "If you find Gordie around, be sure to give him a right trashing, would you?", - 3: "I think you took breaking the ice a little too literally…" + 1: "你……你可厲害了,是不是?", + 2: "如果你找到瑪瓜,一定要好好教訓他,好嗎?", + 3: "你的破冰方式有點過於直接了呢……", }, "defeat": { - 1: "Now do you see how severe battles can be?", - 2: "Hee! Looks like I went and won again!", - 3: "Are you holding back?" + 1: "現在你知道戰鬥有多殘酷了吧?", + 2: "嘿!看來我又贏了!", + 3: "你是在保留實力嗎?", } }, "marlon": { "encounter": { - 1: "You look strong! Shoots! Let's start!", - 2: "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", - 3: "Oh ho, so I'm facing you! That's off the wall." + 1: "你看起來很強!來吧!讓我們開始吧!", + 2: "我的強大像大海一樣無邊無際。$你會被我沖走,絕對的。", + 3: "哦豁,由我來面對你!這可不得了咯!", }, "victory": { - 1: "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", - 2: "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!", - 3: "You're strong as a gnarly wave!" + 1: "你太厲害了!\n你培養了一些非常強大的寶可夢啊,$你已經掌握了訓練師的精髓!", + 2: "你不僅僅是看起來,\n你是真的強,真的!$呃,我也被沖走了!", + 3: "你像兇猛的波浪一樣強壯!", }, "defeat": { - 1: "You're tough, but it's not enough to sway the sea, 'K!", - 2: "Hee! Looks like I went and won again!", - 3: "Sweet, sweet victory!" + 1: "你很強,但這還不足以動搖大海,懂?", + 2: "嘻!看來我又贏了!", + 3: "甜蜜的勝利!", } }, "shauntal": { "encounter": { - 1: "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", - 2: "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?", - 3: "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?" + 1: "打擾了。你是挑戰者,對嗎?$我是四天王的幽靈系寶可夢使用者,$婉龍,我將是你的對手。", + 2: "我非常喜歡描寫來到這裡的訓練師,\n以及他們訓練的寶可夢。$我可以用你和你的寶可夢作為主題嗎?", + 3: "每個與寶可夢相處的人都有故事要講。$接下來要講的故事是怎樣的呢?", }, "victory": { - 1: "Wow. I'm dumbstruck!", - 2: "S-sorry! First, I must apologize to my Pokémon…\n\nI'm really sorry you had a bad experience because of me!", - 3: "Even in light of that, I'm still one of the Elite Four!" + 1: "哇。我驚呆了!", + 2: "對…對不起!我必須先向我的寶可夢道歉……$都是因為我讓你們有了不好的經歷,真的很抱歉!", + 3: "你要知道,我仍然是四天王之一!", }, "defeat": { - 1: "Eheh.", - 2: "That gave me excellent material for my next novel!", - 3: "And so, another tale ends…" + 1: "額呵呵。", + 2: "給了我下一部小說的絕佳素材!", + 3: "就這樣,又一篇故事來到尾聲……", } }, "marshal": { "encounter": { - 1: "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", - 2: "Victory, decisive victory, is my intention! Challenger, here I come!", - 3: "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!" + 1: "我的師傅,阿戴克,\n看到了你作為訓練師的潛力,$對你很有興趣。$我要來考驗你——挖掘你力量的極限。\n丹田發力!", + 2: "勝利,決定性的勝利,\n正是我所求!挑戰者,我來了!", + 3: "在我的心中,我尋求著成為戰士的力量,\n克服自身的所有弱點!$以我的信念,取勝!", }, "victory": { - 1: "Whew! Well done!", - 2: "As your battles continue, aim for even greater heights!", - 3: "The strength shown by you and your Pokémon has deeply impressed me…" + 1: "呼!幹得好!", + 2: "不要停止戰鬥,追求更高的目標!", + 3: "你和你寶可夢展現的力量\n給我留下了深刻的印象……", }, "defeat": { - 1: "Hmm.", - 2: "That was good battle.", - 3: "Haaah! Haaah! Haiyaaaah!" + 1: "嗯…", + 2: "這真是場好戰鬥。", + 3: "哈啊!哈啊!嗨呀啊!", } }, "cheren": { "encounter": { - 1: "You remind me of an old friend. That makes me excited about this Pokémon battle!", - 2: `Pokémon battles have no meaning if you don't think why you battle. - $Or better said, it makes battling together with Pokémon meaningless.`, - 3: "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you." + 1: "你讓我想起了一位老朋友。$這讓我對這場寶可夢戰鬥感到興奮!", + 2: "不考慮清楚這一點,\n寶可夢對戰就沒有了意義。$這就是失去了和寶可夢一同戰鬥的意義。", + 3: "我的名字是黑連!我是道館館主,\n也是老師!$很高興認識你。", }, "victory": { - 1: "Thank you! I saw what was missing in me.", - 2: "Thank you! I feel like I saw a little of the way toward my ideals.", - 3: "Hmm… This is problematic." + 1: "謝謝……我又能發現自己的不足了。", + 2: "謝謝…接近理想的道路…我好像隱約看到了。", + 3: "嗯……這值得思考。", }, "defeat": { - 1: "As a Gym Leader, I aim to be a wall for you to overcome.", - 2: "All right!", - 3: "I made it where I am because Pokémon were by my side.\nPerhaps we need to think about why Pokémon help us not in terms of Pokémon and Trainers but as a relationship between living beings." + 1: "作為道館館主,我要成為你要跨越的壁壘!", + 2: "好吧!", + 3: "正因為有寶可夢,我們才能走到這裡。$為什麼寶可夢會幫助我們,\n這個恐怕不僅是寶可夢與訓練家…$而是生命與生命之間的問題。", } }, "chili": { "encounter": { - 1: "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", - 2: "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", - 3: "I'm going to show you what me and my blazing Fire types can do!" + 1: "咿呀!是時候玩火了!!我是三兄弟中最強的!", + 2: "嗒噠!如火似焰的伯特——就是我\n——你接下來的對手!", + 3: "我將向你展示,\n我和我熾熱的火系寶可夢的能耐!", }, "victory": { - 1: "You got me. I am… burned… out…", - 2: "Whoa ho! You're on fire!", - 3: "Augh! You got me!" + 1: "被你幹掉了。我……燃盡了……", + 2: "哇吼!你燃起來了!", + 3: "啊!被你幹碎了!", }, "defeat": { - 1: "I'm on fire! Play with me, and you'll get burned!", - 2: "When you play with fire, you get burned!", - 3: "I mean, c'mon, your opponent was me! You didn't have a chance!" + 1: "我燃起來啦!和我玩兒,你就會被燙傷!", + 2: "你要是玩兒火,就會被燙傷!", + 3: "我說,拜託,\n你的對手是我,沒機會贏的!", } }, "cilan": { "encounter": { - 1: `Nothing personal... No hard feelings... Me and my Grass-type Pokémon will... - $Um... We're gonna battle come what may.`, - 2: "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", - 3: "OK… So, um, I'm Cilan, I like Grass-type Pokémon." + 1: "無關個人情感…也不會有艱難的感受…$我和我的草屬性寶可夢會…$呃…不管什麼樣的對手我們都會應戰的。", + 2: "所以,呃,如果你願意的話,我會,\n呃,盡我所能做好,呃,你知道的,你的對手。", + 3: "好吧……所以,我是天桐,\n我喜歡草屬性寶可夢。", }, "victory": { - 1: "Er… Is it over now?", - 2: `…What a surprise. You are very strong, aren't you? - $I guess my brothers wouldn't have been able to defeat you either…`, - 3: "…Huh. Looks like my timing was, um, off?" + 1: "呃……已經結束了嗎?", + 2: "…真是太意外了。你真…強。$看起來就算是伯特或寇恩都贏不了你…", + 3: "…嗯。看起來我來的…不是時候?", }, "defeat": { - 1: "Huh? Did I win?", - 2: `I guess… - $I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.`, - 3: "It…it was quite a thrilling experience…" + 1: "哈?我贏了?", + 2: "我想…$我想我贏了,因為我一直在和我的兄弟伯特和寇恩競爭,\n我們都變得更強了。", + 3: "…這…這是一次非常嚇人的經歷呢…", } }, "roark": { "encounter": { - 1: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", - 2: "Here goes! These are my rocking Pokémon, my pride and joy!", - 3: "Rock-type Pokémon are simply the best!", - 4: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!" + 1: "我需要看看你作為訓練師的潛力。$還有,我要看看與你並肩作戰的寶可夢的堅韌!", + 2: "來吧!這些是我的岩石系寶可夢,我的驕傲!", + 3: "岩石屬性寶可夢就是最強的!", + 4: "我要看看你作為訓練師的潛力。$還要看看與你並肩作戰的寶可夢的堅韌!", }, "victory": { - 1: "W-what? That can't be! My buffed-up Pokémon!", - 2: "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", - 3: "With skill like yours, it's natural for you to win.", - 4: "Wh-what?! It can't be! Even that wasn't enough?", - 5: "I blew it." + 1: "什麼?不可能!我強化的寶可夢們!", + 2: "……我大腦過載了。$下次邀請你參加地下的化石挖掘比賽。", + 3: "有你這種技術,贏得勝利是很正常的。", + 4: "什麼?!連這也不夠?", + 5: "我搞砸了。", }, "defeat": { - 1: "See? I'm proud of my rocking battle style!", - 2: "Thanks! The battle gave me confidence that I may be able to beat my dad!", - 3: "I feel like I just smashed through a really stubborn boulder!" + 1: "看?我為我的搖滾戰鬥風格感到驕傲!", + 2: "謝謝!這場戰鬥給了我自信,$我感覺能夠打敗我父親了!", + 3: "我感覺就像我砸穿了一塊頑石!", } }, "morty": { "encounter": { - 1: `With a little more, I could see a future in which I meet the legendary Pokémon. - $You're going to help me reach that level!`, - 2: `It's said that a rainbow-hued Pokémon will come down to appear before a truly powerful Trainer. - $I believed that tale, so I have secretly trained here all my life. As a result, I can now see what others cannot. - $I see a shadow of the person who will make the Pokémon appear. - $I believe that person is me! You're going to help me reach that level!`, - 3: "Whether you choose to believe or not, mystic power does exist.", - 4: "You can bear witness to the fruits of my training.", - 5: "You must make your soul one with that of Pokémon. Can you do this?", - 6: "Say, do you want to be part of my training?" + 1: "只要我再多努力一點,我就能看到我遇到傳說中的寶可夢的未來!$你會幫助我達到那個水平!", + 2: "據說,彩虹色的寶可夢會\n出現在真正強大的訓練師面前。 $我一直相信著這個美麗的傳說,\n所以,從出生開始,\n就在這裡進行著秘密的修行。$因為這樣,其他人看不到的東西\n我也能夠看得到…$我看到的,是那個將傳說中的寶可夢\n召喚到這片大地上的人的影子。$我一直相信,那就是我自己!\n希望你也能助我一臂之力!", + 3: "無論你相信還是不相信,神秘的力量確實存在。", + 4: "你可以見證我訓練的成果。", + 5: "你必須讓你與寶可夢的靈魂合二為一。你能做到嗎?", + 6: "嘿,你想成為我訓練的一部分嗎?", }, "victory": { - 1: "I'm not good enough yet…", - 2: `I see… Your journey has taken you to far-away places and you have witnessed much more than I. - $I envy you for that…`, - 3: "How is this possible…", - 4: `I don't think our potentials are so different. - $But you seem to have something more than that… So be it.`, - 5: "Guess I need more training.", - 6: "That's a shame." + 1: "我還不夠好……", + 2: "我明白了…你的旅程…去了遙遠的地方,你見過的比我多得多。$我羨慕你…", + 3: "這怎麼可能……", + 4: "我認為我們的潛力沒什麼不同。$但是,我覺得你並不簡單,似乎還有什麼……", + 5: "我想我需要更多的訓練。", + 6: "那太遺憾了", }, "defeat": { - 1: "I moved… one step ahead again.", - 2: "Fufufu…", - 3: "Wh-what?! It can't be! Even that wasn't enough?", - 4: "I feel like I just smashed through a really stubborn boulder!", - 5: "Ahahahah!", - 6: "I knew I would win!" + 1: "我又向前邁進了一步。", + 2: "呵呵呵……", + 3: "什…麼?!那還不夠?", + 4: "我感覺就像我砸穿了一塊頑石!", + 5: "哈哈哈啊!", + 6: "我知道我會贏!", } }, "crispin": { "encounter": { - 1: "I wanna win, so that's exactly what I'll do!", - 2: "I battle because I wanna battle! And you know what? That's how it should be!" + 1: "我想贏,所以接下來我正要贏!", + 2: "我想對戰就對戰!懂嗎!就應該這樣!", }, "victory": { - 1: "I wanted to win…but I lost!", - 2: "I lost…'cause I couldn't win!" + 1: "我想贏……但我還是輸了!", + 2: "我輸了……因為我贏不了!", }, "defeat": { - 1: "Hey, wait a sec. Did I just win? I think I just won! Talk about satisfying!", - 2: "Wooo! That was amazing!" + 1: "嘿,等一下。我是不是贏了?$我覺得我贏了!太滿足了!", + 2: "哇哦!那太棒了!", } }, "amarys": { "encounter": { - 1: `I want to be the one to help a certain person. That being the case, I cannot afford to lose. - $… Our battle starts now.`, + 1: "我想幫助某個人。因此,我不能輸。$…我們的戰鬥現在開始。", }, "victory": { - 1: "I am… not enough, I see." + 1: "我還不夠,我明白了。", }, "defeat": { - 1: "Victory belongs to me. Well fought." + 1: "勝利屬於我。打得好。", } }, "lacey": { "encounter": { - 1: "I'll be facing you with my usual party as a member of the Elite Four." + 1: "我將用我平時的隊伍\n作為四天王的一員面對你。", }, "victory": { - 1: "That was a great battle!" + 1: "打得真好呀~", }, "defeat": { - 1: "Let's give your Pokémon a nice round of applause for their efforts!" + 1: "讓我們為你寶可夢的努力給予熱烈的掌聲!", } }, "drayton": { "encounter": { - 1: `Man, I love chairs. Don't you love chairs? What lifesavers. - $I don't get why everyone doesn't just sit all the time. Standing up's tiring work!`, + 1: "哥們,我喜歡椅子。\n你喜歡椅子嗎?簡直是救星。$我不明白為什麼大家不一直坐著。\n站著多累人!", }, "victory": { - 1: "Guess I should've expected that!" + 1: "我早該想到的!", }, "defeat": { - 1: "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?" + 1: "嘿嘿嘿!別介意我,\n我只是在這裡小贏一下。$如果你不開心,我懂,\n但別因為我對烏栗發火,OK?", } }, "ramos": { "encounter": { - 1: `Did yeh enjoy the garden playground I made with all these sturdy plants o' mine? - $Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?`, + 1: "我用那些強壯的植物\n蓋出來的遊樂場精彩嗎?$它們的力量象徵著我這個園丁兼道館館主的實力,\n你真的確定能夠與之抗衡嗎?", }, "victory": { - 1: "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout." + 1: "你信任你的寶可夢,\n它們也信任你…不錯的戰鬥,小豆芽。", }, "defeat": { - 1: "Hohoho… Indeed. Frail little blades o' grass'll break through even concrete." + 1: "呵呵呵…確實,\n脆弱的小草甚至能穿透混凝土。", } }, "viola": { "encounter": { - 1: `Whether it's the tears of frustration that follow a loss or the blossoming of joy that comes with victory… - $They're both great subjects for my camera! Fantastic! This'll be just fantastic! - $Now come at me!`, - 2: "My lens is always focused on victory--I won't let anything ruin this shot!" + 1: "敗陣時的後悔,勝利的瞬間…$都是最棒的影象!很好呀,很好呀!$那麼來吧!", + 2: "我的鏡頭總會聚焦在勝利上,\n我不會讓任何事情破壞這個畫面!", }, "victory": { - 1: "You and your Pokémon have shown me a whole new depth of field! Fantastic! Just fantastic!", - 2: `The world you see through a lens, and the world you see with a Pokémon by your side… - $The same world can look entirely different depending on your view.` + 1: "你和你的寶可夢向我展示了一個全新的鏡頭機位!\n很好呀,很好呀!", + 2: "你通過鏡頭看到的世界,\n和你與寶可夢並肩作戰時看到的世界…$視角不同,即使是同一個世界看起來也完全不同。", }, "defeat": { - 1: "The photo from the moment of my victory will be a real winner, all right!", - 2: "Yes! I took some great photos!" + 1: "我勝利那一刻的照片,\n將是一個真正的贏家,對吧!", + 2: "是的!我拍了些很棒的照片!", } }, "candice": { "encounter": { - 1: `You want to challenge Candice? Sure thing! I was waiting for someone tough! - $But I should tell you, I'm tough because I know how to focus.`, - 2: `Pokémon, fashion, romance… It's all about focus! - $I'll show you just what I mean. Get ready to lose!` + 1: "向小菘我挑戰嗎?好啊!\n我就是在等待強者$但是我也氣勢高昂,很強哦?", + 2: "寶可夢也好,時尚也好,戀愛也好,\n無論做什麼都氣勢高昂!$就說到這兒吧,讓你見識一下我的氣勢,\n要做好覺悟哦!", }, "victory": { - 1: "I must say, I'm warmed up to you! I might even admire you a little.", - 2: `Wow! You're great! You've earned my respect! - $I think your focus and will bowled us over totally. ` + 1: "好厲害!我有點尊敬你了。", + 2: "好厲害!我有點尊敬你了!$嗯,感覺是被你的氣勢給壓倒了。", }, "defeat": { - 1: "I sensed your will to win, but I don't lose!", - 2: "See? Candice's focus! My Pokémon's focus is great, too!" + 1: "你的氣勢我看到了,但我還是不會輸的!", + 2: "怎麼樣?小菘我的氣勢!\n寶可夢們的氣勢滿滿哦!", } }, "gardenia": { "encounter": { - 1: "You have a winning aura about you. So, anyway, this will be fun. Let's have our battle!" + 1: "你身上有一種勝利的氣息。\n那麼不管怎樣,$這應該會是場有趣的戰鬥。\n讓我們對戰吧!", }, "victory": { - 1: "Amazing! You're very good, aren't you?" + 1: "太棒了!你可擅長對戰了,不是嗎?", }, "defeat": { - 1: "Yes! My Pokémon and I are perfectly good!" + 1: "太好了!我的寶可夢和我都很棒!", } }, "aaron": { "encounter": { - 1: "Ok! Let me take you on!" + 1: "好的!讓我來接受你的挑戰!", }, "victory": { - 1: "Battling is a deep and complex affair…" + 1: "戰鬥是一件深刻而複雜的事情……", }, "defeat": { - 1: "Victory over an Elite Four member doesn't come easily." + 1: "戰勝一位四天王並不容易。", } }, "cress": { "encounter": { - 1: "That is correct! It shall be I and my esteemed Water types that you must face in battle!" + 1: "沒!錯!你必須面對\n與我和我高貴的水屬性的戰鬥!", }, "victory": { - 1: "Lose? Me? I don't believe this." + 1: "輸了?我?我不敢相信。", }, "defeat": { - 1: "This is the appropriate result when I'm your opponent." + 1: "當你的對手是我時,這是必然的結果。", } }, "allister": { "encounter": { - 1: "'M Allister.\nH-here… I go…" + 1: "我是歐尼奧。$我…我來了……", }, "victory": { - 1: `I nearly lost my mask from the shock… That was… - $Wow. I can see your skill for what it is.`, + 1: "我差點被嚇得丟了面具…那真是…$哇。我可以看清你真正的實力。", }, "defeat": { - 1: "Th-that was ace!" + 1: "這真是太棒了!", } }, "clay": { "encounter": { - 1: "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!" + 1: "咳咳! 讓我好等,不是嗎,孩子?$好吧,是時候看看你能做到什麼了!", }, "victory": { - 1: "Man oh man… It feels good to go all out and still be defeated!" + 1: "真是的……我先說好,\n我可沒有手下留情。", }, "defeat": { - 1: `What's important is how ya react to losin'. - $That's why folks who use losin' as fuel to get better are tough.`, + 1: "最重要的是輸掉的時候該怎麼辦。$只要你能在失敗中找到教訓,\n就能夠不斷地成長!", } }, "kofu": { "encounter": { - 1: "I'mma serve you a full course o' Water-type Pokémon! Don't try to eat 'em, though!" + 1: "我會給你上一整道水系寶可夢大餐!\n但別真吃了它們!", }, "victory": { - 1: "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!" + 1: "吃了嗎!你真是活力又新鮮啊,\n不是嗎!$就是有點太鮮活了!", }, "defeat": { - 1: "You come back to see me again now, ya hear?" + 1: "你要再來找我,聽見了嗎?", } }, "tulip": { "encounter": { - 1: "Allow me to put my skills to use to make your cute little Pokémon even more beautiful!" + 1: "請讓我運用我的化妝技巧,$讓你可愛的小寶可夢變得更美麗!", }, "victory": { - 1: "Your strength has a magic to it that cannot be washed away." + 1: "你妝點的力量宛如魔法加固,\n完全沖洗不掉啊。", }, "defeat": { - 1: "You know, in my line of work, people who lack talent in one area or the other often fade away quickly—never to be heard of again." + 1: "你知道嗎,在我這行,\n那些沒天賦的人往往會很快消失,$再也不會被提起。", } }, "sidney": { "encounter": { - 1: `I like that look you're giving me. I guess you'll give me a good match. - $That's good! Looking real good! All right! - $You and me, let's enjoy a battle that can only be staged here!`, + 1: "你給我的印象不錯,\n我猜這會是一場精彩的對戰。$很棒!看起來真的很棒!$你和我,讓我們享受一場\n只能在這裡上演的戰鬥吧!", }, "victory": { - 1: "Well, how do you like that? I lost! Eh, it was fun, so it doesn't matter." + 1: "嗯,你覺得怎樣?我輸了!\n嗯,不過這很有趣,所以無所謂啊。", }, "defeat": { - 1: "No hard feelings, alright?" + 1: "別介意,OK?", } }, "phoebe": { "encounter": { - 1: `While I trained, I gained the ability to commune with Ghost-type Pokémon. - $Yes, the bond I developed with Pokémon is extremely tight. - $So, come on, just try and see if you can even inflict damage on my Pokémon!`, + 1: "過去我在修行時得到了\n能與幽靈寶可夢親密交流的能力。$沒錯,我和寶可夢之間\n有著強烈的羈絆。$那麼,來試試看你有沒有能力\n傷到我的寶可夢吧!", }, "victory": { - 1: "Oh, darn. I've gone and lost." + 1: "哦,天呀。我輸了。", }, "defeat": { - 1: "I look forward to battling you again sometime!" + 1: "我期待著下次再和你戰鬥!", } }, "glacia": { "encounter": { - 1: `All I have seen are challenges by weak Trainers and their Pokémon. - $What about you? It would please me to no end if I could go all out against you!`, + 1: "我在這兒見到的盡是些\n弱不禁風的訓練家和寶可夢。$你又如何呢?如果你能讓我不得不用\n上全力的話就再好不過了!", }, "victory": { - 1: `You and your Pokémon… How hot your spirits burn! - $The all-consuming heat overwhelms. - $It's no surprise that my icy skills failed to harm you.`, + 1: "你和你的寶可夢…\n你們的靈魂燃燒得多麼熱烈啊!$這股激烈的熱能仿佛能征服一切。\n$難怪我的冰屬性技巧也奈何不了你了。", }, "defeat": { - 1: "A fiercely passionate battle, indeed." + 1: "一場充滿激情的戰鬥,確實。", } }, "drake": { "encounter": { - 1: `For us to battle with Pokémon as partners, do you know what it takes? Do you know what is needed? - $If you don't, then you will never prevail over me!`, + 1: "對於我們這些將寶可夢視為\n同伴一同戰鬥的訓練家來說,$你知道怎樣才能贏得勝利嗎?\n你知道獲得勝利的條件嗎?$如果你不知道,\n那麼你永遠也無法戰勝我!", }, "victory": { - 1: "Superb, it should be said." + 1: "幹得漂亮,就是這樣。", }, "defeat": { - 1: "I gave my all for that battle!" + 1: "我在這場戰鬥中全力以赴了!", } }, "wallace": { "encounter": { - 1: `There's something about you… A difference in your demeanor. - $I think I sense that in you. Now, show me. Show me the power you wield with your Pokémon. - $And I, in turn, shall present you with a performance of illusions in water by me and my Pokémon!`, + 1: "你的氣質變了,\n我能感覺到這一點。$現在,把你和你的寶可夢\n的力量展現給我看吧。$作為回禮,就由我和我的寶可夢\n演出一場水之幻影吧!", }, "victory": { - 1: `Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. - $I find much joy in having met you and your Pokémon. You have proven yourself worthy.`, + 1: "精彩。此刻,我能從你身上感覺到\n身為寶可夢訓練家的可靠與高貴。$我真榮幸能遇到你和你的寶可夢。", }, "defeat": { - 1: "A grand illusion!" + 1: "偉大的幻影!", } }, "lorelei": { "encounter": { - 1: `No one can best me when it comes to icy Pokémon! Freezing moves are powerful! - $Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?`, + 1: "只要能讓我用冰屬性寶可夢,\n就絕對沒人能贏得過我!\n能凍住對方可是很厲害的哦!$因為如果被凍住,你的寶可夢就無法動彈了!\n啊哈哈!你做好覺悟了吧!", }, "victory": { - 1: "How dare you!" + 1: "你怎麼敢!", }, "defeat": { - 1: "There's nothing you can do once you're frozen." + 1: "一旦你被凍結,你就什麼都做不了。", } }, "will": { "encounter": { - 1: `I have trained all around the world, making my psychic Pokémon powerful. - $I can only keep getting better! Losing is not an option!`, + 1: "我曾經環遊世界,\n日以繼夜地做著超能力寶可夢的修行之旅。$我會不斷變強!沒理由會在這裡輸掉!", }, "victory": { - 1: "I… I can't… believe it…" + 1: "……不會吧……", }, "defeat": { - 1: "That was close. I wonder what it is that you lack." + 1: "就差一點。\n我想知道你缺少了什麼。", } }, "malva": { "encounter": { - 1: `I feel like my heart might just burst into flames. - $I'm burning up with my hatred for you, runt!`, + 1: "我的內心可是一直燃燒著呢。$燃燒著對你的怒火!", }, "victory": { - 1: "What news… So a new challenger has defeated Malva!" + 1: "挑戰者出色地擊敗了四天王之一,帕琦拉。", }, "defeat": { - 1: "I am delighted! Yes, delighted that I could squash you beneath my heel." + 1: "真開心啊,能將你徹底粉碎!", } }, "hala": { "encounter": { - 1: "Old Hala is here to make you holler!" + 1: "老哈拉讓你放開嗓子!" }, "victory": { - 1: "I could feel the power you gained on your journey." + 1: "我能感受到你在旅途中所獲得的力量。" }, "defeat": { - 1: "Haha! What a delightful battle!" + 1: "啊哈哈。多麼有趣的戰鬥。" } }, "molayne": { "encounter": { - 1: `I gave the captain position to my cousin Sophocles, but I'm confident in my ability. - $My strength is like that of a supernova!`, + 1: "我將隊長的位置讓給了我的表弟馬瑪內,\n但我對自己的能力很有信心。 $我的力量就像超新星一樣!", }, "victory": { - 1: "I certainly found an interesting Trainer to face!" + 1: "我發現了一個有趣的訓練師對手!", }, "defeat": { - 1: "Ahaha. What an interesting battle." + 1: "啊哈哈。多麼有趣的戰鬥。", } }, "rika": { "encounter": { - 1: "I'd say I'll go easy on you, but… I'd be lying! Think fast!" + 1: "我要對你手下留情,但……騙你的啦! $好好動腦!", }, "victory": { - 1: "Not bad, kiddo." + 1: "不錯,小子。", }, "defeat": { - 1: "Nahahaha! You really are something else, kiddo!" + 1: "啊哈哈哈哈!你真的很特别,小子!", } }, "bruno": { "encounter": { - 1: "We will grind you down with our superior power! Hoo hah!" + 1: "我們將用勢不可擋的力量磨滅你!呼哈!", }, "victory": { - 1: "Why? How could I lose?" + 1: "為什麼?我怎麼會輸?", }, "defeat": { - 1: "You can challenge me all you like, but the results will never change!" + 1: "你可以隨意挑戰我,\n但結果永遠不會改變!", } }, "bugsy": { "encounter": { - 1: "I'm Bugsy! I never lose when it comes to bug Pokémon!" + 1: "我是阿筆!\n對蟲系寶可夢的熟悉不會輸給任何人的!", }, "victory": { - 1: "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win." + 1: "哇,太棒了!\n你是個寶可夢專家!$我的研究還沒有完成。\n好吧,你贏了。", }, "defeat": { - 1: "Thanks! Thanks to our battle, I was also able to make progress in my research!" + 1: "謝謝!多虧了我們的戰鬥,\n我的研究也取得了進展!", } }, "koga": { "encounter": { - 1: "Fwahahahaha! Pokémon are not merely about brute force--you shall see soon enough!" + 1: "哇哈哈哈哈!$寶可夢不僅僅是關於蠻力,拭目以待吧!", }, "victory": { - 1: "Ah! You've proven your worth!" + 1: "啊!你證明了自己!", }, "defeat": { - 1: "Have you learned to fear the techniques of the ninja?" + 1: "懂不懂要對忍者的技巧心神畏懼?", } }, "bertha": { "encounter": { - 1: "Well, would you show this old lady how much you've learned?" + 1: "啊,讓老婆婆看看你學到了什麼?", }, "victory": { - 1: `Well! Dear child, I must say, that was most impressive. - $Your Pokémon believed in you and did their best to earn you the win. - $Even though I've lost, I find myself with this silly grin!`, + 1: "好吧,親愛的孩子,\n不得不說,那令人印象深刻。$你的寶可夢相信你並盡最大努力為你贏得勝利。$儘管我輸了,\n我也止不住笑呢!", }, "defeat": { - 1: "Hahahahah! Looks like this old lady won!" + 1: "哈哈哈!看來老婆婆我贏了!", } }, "lenora": { "encounter": { - 1: "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!" + 1: "那麼,挑戰者,讓我來研究$你與你精心養育的寶可夢要如何戰鬥!", }, "victory": { - 1: "My theory about you was correct. You're more than just talented… You're motivated! I salute you!" + 1: "我關於你的理論是正確的。$你不僅僅是有天賦……你很努力!\n我向你致敬!", }, "defeat": { - 1: "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!" + 1: "啊哈哈!如果你輸了,\n一定要分析原因,$並在下一場戰鬥中運用那些知識!", } }, "siebold": { "encounter": { - 1: "As long as I am alive, I shall strive onward to seek the ultimate cuisine... and the strongest opponents in battle!" + 1: "只要我活著,我將不斷努力尋求終極美食…$以及和最強的對手戰鬥!", }, "victory": { - 1: "I shall store my memory of you and your Pokémon forever away within my heart." + 1: "您的事蹟,我志米銘記在心。", }, "defeat": { - 1: `Our Pokémon battle was like food for my soul. It shall keep me going. - $That is how I will pay my respects to you for giving your all in battle!`, + 1: "我們的寶可夢戰鬥就像我靈魂的養料。\n它將讓我繼續前進。$這就是我將向你表示敬意的方式,\n感謝你在戰鬥中全力以赴!", } }, "roxie": { "encounter": { - 1: "Get ready! I'm gonna knock some sense outta ya!" + 1: "準備好了嗎!我要給你上一課!", }, "victory": { - 1: "Wild! Your reason's already more toxic than mine!" + 1: "夠野的!你的想法比我的還要毒!", }, "defeat": { - 1: "Hey, c'mon! Get serious! You gotta put more out there!" + 1: "嘿,拜託!認真點!\n你要加把勁啊!", } }, "olivia": { "encounter": { - 1: "No introduction needed here. Time to battle me, Olivia!" + 1: "沒什麼開場白。\n是時候和我麗姿,戰鬥了!", }, "victory": { - 1: "Really lovely… Both you and your Pokémon…" + 1: "真的很可愛……你和你的寶可夢……", }, "defeat": { - 1: "Mmm-hmm." + 1: "嗯哼。", } }, "poppy": { "encounter": { - 1: "Oooh! Do you wanna have a Pokémon battle with me?" + 1: "哦!你想和我進行寶可夢對戰麼?", }, "victory": { - 1: "Uagh?! Mmmuuuggghhh…" + 1: "嗚哇?!嘛……", }, "defeat": { - 1: `Yaaay! I did it! I de-feet-ed you! You can come for… For… An avenge match? - $Come for an avenge match anytime you want!`, + 1: "耶!我做到了!我擊~敗~了~你!\n你可以來…打…復仇之戰?$只要你想,隨時來打復仇之戰吧!", } }, "agatha": { "encounter": { - 1: "Pokémon are for battling! I'll show you how a real Trainer battles!" + 1: "寶可夢是用來戰鬥的!我會讓你看看真正訓練家的戰鬥!" }, "victory": { - 1: "Oh my! You're something special, child!" + 1: "哦,我的天!你真是個特別的孩子!" }, "defeat": { - 1: "Bahaha. That's how a proper battle's done!" + 1: "哈哈哈,這才是正確的戰鬥方式!" } }, "flint": { "encounter": { - 1: "Hope you're warmed up, cause here comes the Big Bang!" + 1: "希望你已經熱身完畢,\n因為這裡即將大爆炸!", }, "victory": { - 1: "Incredible! Your moves are so hot, they make mine look lukewarm!" + 1: "不可思議!$你的動作如此火熱,讓我看起來溫吞吞的!", }, "defeat": { - 1: "Huh? Is that it? I think you need a bit more passion." + 1: "嗯?就這嗎?\n我覺得你得再激情點。", } }, "grimsley": { "encounter": { - 1: "The winner takes everything, and there's nothing left for the loser." + 1: "一無所有,\n或者,贏下所有!", }, "victory": { - 1: "When one loses, they lose everything… The next thing I'll look for will be victory, too!" + 1: "一旦失敗,\n就意味著失去一切……$下一次我要追尋勝利!", }, "defeat": { - 1: "If somebody wins, the person who fought against that person will lose." + 1: "如果有人贏了,\n和他對戰的人就會輸。", } }, "caitlin": { "encounter": { - 1: `It's me who appeared when the flower opened up. You who have been waiting… - $You look like a Pokémon Trainer with refined strength and deepened kindness. - $What I look for in my opponent is superb strength… - $Please unleash your power to the fullest!`, + 1: "當花兒綻開時、我便出現。\n成為你在等待的人…$你似乎同時具備實力和善意$我所尋找的是擁有卓越力量的對手…$請用出你的全力吧!", }, "victory": { - 1: "My Pokémon and I learned so much! I offer you my thanks." + 1: "我和我的寶可夢學到了很多!非常感謝。", }, "defeat": { - 1: "I aspire to claim victory with elegance and grace." + 1: "我渴望以優雅的姿態取得勝利。", } }, "diantha": { "encounter": { - 1: `Battling against you and your Pokémon, all of you brimming with hope for the future… - $Honestly, it just fills me up with energy I need to keep facing each new day! It does!`, + 1: "與你的寶可夢對戰\n讓你充滿了未來的希望…$說真的,這讓我更有活力地面對新的一天,確實如此!", }, "victory": { - 1: "Witnessing the noble spirits of you and your Pokémon in battle has really touched my heart…" + 1: "擁有高尚靈魂的訓練家和寶可夢的身姿,\n讓我的心激烈地震顫…", }, "defeat": { - 1: "Oh, fantastic! What did you think? My team was pretty cool, right?" + 1: "哦,太棒了!你覺得怎麼樣?\n我的隊伍很酷吧~對吧?", } }, "wikstrom": { "encounter": { - 1: `Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! - $Let the battle begin! En garde!`, + 1: "年輕的挑戰者,幸會!\n我乃是著名的鋼鐵之刃,公爵雁鎧! $讓我們開始戰鬥吧!預備!", }, "victory": { - 1: "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!" + 1: "輝煌!你與你尊貴的\n寶可夢之間的信任居然勝過了我!", }, "defeat": { - 1: `What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! - $Winning against such a worthy opponent doth give my soul wings--thus do I soar!`, + 1: "哦哦哦!這是怎麼回事,\n我的心止不住地在震顫! $與如此有價值的對手的勝利\n讓我的靈魂飛翔——我心翱翔!", } }, "acerola": { "encounter": { - 1: "Battling is just plain fun! Come on, I can take you!" + 1: "對戰只是找個樂子!來吧,我來會會你!", }, "victory": { - 1: "I'm… I'm speechless! How did you do it?!" + 1: "我……我說不出話!你是怎麼做到的?!", }, "defeat": { - 1: "Ehaha! What an amazing victory!" + 1: "哈哈!真是嚇人倒怪的勝利呀!", } }, "larry_elite": { "encounter": { - 1: `Hello there… It's me, Larry. - $I serve as a member of the Elite Four too, yes… Unfortunately for me.`, + 1: "……你好,我是青木。$麻煩的是我還要兼任四天王。", }, "victory": { - 1: "Well, that took the wind from under our wings…" + 1: "好吧,我們翅膀下的疾風止於你這了啊…", }, "defeat": { - 1: "It's time for a meeting with the boss." + 1: "是時候和老闆開會了。", } }, "lance": { "encounter": { - 1: "I've been waiting for you. Allow me to test your skill.", - 2: "I thought that you would be able to get this far. Let's get this started." + 1: "我一直在等你。讓我來試試你有幾斤幾兩。", + 2: "我知道你能走這麼遠。讓我們開始吧。", }, "victory": { - 1: "You got me. You are magnificent!", - 2: "I never expected another trainer to beat me… I'm surprised." + 1: "被你拿下了啊。你太出色了!", + 2: "我從沒想到會有另一個訓練師打敗我……$我很驚訝。", }, "defeat": { - 1: "That was close. Want to try again?", - 2: "It's not that you are weak. Don't let it bother you." + 1: "就差一點。想再試一次嗎?", + 2: "我沒覺得你弱,別因此困擾。", } }, "karen": { "encounter": { - 1: "I am Karen. Would you care for a showdown with my Dark-type Pokémon?", - 2: "I am unlike those you've already met.", - 3: "You've assembled a charming team. Our battle should be a good one." + 1: "我是梨花,你想和我的惡屬性寶可夢$來一場對決嗎?", + 2: "我和你見過的那些人不一樣。", + 3: "你組建了一支迷人的隊伍。$我們的戰鬥應該會是場精彩的比賽。", }, "victory": { - 1: "No! I can't win. How did you become so strong?", - 2: "I will not stray from my chosen path.", - 3: "The Champion is looking forward to meeting you." + 1: "不!我贏不了。你是怎麼做到變得這麼強的?", + 2: "我不會偏離我所選擇的道路。", + 3: "冠軍正期待與你見面。", }, "defeat": { - 1: "That's about what I expected.", - 2: "Well, that was relatively entertaining.", - 3: "Come visit me anytime." + 1: "意料之中。", + 2: "嗯,還算有點意思。", + 3: "隨時歡迎你來找我。", } }, "milo": { "encounter": { - 1: `Sure seems like you understand Pokémon real well. - $This is gonna be a doozy of a battle! - $I'll have to Dynamax my Pokémon if I want to win!`, + 1: "看起來你顯然很了解寶可夢。$這會是一場激烈的戰鬥!$如果我想贏,我得讓我的寶可夢極巨化!", }, "victory": { - 1: "The power of Grass has wilted… What an incredible Challenger!" + 1: "草的力量凋謝了…多麼不可思議的挑戰者!", }, "defeat": { - 1: "This'll really leave you in shock and awe." + 1: "這必將讓你大吃一驚。", } }, "lucian": { "encounter": { - 1: `Just a moment, please. The book I'm reading has nearly reached its thrilling climax… - $The hero has obtained a mystic sword and is about to face their final trial… Ah, never mind. - $Since you've made it this far, I'll put that aside and battle you. - $Let me see if you'll achieve as much glory as the hero of my book!,` + 1: "請稍等,我正在讀的書\n正要進入最精彩的部分…$英雄獲得了一把神秘之劍,\n即將面臨最後的考驗…啊,算了。$既然你能走到這一步,\n我就不說這些了,和你戰鬥吧。$讓我看看你是否\n能像我書中的主角一樣榮耀!", }, "victory": { - 1: "I see… It appears you've put me in checkmate." + 1: "我明白了…看來你把我逼入了絕境。", }, "defeat": { - 1: "I have a reputation to uphold." + 1: "我得維護我的名譽。", } }, "drasna": { "encounter": { - 1: `You must be a strong Trainer. Yes, quite strong indeed… - $That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!` + 1: "你很厲害吧,\n而且相當相當地厲害呢。$我很高興,能和這樣的對手交手,\n就能更好地培養寶可夢們了。", }, "victory": { - 1: "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!" + 1: "哎呀,就這麼結束了,\n不好意思,可以的話歡迎再來。", }, "defeat": { - 1: "How can this be?" + 1: "怎麼會這樣?", } }, "kahili": { "encounter": { - 1: "So, here you are… Why don't we see who the winds favor today, you… Or me?" + 1: "那麼,既然來了……\n要不來看看今天的風更青睞誰?$是你……還是我?", }, "victory": { - 1: "It's frustrating to me as a member of the Elite Four, but it seems your strength is the real deal." + 1: "讓我這個四天王都感到沮喪,$看來你的力量貨真價實。", }, "defeat": { - 1: "That was an ace!" + 1: "那真是一記好球!", } }, "hassel": { "encounter": { - 1: "Prepare to learn firsthand how the fiery breath of ferocious battle feels!" + 1: "讓你親身感受一下什麼叫做猛烈的對戰氣息吧!", }, "victory": { - 1: `Fortune smiled on me this time, but… - $Judging from how the match went, who knows if I will be so lucky next time.`, + 1: "這次幸運之神對我微笑了,但是……$誰知道我下次會不會這麼幸運。", }, "defeat": { - 1: "That was an ace!" + 1: "那可真厲害!", } }, "blue": { "encounter": { - 1: "You must be pretty good to get this far." + 1: "能走到這裡,你一定非常優秀。", }, "victory": { - 1: "I've only lost to him and now to you… Him? Hee, hee…" + 1: "我只輸給過他,現在又是你……?$你問他是誰?哈哈哈……", }, "defeat": { - 1: "See? My power is what got me here." + 1: "看吧?我的實力就是我來到這裡的原因。", } }, "piers": { "encounter": { - 1: "Get ready for a mosh pit with me and my party! Spikemuth, it's time to rock!" + 1: "準備好和我的隊伍來個大狂歡吧!$尖釘鎮,是時候嗨起來了!", }, "victory": { - 1: "Me an' my team gave it our best. Let's meet up again for a battle some time…" + 1: "我和我的隊伍已經盡力了。$找個時間再來對戰吧……", }, "defeat": { - 1: "My throat's ragged from shoutin'… But 'at was an excitin' battle!" + 1: "我的喉嚨因為呼喊而變得沙啞……$但這是一場激動人心的戰鬥!", } }, "red": { "encounter": { - 1: "…!" + 1: "…!", }, "victory": { - 1: "…?" + 1: "…?", }, "defeat": { - 1: "…!" + 1: "…!", } }, "jasmine": { "encounter": { - 1: "Oh… Your Pokémon are impressive. I think I will enjoy this." + 1: "哦……你的寶可夢給人印象深刻。$我想我會享受這場戰鬥的。", }, "victory": { - 1: "You are truly strong. I'll have to try much harder, too." + 1: "你真的很強。我也得加把勁了。", }, "defeat": { - 1: "I never expected to win." + 1: "我從沒想到會贏。", } }, "lance_champion": { "encounter": { - 1: "I am still the Champion. I won't hold anything back." + 1: "我依舊是冠軍,所以我不會留情的。", }, "victory": { - 1: "This is the emergence of a new Champion." + 1: "這就是新冠軍的崛起。", }, "defeat": { - 1: "I successfully defended my Championship." + 1: "我成功捍衛了冠軍的頭銜。", } }, "steven": { "encounter": { - 1: `Tell me… What have you seen on your journey with your Pokémon? - $What have you felt, meeting so many other Trainers out there? - $Traveling this rich land… Has it awoken something inside you? - $I want you to come at me with all that you've learned. - $My Pokémon and I will respond in turn with all that we know!`, + 1: "告訴我…你在和寶可夢的旅途過程中看到了什麼?$邂逅了那麼多的訓練師,\n你都會有什麼樣的感受呢?$在這豐饒的大地上旅行…\n有沒有喚醒你內在的某種東西?$你不如就用一場對戰來告訴我你心中的答案吧。$我也會和我的寶可夢用這種方式\n將我們所知道的告訴你的!", }, "victory": { - 1: "So I, the Champion, fall in defeat…" + 1: "沒想到連我這個聯盟冠軍\n都敗在你的手上了呢…", }, "defeat": { - 1: "That was time well spent! Thank you!" + 1: "正如我所期待的。謝謝!", } }, "cynthia": { "encounter": { - 1: "I, Cynthia, accept your challenge! There won't be any letup from me!" + 1: "我,竹蘭,接受你的挑戰!\n我是絕不會手軟的!", }, "victory": { - 1: "No matter how fun the battle is, it will always end sometime…" + 1: "無論對戰多麼有趣,\n它總會有結束的時候……", }, "defeat": { - 1: "Even if you lose, never lose your love of Pokémon." + 1: "即使你輸了,\n也永遠不要失去你對寶可夢的熱愛。", } }, "iris": { "encounter": { - 1: `Know what? I really look forward to having serious battles with strong Trainers! - $I mean, come on! The Trainers who make it here are Trainers who desire victory with every fiber of their being! - #And they are battling alongside Pokémon that have been through countless difficult battles! - $If I battle with people like that, not only will I get stronger, my Pokémon will, too! - $And we'll get to know each other even better! OK! Brace yourself! - $I'm Iris, the Pokémon League Champion, and I'm going to defeat you!`, + 1: "你知道嗎?\n我真的很期待和強大的訓練師進行認真的戰鬥!$我的意思是,來吧!\n到達這裡的是那些渴望勝利的訓練師,$他們與經歷過無數艱難\n戰鬥的寶可夢一起戰鬥!$如果我和那樣的人戰鬥,\n不僅我會變得更強,我的寶可夢也會!$我們也會更好地了解彼此!\n好!做好準備吧!$我是艾莉絲,寶可夢聯盟冠軍,\n我,將打敗你!", }, "victory": { - 1: "Aghhhh… I did my best, but we lost…" + 1: "啊……我盡力了,但我們輸了……", }, "defeat": { - 1: "Yay! We won!" + 1: "耶!我們贏了!", } }, "hau": { "encounter": { - 1: `I wonder if a Trainer battles differently depending on whether they're from a warm region or a cold region. - $Let's test it out!`, + 1: "我想知道,訓練師是否會根據他們是\n來自溫暖地區還是寒冷地區而以不同的方式戰鬥。$讓我們來測試一下!", }, "victory": { - 1: "That was awesome! I think I kinda understand your vibe a little better now!" + 1: "那太棒了!我覺得我現在有點了解你的感覺了!", }, "defeat": { - 1: "Ma-an, that was some kinda battle!" + 1: "老鐵,這才叫戰鬥!", } }, "geeta": { "encounter": { - 1: `I decided to throw my hat in the ring once more. - $Come now… Show me the fruits of your training.`, + 1: "我決定再試一次。$來吧…讓我看看你的訓練成果。", }, "victory": { - 1: "I eagerly await news of all your achievements!" + 1: "我期待著你的成就!", }, "defeat": { - 1: "What's the matter? This isn't all, is it?" + 1: "怎麼,這就結束了?", } }, "nemona": { "encounter": { - 1: "Yesss! I'm so psyched! Time for us to let loose!" + 1: "耶!我太興奮了!讓我們稍微放輕鬆!", }, "victory": { - 1: "Well, that stinks, but I still had fun! I'll getcha next time!" + 1: "好吧,太糟了,但我還是玩得很開心!$下次我一定會贏你!", }, "defeat": { - 1: "Well, that was a great battle! Fruitful for sure." + 1: "好吧,那是一場很棒的戰鬥!$肯定是會有收穫的啦。", } }, "leon": { "encounter": { - 1: "We're gonna have an absolutely champion time!" + 1: "來享受一段冠軍時刻吧!", }, "victory": { - 1: `My time as Champion is over… - $But what a champion time it's been! - $Thank you for the greatest battle I've ever had!`, + 1: "我的冠軍生涯結束了……但這是多麼美好的冠軍時刻啊!但這是多麼美好的冠軍時刻啊!謝謝你給了我最精彩的一戰!", }, "defeat": { - 1: "An absolute champion time, that was!" + 1: "名副其實的冠軍時刻!", } }, "whitney": { "encounter": { - 1: "Hey! Don't you think Pokémon are, like, super cute?" + 1: "嘿!你不認為寶可夢超級可愛嗎?", }, "victory": { - 1: "Waaah! Waaah! You're so mean!" + 1: "哇啊!哇啊!你太壞了!", }, "defeat": { - 1: "And that's that!" + 1: "就是這樣!", } }, "chuck": { "encounter": { - 1: "Hah! You want to challenge me? Are you brave or just ignorant?" + 1: "哈!你想挑戰我?你是勇敢還是無知?", }, "victory": { - 1: "You're strong! Would you please make me your apprentice?" + 1: "你很強!能不能收我為徒?", }, "defeat": { - 1: "There. Do you realize how much more powerful I am than you?" + 1: "搞定。你明白我比你強得多了嗎?", } }, "katy": { "encounter": { - 1: "Don't let your guard down unless you would like to find yourself knocked off your feet!" + 1: "不要放鬆警惕,除非你想被蟲絲絆倒哦!", }, "victory": { - 1: "All of my sweet little Pokémon dropped like flies!" + 1: "我可愛的寶可夢們都像蒼蠅一樣墜落了!", }, "defeat": { - 1: "Eat up, my cute little Vivillon!" + 1: "開飯啦,我可愛的彩粉蝶!", } }, "pryce": { "encounter": { - 1: "Youth alone does not ensure victory! Experience is what counts." + 1: "年輕不代表能獲得勝利!經驗才是關鍵。", }, "victory": { - 1: "Outstanding! That was perfect. Try not to forget what you feel now." + 1: "無與倫比!贏得完美,試著不要忘記你現在的感受。", }, "defeat": { - 1: "Just as I envisioned." + 1: "正如我所料。", } }, "clair": { "encounter": { - 1: "Do you know who I am? And you still dare to challenge me?" + 1: "你知道我是誰嗎?知道還敢挑戰我?", }, "victory": { - 1: "I wonder how far you can get with your skill level. This should be fascinating." + 1: "我想知道以你現在的水平能走多遠,有趣。", }, "defeat": { - 1: "That's that." + 1: "就是這樣。", } }, "maylene": { "encounter": { - 1: `I've come to challenge you now, and I won't hold anything back. - $Please prepare yourself for battle!`, + 1: "我現在要挑戰你,我不會保留任何實力。$請準備好戰鬥!", }, "victory": { - 1: "I admit defeat…" + 1: "是我輸了…", }, "defeat": { - 1: "That was awesome." + 1: "太棒了。", } }, "fantina": { "encounter": { - 1: `You shall challenge me, yes? But I shall win. - $That is what the Gym Leader of Hearthome does, non?`, + 1: "你來挑戰吧。我會勝利。$這就是家緣市的道館館主。", }, "victory": { - 1: "You are so fantastically strong. I know why I have lost." + 1: "你是最強的,我認輸了。", }, "defeat": { - 1: "I am so, so, very happy!" + 1: "我非常,非常高興!", } }, "byron": { "encounter": { - 1: `Trainer! You're young, just like my son, Roark. - $With more young Trainers taking charge, the future of Pokémon is bright! - $So, as a wall for young people, I'll take your challenge!`, + 1: "和我兒子瓢太一樣的年輕人啊!$我相信培養年輕人\n關係到寶可夢光明的未來!$為此就讓我來成為\n年輕人必須跨越的堡壘吧!", }, "victory": { - 1: "Hmm! My sturdy Pokémon--defeated!" + 1: "唔!我千錘百煉的寶可夢!", }, "defeat": { - 1: "Gwahahaha! How were my sturdy Pokémon?!" + 1: "哈哈哈哈!怎麼樣!我千錘百煉的寶可夢!", } }, "olympia": { "encounter": { - 1: "An ancient custom deciding one's destiny. The battle begins!" + 1: "戰鬥是決定命運的古老傳統。讓我們開始吧!", }, "victory": { - 1: "Create your own path. Let nothing get in your way. Your fate, your future." + 1: "創造你自己的道路。$不要讓任何東西阻擋你的路、你的命運、你的未來。", }, "defeat": { - 1: "Our path is clear now." + 1: "我們的道路現在已經清晰了。", } }, "volkner": { "encounter": { - 1: `Since you've come this far, you must be quite strong… - $I hope you're the Trainer who'll make me remember how fun it is to battle!`, + 1: "能留到最後的訓練家想必肯定是很強的…$希望你會是能讓我回憶起\n寶可夢對戰樂趣的訓練家!", }, "victory": { - 1: `You've got me beat… - $Your desire and the noble way your Pokémon battled for you… - $I even felt thrilled during our match. That was a very good battle.`, + 1: "我輸了…$你的心意,寶可夢的不顧一切。$戰鬥的時候就讓我熱血沸騰。", }, "defeat": { - 1: `It was not shocking at all… - $That is not what I wanted!`, + 1: "完全沒感覺…$和我希望的完全不一樣!", } }, "burgh": { "encounter": { - 1: `M'hm… If I win this battle, I feel like I can draw a picture unlike any before it. - $OK! I can hear my battle muse loud and clear. Let's get straight to it!`, - 2: `Of course, I'm really proud of all of my Pokémon! - $Well now… Let's get right to it!` + 1: "唔…我有預感,\n只要贏了這場戰鬥就能畫出更好的畫來…$嗯!戰鬥充滿了幻象!那麼,馬上開始吧。", + 2: "當然,我對我所有的寶可夢都相當驕傲! $現在…讓我們馬上開始吧!", }, "victory": { - 1: "Is it over? Has my muse abandoned me?", - 2: "Hmm… It's over! You're incredible!" + 1: "結束了嗎?我的女神拋棄我了嗎?", + 2: "啊唔,輸了……你還真是很強啊。", }, "defeat": { - 1: "Wow… It's beautiful somehow, isn't it…", - 2: `Sometimes I hear people say something was an ugly win. - $I think if you're trying your best, any win is beautiful.` + 1: "唔啊……好……好美啊!", + 2: "偶爾也有一些不是很好看的勝利,$但只要努力了,\n不管怎麼樣的戰鬥,都是很美麗的。", } }, "elesa": { "encounter": { - 1: `C'est fini! When I'm certain of that, I feel an electric jolt run through my body! - $I want to feel the sensation, so now my beloved Pokémon are going to make your head spin!`, + 1: "最後一擊!\n在確信這一點的時候全身會流淌過電流!$為追求這個快感,\n我要用可愛的寶可夢們讓你頭暈眼花。", }, "victory": { - 1: "I meant to make your head spin, but you shocked me instead." + 1: "本想讓你頭暈的,\n結果我倒反被你電到了。", }, "defeat": { - 1: "That was unsatisfying somehow… Will you give it your all next time?" + 1: "感覺還不夠啊……下次能使出全力來嗎?", } }, "skyla": { "encounter": { - 1: `It's finally time for a showdown! That means the Pokémon battle that decides who's at the top, right? - $I love being on the summit! 'Cause you can see forever and ever from high places! - $So, how about you and I have some fun?`, + 1: "終於到決戰了!\n這是決定頂點的寶可夢對戰吧?$我最喜歡頂點了!\n在高的地方能看到很遠很遠!$好了!就讓我和你好好地玩一場吧!", }, "victory": { - 1: "Being your opponent in battle is a new source of strength to me. Thank you!" + 1: "和你的戰鬥讓我更強了……謝謝。", }, "defeat": { - 1: "Win or lose, you always gain something from a battle, right?" + 1: "不管是贏了還是輸了,戰鬥都能得到一些東西。", } }, "brycen": { "encounter": { - 1: `There is also strength in being with other people and Pokémon. - $Receiving their support makes you stronger. I'll show you this power!`, + 1: "有其他的人和寶可夢在一起,$這份支持會讓自己更強…\n讓我來給你展示一下這樣的強大吧!", }, "victory": { - 1: "The wonderful combination of you and your Pokémon! What a beautiful friendship!" + 1: "你和你的寶可夢!配合得天衣無縫!\n華麗的友情!", }, "defeat": { - 1: "Extreme conditions really test you and train you!" + 1: "嘗試極限!鍛鍊!", } }, "drayden": { "encounter": { - 1: `What I want to find is a young Trainer who can show me a bright future. - $Let's battle with everything we have: your skill, my experience, and the love we've raised our Pokémon with!`, + 1: "現在我尋求的是\n能讓我看到光明未來的年輕訓練家。$你有多少實力,就讓我用我的經驗,\n我對寶可夢傾注的愛來驗證吧!", }, "victory": { - 1: "This intense feeling that floods me after a defeat… I don't know how to describe it." + 1: "失敗後湧現的這灼熱的意志…\n該怎麼說呢…", }, "defeat": { - 1: "Harrumph! I know your ability is greater than that!" + 1: "啊啊啊!你的實力就這種程度嗎!", } }, "grant": { "encounter": { - 1: `There is only one thing I wish for. - $That by surpassing one another, we find a way to even greater heights.`, + 1: "我只期待一件事。. $通過超越彼此,\n我們找到通往更高境界的道路。", }, "victory": { - 1: "You are a wall that I am unable to surmount!" + 1: "你是一堵我無法逾越的牆!", }, "defeat": { - 1: `Do not give up. - $That is all there really is to it. - $The most important lessons in life are simple.`, + 1: "不要放棄。\n這就是人生的真諦。$大道至簡。", } }, "korrina": { "encounter": { - 1: "Time for Lady Korrina's big appearance!" + 1: "小女子科爾尼來大顯身手啦!", }, "victory": { - 1: "It's your very being that allows your Pokémon to evolve!" + 1: "正因為有你,\n才能讓你的寶可夢進化!", }, "defeat": { - 1: "What an explosive battle!" + 1: "好勁爆的戰鬥呀!", } }, "clemont": { "encounter": { - 1: "Oh! I'm glad that we got to meet!" + 1: "哦!我很高興我們能見面!", }, "victory": { - 1: "Your passion for battle inspires me!" + 1: "你對戰鬥的熱情激勵了我!", }, "defeat": { - 1: "Looks like my Trainer-Grow-Stronger Machine, Mach 2 is really working!" + 1: "看來我的訓練師成長強化機-馬克2號,\n真的起作用了!", } }, "valerie": { "encounter": { - 1: `Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. - $Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. - $The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.`, + 1: "哦,這不是一個年輕的訓練師嗎……\n能這樣遇見你真是太好了。 $我想你已經獲得了這場戰鬥的資格,\n作為對你努力的獎勵。 $難以捉摸的妖精可能看起來像微風一樣脆弱,\n像花朵一樣精緻,但很堅強。", }, "victory": { - 1: "I hope that you will find things worth smiling about tomorrow…" + 1: "我希望明天你也能找到一些值得會心微笑的事物……", }, "defeat": { - 1: "Oh goodness, what a pity…" + 1: "哦,天哪,這太遺憾了……", } }, "wulfric": { "encounter": { - 1: `You know what? We all talk big about what you learn from battling and bonds and all that… - $But really, I just do it 'cause it's fun. - $Who cares about the grandstanding? Let's get to battling!`, + 1: "你知道嗎?\n我們都說戰鬥能學到東西,羈絆之類的,$但實際上,我這麼做只是因為有趣。 $誰在乎那些華而不實的東西?\n我們來戰鬥吧!", }, "victory": { - 1: "Outstanding! I'm tough as an iceberg, but you smashed me through and through!" + 1: "傑出!我像冰山一樣堅硬,但你徹底擊潰了我!", }, "defeat": { - 1: "Tussle with me and this is what happens!" + 1: "和我幹的結果就是這樣!", } }, "kabu": { "encounter": { - 1: `Every Trainer and Pokémon trains hard in pursuit of victory. - $But that means your opponent is also working hard to win. - $In the end, the match is decided by which side is able to unleash their true potential.`, + 1: "每個訓練師和寶可夢都在努力追求勝利。$但這意味著你的對手也在努力贏得勝利。$最終,比賽是由哪一方\n能夠發揮出他們真正的潛力來決定的。", }, "victory": { - 1: "I'm glad I could battle you today!" + 1: "我很高興今天能和你戰鬥!", }, "defeat": { - 1: "That's a great way for me to feel my own growth!" + 1: "這是我感覺自己的成長的好方式!", } }, "bea": { "encounter": { - 1: `Do you have an unshakable spirit that won't be moved, no matter how you are attacked? - $I think I'll just test that out, shall I?`, + 1: "你有沒有一種不可動搖的精神,\n受到什麼攻擊都安如磐石? $就讓我來試試吧?", }, "victory": { - 1: "I felt the fighting spirit of your Pokémon as you led them in battle." + 1: "我感受到了你的寶可夢\n在戰鬥中被你指揮時的戰鬥之魂。", }, "defeat": { - 1: "That was the best sort of match anyone could ever hope for." + 1: "每個人都希望能有一場這樣的好比賽。", } }, "opal": { "encounter": { - 1: "Let me have a look at how you and your partner Pokémon behave!" + 1: "讓我看看你和你的寶可夢的表現如何!", }, "victory": { - 1: "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon." + 1: "你不夠粉嫩呀,\n但你是一個優秀的訓練師,$還擁有著優秀的寶可夢。", }, "defeat": { - 1: "Too bad for you, I guess." + 1: "對你來說太慘了,我覺得。", } }, "bede": { "encounter": { - 1: "I suppose I should prove beyond doubt just how pathetic you are and how strong I am." + 1: "就讓我來證明你有多可憐,我有多強大。", }, "victory": { - 1: "I see… Well, that's fine. I wasn't really trying all that hard anyway." + 1: "我懂了……好吧。其實我還沒拿出全力呢。", }, "defeat": { - 1: "Not a bad job, I suppose." + 1: "我覺得我打得不錯。", } }, "gordie": { "encounter": { - 1: "So, let's get this over with." + 1: "好了,我們來做個了結吧!", }, "victory": { - 1: "I just want to climb into a hole… Well, I guess it'd be more like falling from here." + 1: "我只想要挖一個洞爬進去……$好吧,現在更像是掉了進去。", }, "defeat": { - 1: "Battle like you always do, victory will follow!" + 1: "像往常一樣戰鬥,勝利就會隨之而來!", } }, "marnie": { "encounter": { - 1: `The truth is, when all's said and done… I really just wanna become Champion for myself! - $So don't take it personal when I kick your butt!`, + 1: "事實上,言而總之… \n人家自己也想當冠軍呀! $所以別認為我在針對你!", }, "victory": { - 1: "OK, so I lost… But I got to see a lot of the good points of you and your Pokémon!" + 1: "好吧,我還是輸了……\n但是我看到了很多你和你寶可夢的優點哦", }, "defeat": { - 1: "Hope you enjoyed our battle tactics." + 1: "希望你喜歡我們的戰鬥策略。", } }, "raihan": { "encounter": { - 1: "I'm going to defeat the Champion, win the whole tournament, and prove to the world just how strong the great Raihan really is!" + 1: "我打算擊敗冠軍,贏得錦標賽,\n並向世界證明奇巴納大人有多強!", }, "victory": { - 1: `I look this good even when I lose. - $It's a real curse. - $Guess it's time for another selfie!`, + 1: "就算輸了我也好帥。$真是罪孽深重啊。$看來得再來張自拍了!", }, "defeat": { - 1: "Let's take a selfie to remember this." + 1: "為了紀念此刻,來張自拍吧!", } }, "brassius": { "encounter": { - 1: "I assume you are ready? Let our collaborative work of art begin!" + 1: "你應該準備好了吧,\一起完成這美麗的藝術作品吧!", }, "victory": { - 1: "Ahhh…vant-garde!" + 1: "啊……前衛!", }, "defeat": { - 1: "I will begin on a new piece at once!" + 1: "我將立即開始新的創作!", } }, "iono": { "encounter": { - 1: `How're ya feelin' about this battle? - $... - $Let's get this show on the road! How strong is our challenger? - $I 'unno! Let's find out together!`, + 1: "誰在奇述!是我奇樹!\n做好準備了嗎!$...$直播開始!\n今天的小挑戰者有多強?$奇樹不知道哦~\n讓我們一起來看看吧!", }, "victory": { - 1: "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!" + 1: "你的閃耀如1000萬伏特!朋友!", }, "defeat": { - 1: "Your eyeballs are MINE!" + 1: "奇樹奇樹捕獲你的眼球!", } }, "larry": { "encounter": { - 1: "When all's said and done, simplicity is strongest." + 1: "歸根結底,普普通通就是最強。", }, "victory": { - 1: "A serving of defeat, huh?" + 1: "哼,給我上了一道“戰敗”。", }, "defeat": { - 1: "I'll call it a day." + 1: "下班打卡,走了", } }, "ryme": { "encounter": { - 1: "Come on, baby! Rattle me down to the bone!" + 1: "寶貝, 一起! \n搖滾搖到骨子裡!", }, "victory": { - 1: "You're cool, my friend—you move my SOUL!" + 1: "你好酷!我佩服!\n我的靈魂為你哭!", }, "defeat": { - 1: "Later, baby!" + 1: "再會, 寶貝!", } }, "grusha": { "encounter": { - 1: "All I need to do is make sure the power of my Pokémon chills you to the bone!" + 1: "我保證我寶可夢的力量\n會讓你感到寒冷徹骨!", }, "victory": { - 1: "Your burning passion… I kinda like it, to be honest." + 1: "你燃燒的熱情……老實說,我有點喜歡。", }, "defeat": { - 1: "Things didn't heat up for you." + 1: "你沒有升溫。", } }, "marnie_elite": { "encounter": { - 1: "You've made it this far, huh? Let's see if you can handle my Pokémon!", - 2: "I'll give it my best shot, but don't think I'll go easy on you!" + 1: "你已經走到這一步了?$哼~ 看看你能不能對付我的寶可夢!", + 2: "我將全力以赴, 別覺得我會手下留情哦~", }, "victory": { - 1: "I can't believe I lost... But you deserved that win. Well done!", - 2: "Looks like I've still got a lot to learn. Great battle, though!" + 1: "不敢相信…我輸掉了… $但是你確實贏得好,幹得漂亮捏~", + 2: "看來我還要多多學習呀,\n不過你打得很不錯哦~", }, "defeat": { - 1: "You put up a good fight, but I've got the edge! Better luck next time!", - 2: "Seems like my training's paid off. Thanks for the battle!" + 1: "你打得不錯,但是我更勝一籌!$祝你下次好運啦~", + 2: "看來我的練習有所回報了。\n感謝一戰!", } }, "nessa_elite": { "encounter": { - 1: "The tides are turning in my favor. Ready to get swept away?", - 2: "Let's make some waves with this battle! I hope you're prepared!" + 1: "海流正在朝著對我有利的方向轉變。$準備好被捲走了嗎?", + 2: "讓我們在這場戰鬥中掀起波瀾!$我希望你做好準備!", }, "victory": { - 1: "You navigated those waters perfectly... Well done!", - 2: "Looks like my currents were no match for you. Great job!" + 1: "你完美地渡過了這片水域......幹得好!", + 2: "看來我現在無法與你匹敵。幹得好!", }, "defeat": { - 1: "Water always finds a way. That was a refreshing battle!", - 2: "You fought well, but the ocean's power is unstoppable!" + 1: "水總能找到出路。\n真是爽快的一戰!", + 2: "你打得很好,\n但海洋的力量是不可阻擋的!", } }, "bea_elite": { "encounter": { - 1: "Prepare yourself! My fighting spirit burns bright!", - 2: "Let's see if you can keep up with my relentless pace!" + 1: "做好準備!我的鬥志熊熊燃燒!", + 2: "讓我們看看你是否能跟上我永不停歇的節奏!", }, "victory": { - 1: "Your strength... It's impressive. You truly deserve this win.", - 2: "I've never felt this intensity before. Amazing job!" + 1: "你的實力......令人印象深刻。\n你真的值得這場勝利。", + 2: "我以前從未感受過這種強度。\n太棒了!", }, "defeat": { - 1: "Another victory for my intense training regimen! Well done!", - 2: "You've got strength, but I trained harder. Great battle!" + 1: "我的高強度訓練又帶來勝利了!\n幹得好!", + 2: "你有實力,但我的訓練更努力。\n精彩的戰鬥!", } }, "allister_elite": { "encounter": { - 1: "Shadows fall... Are you ready to face your fears?", - 2: "Let's see if you can handle the darkness that I command." + 1: "黑暗降臨...你準備好面對你的恐懼了嗎?", + 2: "讓我們看看你能否應對我所操控的黑暗。", }, "victory": { - 1: "You've dispelled the shadows... For now. Well done.", - 2: "Your light pierced through my darkness. Great job." + 1: "你已經驅散了陰影......\n暫時。幹得很好。", + 2: "你的光芒刺穿了我的黑暗。幹得好。", }, "defeat": { - 1: "The shadows have spoken... Your strength isn't enough.", - 2: "Darkness triumphs... Maybe next time you'll see the light." + 1: "黑影在輕語...\n你的力量還不夠。", + 2: "黑暗獲勝了......\n也許下次你會看到光明。", } }, "raihan_elite": { "encounter": { - 1: "Storm's brewing! Let's see if you can weather this fight!", - 2: "Get ready to face the eye of the storm!" + 1: "風暴來臨!你能挺過這場戰鬥嗎!", + 2: "準備好面對風暴之眼!", }, "victory": { - 1: "You've bested the storm... Incredible job!", - 2: "You rode the winds perfectly... Great battle!" + 1: "你戰勝了風暴...難以置信!", + 2: "你完美地駕馭了風……打得好!", }, "defeat": { - 1: "Another storm weathered, another victory claimed! Well fought!", - 2: "You got caught in my storm! Better luck next time!" + 1: "又一場風暴襲來,又一場勝利!打得好!", + 2: "你被我的風暴捲入了!祝你下次好運!", } }, "rival": { "encounter": { - 1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye… - $@c{smile_eclosed}So you're really pursuing your dream after all?\n I almost can't believe it. - $@c{serious_smile_fists}Since we're here, how about a battle?\nAfter all, I want to make sure you're ready. - $@c{serious_mopen_fists}Don't hold back, I want you to give me everything you've got!` + 1: "@c{smile}嘿,我在找你呢!我知道你急著上路,\n但至少說個再見吧…$@c{smile_eclosed}所以你終於要開始追逐夢想了?\n我幾乎不敢相信。$@c{serious_smile_fists}來都來了,來一場對戰怎麼樣?\n畢竟,我想看看你是不是準備周全了。$@c{serious_mopen_fists}不要手下留情,我想讓你全力以赴!", }, "victory": { - 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? - $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. - $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there!` + 1: "@c{shock}哇…你徹底擊敗了我。\n你是真初學者嗎?$@c{smile}也許是靠點運氣,但是…\n誰知道,你可能真的能一路走下去。$順便說一下,博士讓我給你這些東西。它們看起來可牛了。$@c{serious_smile_fists}祝你好运!", }, }, "rival_female": { "encounter": { - 1: `@c{smile_wave}There you are! I've been looking everywhere for you!\n@c{angry_mopen}Did you forget to say goodbye to your best friend? - $@c{smile_ehalf}You're going after your dream, huh?\nThat day is really today isn't it… - $@c{smile}Anyway, I'll forgive you for forgetting me, but on one condition. @c{smile_wave_wink}You have to battle me! - $@c{angry_mopen}Give it your all! Wouldn't want your adventure to be over before it started, right?` + 1: "@c{smile_wave}你在這兒啊!我到處找你呢!$@c{angry_mopen}你忘了和你最好的朋友說再見了嗎?$@c{smile_ehalf}你要去追逐夢想了,對吧?\n從今天開始,是不是…$@c{smile}不管怎樣,忘了我的事就原諒你吧,\n但有個條件。@c{smile_wave_wink}你必須和我對戰!$@c{angry_mopen}全力以赴!\n你也不想讓你的冒險在開始之前就結束了,對吧?", }, "victory": { - 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? - $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. - $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you!` + 1: "@c{shock}你剛開始就已經這麼強了?!@d{96}$@c{angry}你是不是開了?$@c{smile_wave_wink}只是開個玩笑啦!@d{64} @c{smile_eclosed}我輸地心服口服了…\n我感覺你出去挺有天賦的。$@c{smile}順便說一下,博士想讓我給你一些東西。\n希望它們能幫上忙!$@c{smile_wave}像往常一樣盡力而為!\n我相信你!", }, }, "rival_2": { "encounter": { - 1: `@c{smile}Hey, you're here too?\n@c{smile_eclosed}Still a perfect record, huh…? - $@c{serious_mopen_fists}I know it kind of looks like I followed you here, but that's mostly not true. - $@c{serious_smile_fists}Honestly though, I've been itching for a rematch since you beat me back at home. - $I've been doing a lot of my own training so I'll definitely put up a fight this time. - $@c{serious_mopen_fists}Don't hold back, just like before!\nLet's go!` + 1: "@c{smile}嘿,你也在這裡嗎?$@c{smile_eclosed}一路過關斬將,是吧?$@c{serious_mopen_fists}我知道看起來好像我尾隨著你來到這裡,\n怎麼可能啦。$@c{serious_smile_fists}說真的,自從你在老家打敗我後,\n我就一直很渴望再比一場。$我自己也進行了很多訓練,\n所以這次我肯定會好好打一場。$@c{serious_mopen_fists}不要手下留情,就像以前一樣!$讓我們開始吧!", }, "victory": { - 1: `@c{neutral_eclosed}Oh. I guess I was overconfident. - $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n - $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n - $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care!` + 1: "@c{neutral_eclosed}哦。我過於自信了。$@c{smile}不過沒關係。我猜到可能會這樣。$@c{serious_mopen_fists}這只意味著我下次需要更努力!$$@c{smile}呃,不是特意幫你,我正好有多餘的這個,\n我覺得你可能想要。$$@c{serious_smile_fists}不過這次之後別指望再有了!$我不能一直給我的對手優勢。$@c{smile}反正,保重!", }, }, "rival_2_female": { "encounter": { - 1: `@c{smile_wave}Oh, fancy meeting you here. Looks like you're still undefeated. @c{angry_mopen}Huh… Not bad! - $@c{angry_mopen}I know what you're thinking, and no, I wasn't creeping on you. @c{smile_eclosed}I just happened to be in the area. - $@c{smile_ehalf}I'm happy for you but I just want to let you know that it's OK to lose sometimes. - $@c{smile}We learn from our mistakes, often more than we would if we kept succeeding. - $@c{angry_mopen}In any case, I've been training hard for our rematch, so you'd better give it your all!` + 1: "@c{smile_wave}哦,真巧,在這裡遇見你。\n看來你還沒輸過嘛。@c{angry_mopen}哈……好傢伙!$@c{angry_mopen}我知道你在想什麼,\n不,我才不會跟蹤你什麼呢。 @c{smile_eclosed}我只是碰巧在附近。$@c{smile_ehalf}我為你感到高興,但我只想讓你知道\n有時輸了是可以接受的。$@c{smile}我們從錯誤中學到的東西\n往往比我們一直成功時學到的還要多。$@c{angry_mopen}無論如何,我為了我們的複賽已經努力訓練了\n所以你最好全力以赴!", }, "victory": { - 1: `@c{neutral}I… wasn't supposed to lose that time… - $@c{smile}Aw well. That just means I'll have to train even harder for next time! - $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. - $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it!` + 1: "@c{neutral}我……沒打算會輸來著……$@c{smile}嗷……好吧。看來我要再更加努力訓練了!$@c{smile_wave}我還給你帶了個這個$@c{smile_wave_wink}不用謝我哦~.$@c{angry_mopen}不過,這是最後一個啦!\n 你可別想再從我這賺小便宜了~$@c{smile_wave}要保重哦!", }, "defeat": { - 1: "It's OK to lose sometimes…" + 1: "輸了有時候也不要緊的…", } }, "rival_3": { "encounter": { - 1: `@c{smile}Hey, look who it is! It's been a while.\n@c{neutral}You're… still undefeated? Huh. - $@c{neutral_eclosed}Things have been kind of… strange.\nIt's not the same back home without you. - $@c{serious}I know it's selfish, but I need to get this off my chest.\n@c{neutral_eclosed}I think you're in over your head here. - $@c{serious}Never losing once is just unrealistic.\nWe need to lose sometimes in order to grow. - $@c{neutral_eclosed}You've had a great run but there's still so much ahead, and it only gets harder. @c{neutral}Are you prepared for that? - $@c{serious_mopen_fists}If so, prove it to me.` + 1: "@c{smile}嘿,看看這是誰!好久不見啊。$@c{neutral}你……還是沒輸過?哈…$@c{neutral_eclosed}這有點……不太對勁。$沒有你一起,回家的感覺有很不一樣。$@c{serious}雖然我知道這挺別扭的,但我就直說了。$@c{neutral_eclosed}我覺得你有點兒難以理解。$@c{serious}沒有人能夠戰無不勝。$失敗乃成功之母。$@c{neutral_eclosed}你已經贏得了夠好的成績,\n但前面道阻且長,只會愈發艱難。 @c{neutral}你做好準備了沒?$@c{serious_mopen_fists}如果做好了,證明給我看吧。", }, "victory": { - 1: "@c{angry_mhalf}This is ridiculous… I've hardly stopped training…\nHow are we still so far apart?" + 1: "@c{angry_mhalf}這太離譜了……我幾乎從沒停下訓練……$我們之間的差距怎麼還是這麼大?", }, }, "rival_3_female": { "encounter": { - 1: `@c{smile_wave}Long time no see! Still haven't lost, huh.\n@c{angry}You're starting to get on my nerves. @c{smile_wave_wink}Just kidding! - $@c{smile_ehalf}But really, don't you miss home by now? Or… me?\nI… I mean, we've really missed you. - $@c{smile_eclosed}I support you in your dream and everything, but the reality is you're going to lose sooner or later. - $@c{smile}And when you do, I'll be there for you like always.\n@c{angry_mopen}Now, let me show you how strong I've become!` + 1: "@c{smile_wave}好久不見!還沒輸過,對吧。$@c{angry}我覺得你點煩了。@c{smile_wave_wink}開玩笑啦!$@c{smile_ehalf}但說真的,你現在不想家嗎?\n 不想…我嗎?$我……我的意思是,我們真的很想你。$@c{smile_eclosed}我支持你的一切,包括你的夢想。\n但現實就是你早晚會經歷失敗。$@c{smile}當你失敗的時候,我想像往常一樣陪在你身邊。$@c{angry_mopen}現在,給你看看我變得多強了吧!", }, "victory": { - 1: "@c{shock}After all that… it wasn't enough…?\nYou'll never come back at this rate…" - + 1: "@c{shock}都這樣了……還是不夠嗎?$這樣下去,你就永遠不會回來了……", }, "defeat": { - 1: "You gave it your best, now let's go home." + 1: "你盡力了,現在讓我們回家吧。", } }, "rival_4": { "encounter": { - 1: `@c{neutral}Hey. - $I won't mince words or pleasantries with you.\n@c{neutral_eclosed}I'm here to win, plain and simple. - $@c{serious_mhalf_fists}I've learned to maximize my potential by putting all my time into training. - $@c{smile}You get a lot of extra time when you cut out the unnecessary sleep and social interaction. - $@c{serious_mopen_fists}None of that matters anymore, not until I win. - $@c{neutral_eclosed}I've even reached the point where I don't lose anymore.\n@c{smile_eclosed}I suppose your philosophy wasn't so wrong after all. - $@c{angry_mhalf}Losing is for the weak, and I'm not weak anymore. - $@c{serious_mopen_fists}Prepare yourself.` + 1: "@c{neutral}嘿。$我不會對你說什麼拐彎抹角的客套話。$@c{neutral_eclosed}我來,就是為了贏,簡單明了。$@c{serious_mhalf_fists}我將所有時間都投入到訓練中,\n掌握了如何發揮我的潛力。$@c{smile}當你削減掉不必要的睡眠和社交後,\n你會得到很多額外的時間。$@c{serious_mopen_fists}但在我獲勝之前,這些都不重要了。$@c{neutral_eclosed}我甚至已經到達了戰無不敗的境地。$@c{smile_eclosed}我覺得你的思路倒是也沒毛病。$@c{angry_mhalf}失敗是屬於弱者的,\n我已經不再軟弱了。$@c{serious_mopen_fists}準備好吧。", }, "victory": { - 1: "@c{neutral}What…@d{64} What are you?" + 1: "@c{neutral}你…@d{64} 你是人嗎?", }, }, "rival_4_female": { "encounter": { - 1: `@c{neutral}It's me! You didn't forget about me again… did you? - $@c{smile}You should be proud of how far you made it. Congrats!\nBut it looks like it's the end of your journey. - $@c{smile_eclosed}You've awoken something in me I never knew was there.\nIt seems like all I do now is train. - $@c{smile_ehalf}I hardly even eat or sleep now, I just train my Pokémon all day, getting stronger every time. - $@c{neutral}In fact, I… hardly recognize myself. - $And now, I've finally reached peak performance.\nI don't think anyone could beat me now. - $And you know what? It's all because of you.\n@c{smile_ehalf}I don't know whether to thank you or hate you. - $@c{angry_mopen}Prepare yourself.` + 1: "@c{neutral}是我哦!沒又把我忘了吧……是嗎?$@c{smile}你應該為自己走了這麼遠感到驕傲。恭喜你!$但看來你的旅程到此為止了。$@c{smile_eclosed}你喚醒了我體內一些我從未有過的東西。\n就像我現在滿腦子除了訓練還是訓練。$@c{smile_ehalf}我幾乎已經沒空吃飯睡覺了,\n我沒日沒夜訓練我的寶可夢,每次都能變得更強。$@c{neutral}事實上,我……幾乎不認識自己了。$現在,我終於達到了巔峰。\n我感覺我已經戰無不勝了。$而且你知道嗎?這一切都是因為你。$@c{smile_ehalf}我不知道到底是該感謝你還是恨你。$@c{angry_mopen}做好準備…", }, "victory": { - 1: "@c{neutral}What…@d{64} What are you?" - + 1: "@c{neutral}你…@d{64} 你是人嗎?", }, "defeat": { - 1: "$@c{smile}You should be proud of how far you made it." + 1: "@c{smile}你應該為自己走了這麼遠感到驕傲。", } }, "rival_5": { @@ -2254,47 +2102,18 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rival_6": { "encounter": { - 1: `@c{smile_eclosed}We meet again. - $@c{neutral}I've had some time to reflect on all this.\nThere's a reason this all seems so strange. - $@c{neutral_eclosed}Your dream, my drive to beat you…\nIt's all a part of something greater. - $@c{serious}This isn't about me, or about you… This is about the world, @c{serious_mhalf_fists}and it's my purpose to push you to your limits. - $@c{neutral_eclosed}Whether I've fulfilled that purpose I can't say, but I've done everything in my power. - $@c{neutral}This place we ended up in is terrifying… Yet somehow I feel unphased, like I've been here before. - $@c{serious_mhalf_fists}You feel the same, don't you? - $@c{serious}…and it's like something here is speaking to me.\nThis is all the world's known for a long time now. - $Those times we cherished together that seem so recent are nothing but a distant memory. - $@c{neutral_eclosed}Who can say whether they were ever even real in the first place. - $@c{serious_mopen_fists}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. - $@c{serious_smile_fists}I hardly know what any of this means, I just know that it's true. - $@c{serious_mopen_fists}If you can't defeat me here and now, you won't stand a chance.` + 1: "@c{smile_eclosed}又見面了。$@c{neutral}我花了點時間思考反思\n有理由說明為什麼這一切都顯得如此奇妙。$@c{neutral_eclosed}你所追逐的夢想,我想擊敗你的決心…$這都是某種龐大使命的一部分。$@c{serious}這不僅僅是關於我和你… 而是關於這個世界, @c{serious_mhalf_fists}我的使命就是將你推向極限。$@c{neutral_eclosed}我是否達成了那個使命,我說不上來,但我已盡我所能。$@c{neutral}我們最終到達的這個地方看起來很可怕\n 然而不知何故,我心中毫無畏懼,好像我早就來過這裡。$@c{serious_mhalf_fists}你也有同樣的感覺,對吧?$@c{serious}……這裡好像有什麼東西在呼喚我。\n這是世界早已記錄的一切。$那些我們經歷過的時光,那些記憶猶新的過去,\n其實只是遙遠的回憶。$@c{neutral_eclosed}誰能保證它們是否真的發生過。$@c{serious_mopen_fists}你必須繼續前進,不然的話,這一切將永無止境。\n這件事而只有你能辦成。$@c{serious_smile_fists}我不清楚這一切意味著什麼,但我知道……$@c{serious_mopen_fists}如果現在你不能就此擊敗我,\n你將毫無機會可言。", }, "victory": { - 1: `@c{smile_eclosed}It looks like my work is done here. - $I want you to promise me one thing.\n@c{smile}After you heal the world, please come home.` + 1: "@c{smile_eclosed}看來我的使命在這裡已經完成了。\n我想讓你答應我一件事。$@c{smile}在你拯救世界之後,要回家。", }, }, "rival_6_female": { "encounter": { - 1: `@c{smile_ehalf}So it's just us again. - $@c{smile_eclosed}You know, I keep going around and around in my head… - $@c{smile_ehalf}There's something to all this, why everything seems so strange now… - $@c{smile}You have your dream, and I have this ambition in me… - $I just can't help but feel there's a greater purpose to all this, to what we're doing, you and I. - $@c{smile_eclosed}I think I'm supposed to push you… to your limits. - $@c{smile_ehalf}I'm not sure if I've been doing a good job at that, but I've tried my best up to now. - $It's something about this strange and dreadful place… Everything seems so clear… - $This… is all the world's known for a long time now. - $@c{smile_eclosed}It's like I can barely remember the memories we cherished together. - $@c{smile_ehalf}Were they even real? They seem so far away now… - $@c{angry_mopen}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. - $@c{smile_ehalf}I… don't know what all this means… but I feel it's true. - $@c{neutral}If you can't defeat me here and now, you won't stand a chance.` + 1: "@c{smile_ehalf}又只有我們兩個人了。$@c{smile_eclosed}你知道嗎,我在心裡想啊想,\n想了好久……$@c{smile_ehalf}這一切背後是有什麼原因嗎,\n為什麼一切現在看起來都這麼奇怪……$@c{smile}你有你的夢想,而我內心有這個抱負……$我不禁感覺這一切背後有一個更龐大的力量,$掌控者我們所做的一切,你和我之間。$@c{smile_eclosed}}我想我注定要推動你……到你的極限。$@c{smile_ehalf}我不清楚我是否一直做得很好,\n但到現在為止,我已經盡力了。$這個奇怪而可怕的地方……\n一切看起來都那麼清晰……$這是世界早已記錄的一切。$@c{smile_eclosed}我好像記不清我們一起度過的日子了。$@c{smile_ehalf}那些回憶到底是真的嗎?\n怎麼感覺這麼久遠……$@c{angry_mopen}你得繼續前進,不然的話,這一切將永無止境。\n你是唯一能做到這件事的。$@c{smile_ehalf}}我……不知道這一切意味著什麼……\n但我明白$@c{neutral}如果你現在不能就此擊敗我,\n你將毫無機會可言。", }, "victory": { - 1: `@c{smile_ehalf}I… I think I fulfilled my purpose… - $@c{smile_eclosed}Promise me… After you heal the world… Please… come home safe. - $@c{smile_ehalf}…Thank you.` - + 1: "@c{smile_ehalf}我……\n我想我完成了我的使命……$@c{smile_eclosed}答應我……在你拯救世界之後\n……要……平安到家。$@c{smile_ehalf}……謝謝你。", }, }, }; @@ -2305,17 +2124,17 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; // Dialogue of the endboss of the game when the player character is male (Or unset) export const PGMbattleSpecDialogue: SimpleTranslationEntries = { - "encounter": `It appears the time has finally come once again.\nYou know why you have come here, do you not? - $You were drawn here, because you have been here before.\nCountless times. - $Though, perhaps it can be counted.\nTo be precise, this is in fact your 5,643,853rd cycle. - $Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain. - $Until now you have yet to succeed, but I sense a different presence in you this time.\n - $You are the only one here, though it is as if there is… another. - $Will you finally prove a formidable challenge to me?\nThe challenge I have longed for for millennia? - $We begin.`, - "firstStageWin": `I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back. - $Do not disappoint me.`, - "secondStageWin": "…Magnificent." + "encounter": `看來終於又到了那個時候。\n你知道自己為何會來到這裡,不是嗎? + $你被吸引到這裡,因為你以前就來過這裡。\n無數次。 + $儘管,或許可以數一數。\n準確地說,這實際上是你的第5,643,853次循環。 + $每一次循環,你的思想都會恢復到之前的狀態。\n即便如此,不知何故,你之前自我的殘留仍然存在。 + $直到現在,你仍未成功,但我感覺這次你身上有一種異樣的氣息。 + $你是這裡唯一的人,儘管感覺上還有……另一個人。 + $你最終會成為對我來的一個硬茬嗎?\n我渴望了數千年的挑戰? + $我們,開始。`, + "firstStageWin": `我明白了。我所感覺到的氣息確實是真實的。\n看來我不再需要保留實力了。 + $別讓我失望。`, + "secondStageWin": "…漂亮。" }; // Dialogue of the endboss of the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMbattleSpecDialogue. @@ -2324,21 +2143,21 @@ export const PGFbattleSpecDialogue: SimpleTranslationEntries = PGMbattleSpecDial // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is male export const PGMmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. - $@c{smile}It's over.@d{64} You ended the loop. - $@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once. - $@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it? - $@c{serious_smile_fists}Your legend will always live on in our hearts. - $@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home. - $@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.`, + `@c{smile}哦?你贏了?@d{96} @c{smile_eclosed}我應該早猜到了\n你回來了。 + $@c{smile}結束了。@d{64} 你終結了這個循環。 + $@c{serious_smile_fists}你也完成了自己的夢想,不是嗎?\n你甚至一次都沒失敗。 + $@c{neutral}我是唯一能夠記得你所作所為的人@d{96}\n我覺得這應該也還行吧? + $@c{serious_smile_fists}你的傳奇將永遠留存於我們心中。 + $@c{smile_eclosed}不管了,我真是受夠這個地方了,你也一樣嗎?我們回家吧。 + $@c{serious_smile_fists}可能等我們回家以後,再打一場?\n要是你想的話`, "ending_female": - `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. - $@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop. - $@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once. - $I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget! - $@c{smile_wave_wink}Just kidding!@d{64} @c{smile}I'd never forget.@d{32}\nYour legend will live on in our hearts. - $@c{smile_wave}Anyway,@d{64} it's getting late…@d{96} I think?\nIt's hard to tell in this place. - $Let's go home. @c{smile_wave_wink}Maybe tomorrow, we can have another battle, for old time's sake?`, + `@c{shock}你回來了?@d{32} 也就是說…@d{96} 你贏了呀!?\n@c{smile_ehalf}我應該早料到了。 + $@c{smile_eclosed}當然…我一直有這種感覺\n@c{smile}一切都結束了,對麼? 你打破了循環。 + $@c{smile_ehalf}你也完成了自己的夢想,不是嗎?\n你甚至一次都沒失敗。 + $我是唯一能夠記得你所作所為的人\n@c{angry_mopen}我會努力不忘掉哒! + $@c{smile_wave_wink}開玩笑啦,@d{64} @c{smile}我才不會忘呢。@d{32}\n你的傳奇將永遠留存於我們心中。 + $@c{smile_wave}不管了,@d{64} 時候不早了@d{96} ,應該吧?\n在這地方還真搞不清楚。 + $一起回家吧。 @c{smile_wave_wink}可能明天,我們再來打一場,為了重溫回憶嘛~`, }; // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMmiscDialogue. export const PGFmiscDialogue: SimpleTranslationEntries = PGMmiscDialogue; @@ -2348,113 +2167,82 @@ export const PGFmiscDialogue: SimpleTranslationEntries = PGMmiscDialogue; export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { "blue_red_double": { "encounter": { - 1: `Blue: Hey Red, let's show them what we're made of! - $Red: ... - $Blue: This is Pallet Town Power!`, + 1: "青綠:嘿,赤紅,\n讓這傢伙看看我們是什麼來頭!$赤紅:...$青綠: 見識下真新鎮的實力!", }, "victory": { - 1: `Blue: That was a great battle! - $Red: ...`, + 1: "青綠:打得真不錯$赤紅: ...", }, }, "red_blue_double": { "encounter": { - 1: `Red: ...! - $Blue: He never talks much. - $Blue: But dont let that fool you! He is a champ after all!`, + 1: "赤紅: ...!$青綠:他人狠話不多。$青綠: 他人狠話不多。$青綠: 但別被他耍了,\n畢竟他可是個冠軍!", }, "victory": { - 1: `Red: ...! - $Blue: Next time we will beat you!`, + 1: "赤紅: ...!$青綠: 下次我們一定會贏你!", }, }, "tate_liza_double": { "encounter": { - 1: `Tate: Are you suprised? - $Liza: We are two gym leaders at once! - $Tate: We are twins! - $Liza: We dont need to talk to understand each other! - $Tate: Twice the power... - $Liza: Can you handle it?`, + 1: "小楓:嘿嘿嘿……你驚訝嗎?$小南:這裡有兩個道館館主?$小楓: 我們是雙胞胎!$小南:我們無需交談,因為……我們可以通曉彼此的想法$小楓: 我們的組合……$小南: 你能打敗嗎?", }, "victory": { - 1: `Tate: What? Our combination was perfect! - $Liza: Looks like we need to train more...`, + 1: "小楓:什麼?我們的組合……$小南:被瓦解了!", }, }, "liza_tate_double": { "encounter": { - 1: `Liza: Hihihi... Are you suprised? - $Tate: Yes, we are really two gym leaders at once! - $Liza: This is my twin brother Tate! - $Tate: And this is my twin sister Liza! - $Liza: Don't you think we are a perfect combination?` + 1: "小南:呵呵呵……你驚訝吧?$小楓:這裡有兩個道館館主?$小南:我們可以通曉……$小楓:彼此的想法……$小南:全在我們腦中!$小楓:我們的組合……$小南:你能打敗嗎?", }, "victory": { - 1: `Liza: Are we... - $Tate: ...not as strong as we thought?`, + 1: "小楓:你和你的寶可夢……$小南:簡直像親兄弟姐妹!", }, }, "wallace_steven_double": { "encounter": { - 1: `Steven: Wallace, let's show them the power of the champions! - $Wallace: We will show you the power of Hoenn! - $Steven: Let's go!`, + 1: "大吾:米可利, 展現冠軍的實力吧!$米可利:我們將展示豐緣的實力!$米可利:我們將展示豐緣的實力!$大吾:要上了!", }, "victory": { - 1: `Steven: That was a great battle! - $Wallace: We will win next time!`, + 1: "大吾:打得真不錯!$米可利:我們下次會贏的!", }, }, "steven_wallace_double": { "encounter": { - 1: `Steven: Do you have any rare pokémon? - $Wallace: Steven... We are here for a battle, not to show off our pokémon. - $Steven: Oh... I see... Let's go then!`, + 1: "大吾:你有什麼稀有的寶可夢嗎?$米可利:大吾……我們是來對戰的,\n不是來炫耀寶可夢的。$大吾:哦……知道了… 那麼要上了!", }, "victory": { - 1: `Steven: Now that we are done with the battle, let's show off our pokémon! - $Wallace: Steven...`, + 1: "大吾:戰鬥結束了,\n來看看我的稀有寶可夢!$米可利:大吾……", }, }, "alder_iris_double": { "encounter": { - 1: `Alder: We are the strongest trainers in Unova! - $Iris: Fights against strong trainers are the best!`, + 1: "阿戴克:我們倆是合眾最強的訓練家!$艾莉絲:與最強來一場最激烈的戰鬥吧!", }, "victory": { - 1: `Alder: Wow! You are super strong! - $Iris: We will win next time!`, + 1: "阿戴克:哇哦!你真是超級厲害!$艾莉絲:我們下次會贏的啦!", }, }, "iris_alder_double": { "encounter": { - 1: `Iris: Welcome Challenger! I am THE Unova Champion! - $Alder: Iris, aren't you a bit too excited?`, + 1: "艾莉絲:歡迎!挑戰者,\n合眾地區最強的冠軍大駕光臨!$阿戴克:艾莉絲,你是不是有點太興奮了…", }, "victory": { - 1: `Iris: A loss like this is not easy to take... - $Alder: But we will only get stronger with every loss!`, + 1: "艾莉絲:這樣的失敗可不好受啊…$阿戴克:但是只有失敗才能讓我們變強!", }, }, "piers_marnie_double": { "encounter": { - 1: `Marnie: Brother, let's show them the power of Spikemuth! - $Piers: We bring darkness!`, + 1: "瑪俐:哥哥,給他們展現尖釘鎮的實力!$聶梓:我們帶來黑暗!", }, "victory": { - 1: `Marnie: You brought light to our darkness! - $Piers: Its too bright...`, + 1: "瑪俐:你的強光亮瞎我們的黑暗了啦……$聶梓:實在太亮了…", }, }, "marnie_piers_double": { "encounter": { - 1: `Piers: Ready for a concert? - $Marnie: Brother... They are here to fight, not to sing...`, + 1: "聶梓: 台下準備好了嗎!$瑪俐: 哥哥,我們是來對戰的,\n不是來唱歌的……", }, "victory": { - 1: `Piers: Now that was a great concert! - $Marnie: Brother...`, + 1: "聶梓:這首歌獻給大家!$瑪俐:哥哥……", }, }, }; diff --git a/src/locales/zh_TW/game-mode.ts b/src/locales/zh_TW/game-mode.ts new file mode 100644 index 00000000000..be342b4c390 --- /dev/null +++ b/src/locales/zh_TW/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classic", + "endless": "Endless", + "endlessSpliced": "Endless (Spliced)", + "dailyRun": "Daily Run", + "unknown": "Unknown", + "challenge": "Challenge", +} as const; diff --git a/src/locales/zh_TW/menu.ts b/src/locales/zh_TW/menu.ts index 680db51e8ac..d16052f2ac7 100644 --- a/src/locales/zh_TW/menu.ts +++ b/src/locales/zh_TW/menu.ts @@ -45,8 +45,8 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "每週排名", "noRankings": "無排名", "loading": "加載中…", + "loadingAsset": "Loading asset: {{assetName}}", "playersOnline": "在線玩家", - "empty":"空", "yes":"是", "no":"否", "disclaimer": "DISCLAIMER", diff --git a/src/locales/zh_TW/modifier-type.ts b/src/locales/zh_TW/modifier-type.ts index 730f269bb21..2577db69d65 100644 --- a/src/locales/zh_TW/modifier-type.ts +++ b/src/locales/zh_TW/modifier-type.ts @@ -5,11 +5,11 @@ export const modifierType: ModifierTypeTranslationEntries = { AddPokeballModifierType: { name: "{{modifierCount}}x {{pokeballName}}", description: - "獲得 {{pokeballName}} x{{modifierCount}} (已有:{{pokeballAmount}}) \n捕捉倍率:{{catchRate}}", + "獲得 {{pokeballName}} x{{modifierCount}} (已有:{{pokeballAmount}}) \n捕捉倍率:{{catchRate}}。", }, AddVoucherModifierType: { name: "{{modifierCount}}x {{voucherTypeName}}", - description: "獲得 {{voucherTypeName}} x{{modifierCount}}", + description: "獲得 {{voucherTypeName}} x{{modifierCount}}。", }, PokemonHeldItemModifierType: { extra: { @@ -19,25 +19,25 @@ export const modifierType: ModifierTypeTranslationEntries = { }, PokemonHpRestoreModifierType: { description: - "爲一隻寶可夢恢復 {{restorePoints}} HP 或 {{restorePercent}}% HP,取最大值", + "爲一隻寶可夢恢復 {{restorePoints}} HP 或 {{restorePercent}}% HP,取最大值。", extra: { - fully: "爲一隻寶可夢恢復全部HP", - fullyWithStatus: "爲一隻寶可夢恢復全部HP並消除所有負面\n狀態", + fully: "爲一隻寶可夢恢復全部HP。", + fullyWithStatus: "爲一隻寶可夢恢復全部HP並消除所有負面\n狀態。", }, }, PokemonReviveModifierType: { - description: "復活一隻寶可夢並恢復 {{restorePercent}}% HP", + description: "復活一隻寶可夢並恢復 {{restorePercent}}% HP。", }, PokemonStatusHealModifierType: { - description: "爲一隻寶可夢消除所有負面狀態", + description: "爲一隻寶可夢消除所有負面狀態。", }, PokemonPpRestoreModifierType: { - description: "爲一隻寶可夢的一個招式恢復 {{restorePoints}} PP", - extra: { fully: "完全恢復一隻寶可夢一個招式的PP" }, + description: "爲一隻寶可夢的一個招式恢復 {{restorePoints}} PP。", + extra: { fully: "完全恢復一隻寶可夢一個招式的PP。" }, }, PokemonAllMovePpRestoreModifierType: { - description: "爲一隻寶可夢的所有招式恢復 {{restorePoints}} PP", - extra: { fully: "爲一隻寶可夢的所有招式恢復所有PP" }, + description: "爲一隻寶可夢的所有招式恢復 {{restorePoints}} PP。", + extra: { fully: "爲一隻寶可夢的所有招式恢復所有PP。" }, }, PokemonPpUpModifierType: { description: @@ -46,101 +46,101 @@ export const modifierType: ModifierTypeTranslationEntries = { PokemonNatureChangeModifierType: { name: "{{natureName}}薄荷", description: - "將一隻寶可夢的性格改爲{{natureName}}併爲該寶可\n夢永久解鎖該性格.", + "將一隻寶可夢的性格改爲{{natureName}}併爲該寶可\n夢永久解鎖該性格。", }, DoubleBattleChanceBoosterModifierType: { - description: "接下來的{{battleCount}}場戰鬥是雙打的概率翻倍", + description: "接下來的{{battleCount}}場戰鬥是雙打的概率翻倍。", }, TempBattleStatBoosterModifierType: { description: - "爲所有成員寶可夢提升一級{{tempBattleStatName}},持續5場戰鬥", + "爲所有成員寶可夢提升一級{{tempBattleStatName}},持續5場戰鬥。", }, AttackTypeBoosterModifierType: { - description: "一隻寶可夢的{{moveType}}系招式威力提升20%", + description: "一隻寶可夢的{{moveType}}系招式威力提升20%。", }, PokemonLevelIncrementModifierType: { - description: "一隻寶可夢等級提升1級", + description: "一隻寶可夢等級提升1級。", }, AllPokemonLevelIncrementModifierType: { - description: "所有成員寶可夢等級提升1級", + description: "所有成員寶可夢等級提升1級。", }, PokemonBaseStatBoosterModifierType: { description: - "增加持有者的{{statName}}10%,個體值越高堆疊\n上限越高.", + "增加持有者的{{statName}}10%,個體值越高堆疊\n上限越高。", }, AllPokemonFullHpRestoreModifierType: { - description: "所有寶可夢完全恢復HP", + description: "所有寶可夢完全恢復HP。", }, AllPokemonFullReviveModifierType: { - description: "復活所有瀕死寶可夢,完全恢復HP", + description: "復活所有瀕死寶可夢,完全恢復HP。", }, MoneyRewardModifierType: { - description: "獲得{{moneyMultiplier}}金錢 (₽{{moneyAmount}})", + description: "獲得{{moneyMultiplier}}金錢 (₽{{moneyAmount}})。", extra: { small: "少量", moderate: "中等", large: "大量" }, }, ExpBoosterModifierType: { - description: "經驗值獲取量增加{{boostPercent}}%", + description: "經驗值獲取量增加{{boostPercent}}%。", }, PokemonExpBoosterModifierType: { - description: "持有者經驗值獲取量增加{{boostPercent}}%", + description: "持有者經驗值獲取量增加{{boostPercent}}%。", }, PokemonFriendshipBoosterModifierType: { - description: "每場戰鬥獲得的好感度提升50%", + description: "每場戰鬥獲得的好感度提升50%。", }, PokemonMoveAccuracyBoosterModifierType: { - description: "招式命中率增加{{accuracyAmount}} (最大100)", + description: "招式命中率增加{{accuracyAmount}} (最大100)。", }, PokemonMultiHitModifierType: { description: - "攻擊造成一次額外傷害,每次堆疊額外傷害\n分別衰減60/75/82.5%", + "攻擊造成一次額外傷害,每次堆疊額外傷害\n分別衰減60/75/82.5%。", }, TmModifierType: { name: "招式學習器 {{moveId}} - {{moveName}}", - description: "教會一隻寶可夢{{moveName}}", + description: "教會一隻寶可夢{{moveName}}。", }, TmModifierTypeWithInfo: { name: "TM{{moveId}} - {{moveName}}", - description: "教會一隻寶可夢{{moveName}}\n(Hold C or Shift for more info)", + description: "教會一隻寶可夢{{moveName}}\n(Hold C or Shift for more info)。", }, - EvolutionItemModifierType: { description: "使某些寶可夢進化" }, - FormChangeItemModifierType: { description: "使某些寶可夢更改形態" }, + EvolutionItemModifierType: { description: "使某些寶可夢進化。" }, + FormChangeItemModifierType: { description: "使某些寶可夢更改形態。" }, FusePokemonModifierType: { description: - "融合兩隻寶可夢 (改變特性, 平分基礎點數\n和屬性, 共享招式池)", + "融合兩隻寶可夢 (改變特性, 平分基礎點數\n和屬性, 共享招式池)。", }, TerastallizeModifierType: { name: "{{teraType}}太晶碎塊", - description: "持有者獲得{{teraType}}太晶化10場戰鬥", + description: "持有者獲得{{teraType}}太晶化10場戰鬥。", }, ContactHeldItemTransferChanceModifierType: { - description: "攻擊時{{chancePercent}}%概率偷取對手物品", + description: "攻擊時{{chancePercent}}%概率偷取對手物品。", }, TurnHeldItemTransferModifierType: { - description: "持有者每回合從對手那裏獲得一個持有的物品", + description: "持有者每回合從對手那裏獲得一個持有的物品。", }, EnemyAttackStatusEffectChanceModifierType: { - description: "攻擊時{{chancePercent}}%概率造成{{statusEffect}}", + description: "攻擊時{{chancePercent}}%概率造成{{statusEffect}}。", }, EnemyEndureChanceModifierType: { - description: "增加{{chancePercent}}%遭受攻擊的概率", + description: "增加{{chancePercent}}%遭受攻擊的概率。", }, RARE_CANDY: { name: "神奇糖果" }, RARER_CANDY: { name: "超神奇糖果" }, MEGA_BRACELET: { name: "超級手鐲", - description: "能讓攜帶着超級石戰鬥的寶可夢進行\n超級進化", + description: "能讓攜帶着超級石戰鬥的寶可夢進行\n超級進化。", }, DYNAMAX_BAND: { name: "極巨腕帶", - description: "能讓攜帶着極巨菇菇戰鬥的寶可夢進行\n極巨化", + description: "能讓攜帶着極巨菇菇戰鬥的寶可夢進行\n極巨化。", }, TERA_ORB: { name: "太晶珠", - description: "能讓攜帶着太晶碎塊戰鬥的寶可夢進行\n太晶化", + description: "能讓攜帶着太晶碎塊戰鬥的寶可夢進行\n太晶化。", }, MAP: { name: "地圖", - description: "允許你在切換寶可夢羣落時選擇目的地", + description: "允許你在切換寶可夢羣落時選擇目的地。", }, POTION: { name: "傷藥" }, SUPER_POTION: { name: "好傷藥" }, @@ -153,7 +153,7 @@ export const modifierType: ModifierTypeTranslationEntries = { SACRED_ASH: { name: "聖灰" }, REVIVER_SEED: { name: "復活種子", - description: "恢復1只瀕死寶可夢的HP至1/2", + description: "恢復1隻瀕死寶可夢的HP至1/2。", }, ETHER: { name: "PP單項小補劑" }, MAX_ETHER: { name: "PP單項全補劑" }, @@ -166,20 +166,20 @@ export const modifierType: ModifierTypeTranslationEntries = { MAX_LURE: { name: "黃金香水" }, MEMORY_MUSHROOM: { name: "回憶蘑菇", - description: "回憶一個寶可夢已經遺忘的招式", + description: "回憶一個寶可夢已經遺忘的招式。", }, EXP_SHARE: { name: "學習裝置", - description: "未參加對戰的寶可夢獲得20%的經驗值", + description: "未參加對戰的寶可夢獲得20%的經驗值。", }, EXP_BALANCE: { name: "均衡型學習裝置", - description: "隊伍中的低級寶可夢獲得更多經驗值", + description: "隊伍中的低級寶可夢獲得更多經驗值。", }, OVAL_CHARM: { name: "圓形護符", description: - "當多隻寶可夢參與戰鬥,分別獲得總經驗值\n10%的額外經驗值", + "當多隻寶可夢參與戰鬥,分別獲得總經驗值\n10%的額外經驗值。", }, EXP_CHARM: { name: "經驗護符" }, SUPER_EXP_CHARM: { name: "超級經驗護符" }, @@ -189,58 +189,58 @@ export const modifierType: ModifierTypeTranslationEntries = { SOOTHE_BELL: { name: "安撫之鈴" }, SOUL_DEW: { name: "心之水滴", - description: "增加寶可夢性格影響10% (加算)", + description: "增加寶可夢性格影響10% (加算)。", }, NUGGET: { name: "金珠" }, BIG_NUGGET: { name: "巨大金珠" }, RELIC_GOLD: { name: "古代金幣" }, - AMULET_COIN: { name: "護符金幣", description: "金錢獎勵增加20%" }, + AMULET_COIN: { name: "護符金幣", description: "金錢獎勵增加20%。" }, GOLDEN_PUNCH: { name: "黃金拳頭", - description: "將50%造成的傷害轉換爲金錢", + description: "將50%造成的傷害轉換爲金錢。", }, COIN_CASE: { name: "代幣盒", - description: "每十場戰鬥, 獲得自己金錢10%的利息", + description: "每十場戰鬥, 獲得自己金錢10%的利息。", }, LOCK_CAPSULE: { name: "上鎖的容器", - description: "允許在刷新物品時鎖定物品稀有度", + description: "允許在刷新物品時鎖定物品稀有度。", }, GRIP_CLAW: { name: "緊纏鉤爪" }, WIDE_LENS: { name: "廣角鏡" }, MULTI_LENS: { name: "多重鏡" }, HEALING_CHARM: { name: "治癒護符", - description: "HP恢復量增加10% (不含復活)", + description: "HP恢復量增加10% (不含復活)。", }, - CANDY_JAR: { name: "糖果罐", description: "神奇糖果提供的升級提升1級" }, + CANDY_JAR: { name: "糖果罐", description: "神奇糖果提供的升級提升1級。" }, BERRY_POUCH: { name: "樹果袋", - description: "使用樹果時有30%的幾率不會消耗樹果", + description: "使用樹果時有30%的幾率不會消耗樹果。", }, FOCUS_BAND: { name: "氣勢頭帶", description: - "攜帶該道具的寶可夢有10%幾率在受到\n攻擊而將陷入瀕死狀態時,保留1點HP不陷入瀕死狀態", + "攜帶該道具的寶可夢有10%幾率在受到\n攻擊而將陷入瀕死狀態時,保留1點HP不陷入瀕死狀態。", }, QUICK_CLAW: { name: "先制之爪", - description: "有10%的幾率無視速度優先使出招式\n(先制技能優先)", + description: "有10%的幾率無視速度優先使出招式\n(先制技能優先)。", }, KINGS_ROCK: { name: "王者之證", description: - "攜帶該道具的寶可夢使用任意原本不會造成\n畏縮狀態的攻擊招式並造成傷害時,有\n10%幾率使目標陷入畏縮狀態", + "攜帶該道具的寶可夢使用任意原本不會造成\n畏縮狀態的攻擊招式並造成傷害時,有\n10%幾率使目標陷入畏縮狀態。", }, LEFTOVERS: { name: "喫剩的東西", - description: "攜帶該道具的寶可夢在每個回合結束時恢復\n最大HP的1/16", + description: "攜帶該道具的寶可夢在每個回合結束時恢復\n最大HP的1/16。", }, SHELL_BELL: { name: "貝殼之鈴", description: - "攜帶該道具的寶可夢在攻擊對方成功造成傷\n害時,攜帶者的HP會恢復其所造成傷害\n的1/8", + "攜帶該道具的寶可夢在攻擊對方成功造成傷\n害時,攜帶者的HP會恢復其所造成傷害\n的1/8。", }, TOXIC_ORB: { name: "Toxic Orb", @@ -254,47 +254,47 @@ export const modifierType: ModifierTypeTranslationEntries = { }, BATON: { name: "接力棒", - description: "允許在切換寶可夢時保留能力變化, 對陷阱\n同樣生效", + description: "允許在切換寶可夢時保留能力變化, 對陷阱\n同樣生效。", }, SHINY_CHARM: { name: "閃耀護符", - description: "顯著增加野生寶可夢的閃光概率", + description: "顯著增加野生寶可夢的閃光概率。", }, ABILITY_CHARM: { name: "特性護符", - description: "顯著增加野生寶可夢有隱藏特性的概率", + description: "顯著增加野生寶可夢有隱藏特性的概率。", }, IV_SCANNER: { name: "個體值探測器", description: - "允許掃描野生寶可夢的個體值。 每個次顯示\n2個個體值. 最好的個體值優先顯示", + "允許掃描野生寶可夢的個體值。 每個次顯示\n2個個體值. 最好的個體值優先顯示。", }, DNA_SPLICERS: { name: "基因之楔" }, MINI_BLACK_HOLE: { name: "迷你黑洞" }, GOLDEN_POKEBALL: { name: "黃金精靈球", - description: "在每場戰鬥結束後增加一個額外物品選項", + description: "在每場戰鬥結束後增加一個額外物品選項。", }, ENEMY_DAMAGE_BOOSTER: { name: "傷害硬幣", - description: "增加5%造成傷害", + description: "增加5%造成傷害。", }, ENEMY_DAMAGE_REDUCTION: { name: "防禦硬幣", - description: "減少2.5%承受傷害", + description: "減少2.5%承受傷害。", }, - ENEMY_HEAL: { name: "恢復硬幣", description: "每回合恢復2%最大HP" }, + ENEMY_HEAL: { name: "恢復硬幣", description: "每回合恢復2%最大HP。" }, ENEMY_ATTACK_POISON_CHANCE: { name: "劇毒硬幣" }, ENEMY_ATTACK_PARALYZE_CHANCE: { name: "麻痹硬幣" }, ENEMY_ATTACK_BURN_CHANCE: { name: "灼燒硬幣" }, ENEMY_STATUS_EFFECT_HEAL_CHANCE: { name: "萬靈藥硬幣", - description: "增加2.5%每回合治癒異常狀態的概率", + description: "增加2.5%每回合治癒異常狀態的概率。", }, ENEMY_ENDURE_CHANCE: { name: "忍受硬幣" }, ENEMY_FUSED_CHANCE: { name: "融合硬幣", - description: "增加1%野生融合寶可夢出現概率", + description: "增加1%野生融合寶可夢出現概率。", }, }, TempBattleStatBoosterItem: { @@ -442,5 +442,43 @@ export const modifierType: ModifierTypeTranslationEntries = { BURN_DRIVE: "火焰卡帶", CHILL_DRIVE: "冰凍卡帶", DOUSE_DRIVE: "水流卡帶", + + "FIST_PLATE": "拳頭石板", + "SKY_PLATE": "藍天石板", + "TOXIC_PLATE": "劇毒石板", + "EARTH_PLATE": "大地石板", + "STONE_PLATE": "岩石石板", + "INSECT_PLATE": "玉蟲石板", + "SPOOKY_PLATE": "妖怪石板", + "IRON_PLATE": "鋼鐵石板", + "FLAME_PLATE": "火球石板", + "SPLASH_PLATE": "水滴石板", + "MEADOW_PLATE": "碧綠石板", + "ZAP_PLATE": "雷電石板", + "MIND_PLATE": "神奇石板", + "ICICLE_PLATE": "冰柱石板", + "DRACO_PLATE": "龍之石板", + "DREAD_PLATE": "惡顏石板", + "PIXIE_PLATE": "妖精石板", + "BLANK_PLATE": "淨空石板", + "LEGEND_PLATE": "傳說石板", + "FIGHTING_MEMORY": "戰鬥記憶碟", + "FLYING_MEMORY": "飛翔記憶碟", + "POISON_MEMORY": "毒記憶碟", + "GROUND_MEMORY": "大地記憶碟", + "ROCK_MEMORY": "岩石記憶碟", + "BUG_MEMORY": "蟲子記憶碟", + "GHOST_MEMORY": "幽靈記憶碟", + "STEEL_MEMORY": "鋼鐵記憶碟", + "FIRE_MEMORY": "火焰記憶碟", + "WATER_MEMORY": "清水記憶碟", + "GRASS_MEMORY": "青草記憶碟", + "ELECTRIC_MEMORY": "電子記憶碟", + "PSYCHIC_MEMORY": "精神記憶碟", + "ICE_MEMORY": "冰雪記憶碟", + "DRAGON_MEMORY": "龍記憶碟", + "DARK_MEMORY": "黑暗記憶碟", + "FAIRY_MEMORY": "妖精記憶碟", + "BLANK_MEMORY": "空白記憶碟", }, } as const; diff --git a/src/locales/zh_TW/move.ts b/src/locales/zh_TW/move.ts index 2dc42353a2b..a5e7898aa05 100644 --- a/src/locales/zh_TW/move.ts +++ b/src/locales/zh_TW/move.ts @@ -71,7 +71,7 @@ export const move: MoveTranslationEntries = { }, doubleKick: { name: "二連踢", - effect: "用2只腳踢飛對手進行攻擊。\n連續2次給予傷害", + effect: "用2隻腳踢飛對手進行攻擊。\n連續2次給予傷害", }, megaKick: { name: "百萬噸重踢", @@ -2886,7 +2886,7 @@ export const move: MoveTranslationEntries = { }, dragonDarts: { name: "龍箭", - effect: "讓多龍梅西亞進行2次攻擊。\n如果對手有2只寶可夢,\n則對它們各進行1次攻擊", + effect: "讓多龍梅西亞進行2次攻擊。\n如果對手有2隻寶可夢,\n則對它們各進行1次攻擊", }, teatime: { name: "茶會", diff --git a/src/locales/zh_TW/save-slot-select-ui-handler.ts b/src/locales/zh_TW/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..98b7764aee2 --- /dev/null +++ b/src/locales/zh_TW/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Overwrite the data in the selected slot?", + "loading": "Loading...", + "wave": "Wave", + "lv": "Lv", + "empty": "空", +} as const; diff --git a/src/locales/zh_TW/starter-select-ui-handler.ts b/src/locales/zh_TW/starter-select-ui-handler.ts index f7139a54189..c28cb39b94b 100644 --- a/src/locales/zh_TW/starter-select-ui-handler.ts +++ b/src/locales/zh_TW/starter-select-ui-handler.ts @@ -30,12 +30,12 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "selectMoveSwapWith": "選擇想要替換成的招式", "unlockPassive": "解鎖被動", "reduceCost": "降低花費", - "cycleShiny": "R: 切換閃光", - "cycleForm": "F: 切換形態", - "cycleGender": "G: 切換性別", - "cycleAbility": "E: 切換特性", - "cycleNature": "N: 切換性格", - "cycleVariant": "V: 切換變種", + "cycleShiny": ": 閃光", + "cycleForm": ": 形態", + "cycleGender": ": 性別", + "cycleAbility": ": 特性", + "cycleNature": ": 性格", + "cycleVariant": ": 變種", "enablePassive": "啟用被動", "disablePassive": "禁用被動", "locked": "未解鎖", diff --git a/src/locales/zh_TW/trainers.ts b/src/locales/zh_TW/trainers.ts index 07b2949bdd8..9a9af64ffb4 100644 --- a/src/locales/zh_TW/trainers.ts +++ b/src/locales/zh_TW/trainers.ts @@ -3,13 +3,13 @@ import {SimpleTranslationEntries} from "#app/plugins/i18n"; // Titles of special trainers like gym leaders, elite four, and the champion export const titles: SimpleTranslationEntries = { "elite_four": "四天王", - "elite_four_female": "Elite Four", + "elite_four_female": "四天王", "gym_leader": "道館館主", "gym_leader_female": "道館館主", - "gym_leader_double": "Gym Leader Duo", + "gym_leader_double": "道館館主", "champion": "冠軍", - "champion_female": "Champion", - "champion_double": "Champion Duo", + "champion_female": "冠軍", + "champion_double": "冠軍搭檔", "rival": "勁敵", "professor": "博士", "frontier_brain": "開拓頭腦", @@ -305,14 +305,14 @@ export const trainerNames: SimpleTranslationEntries = { "rival_female": "艾薇", // Double Names - "blue_red_double": "Blue & Red", - "red_blue_double": "Red & Blue", - "tate_liza_double": "Tate & Liza", - "liza_tate_double": "Liza & Tate", - "steven_wallace_double": "Steven & Wallace", - "wallace_steven_double": "Wallace & Steven", - "alder_iris_double": "Alder & Iris", - "iris_alder_double": "Iris & Alder", - "marnie_piers_double": "Marnie & Piers", - "piers_marnie_double": "Piers & Marnie", + "blue_red_double": "青綠 & 赤紅", + "red_blue_double": "赤紅 & 青綠", + "tate_liza_double": "小楓 & 小南", + "liza_tate_double": "小南 & 小楓", + "steven_wallace_double": "大吾 & 米可利", + "wallace_steven_double": "米可利 & 大吾", + "alder_iris_double": "阿戴克 & 艾莉絲", + "iris_alder_double": "艾莉絲 & 阿戴克", + "marnie_piers_double": "瑪俐 & 聶梓", + "piers_marnie_double": "聶梓 & 瑪俐", } as const; diff --git a/src/main.ts b/src/main.ts index 41cd68afc1e..e750335ddd4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -150,6 +150,7 @@ 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/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 46019281d4b..e3434a824f6 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -25,6 +25,7 @@ import i18next from "#app/plugins/i18n"; import { getModifierTierTextTint } from "#app/ui/text"; import { BattlerTagType } from "#app/data/enums/battler-tag-type.js"; import * as Overrides from "../overrides"; +import { MoneyMultiplierModifier } from "./modifier"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -631,9 +632,13 @@ export class MoneyRewardModifierType extends ModifierType { } getDescription(scene: BattleScene): string { + const moneyAmount = new Utils.IntegerHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); + scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); + const formattedMoney = Utils.formatMoney(scene.moneyFormat, moneyAmount.value); + return i18next.t("modifierType:ModifierType.MoneyRewardModifierType.description", { moneyMultiplier: i18next.t(this.moneyMultiplierDescriptorKey as any), - moneyAmount: scene.getWaveMoneyAmount(this.moneyMultiplier).toLocaleString("en-US"), + moneyAmount: formattedMoney, }); } } @@ -1312,7 +1317,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.EVOLUTION_ITEM, (party: Pokemon[]) => { return Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15), 8); }, 8), - new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode.isClassic ? 1 : 0, 1), + new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode.isClassic && party[0].scene.currentBattle.waveIndex < 180 ? 1 : 0, 1), new WeightedModifierType(modifierTypes.TM_GREAT, 2), new WeightedModifierType(modifierTypes.MEMORY_MUSHROOM, (party: Pokemon[]) => { if (!party.find(p => p.getLearnableLevelMoves().length)) { diff --git a/src/overrides.ts b/src/overrides.ts index f8e3152de98..782cc6552cd 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -79,7 +79,7 @@ export const VARIANT_OVERRIDE: Variant = 0; export const OPP_SPECIES_OVERRIDE: Species | integer = 0; export const OPP_LEVEL_OVERRIDE: number = 0; export const OPP_ABILITY_OVERRIDE: Abilities = Abilities.NONE; -export const OPP_PASSIVE_ABILITY_OVERRIDE = Abilities.NONE; +export const OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE; export const OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; export const OPP_GENDER_OVERRIDE: Gender = null; export const OPP_MOVESET_OVERRIDE: Array = []; diff --git a/src/phases.ts b/src/phases.ts index a235349cd6f..e649c8a291f 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -36,7 +36,7 @@ import { getBiomeKey } from "./field/arena"; import { BattleType, BattlerIndex, TurnCommand } from "./battle"; import { BattleSpec } from "./enums/battle-spec"; import { Species } from "./data/enums/species"; -import { HealAchv, LevelAchv, achvs } from "./system/achv"; +import { ChallengeAchv, HealAchv, LevelAchv, achvs } from "./system/achv"; import { TrainerSlot, trainerConfigs } from "./data/trainer-config"; import { TrainerType } from "./data/enums/trainer-type"; import { EggHatchPhase } from "./egg-hatch-phase"; @@ -55,14 +55,14 @@ import { TerrainType } from "./data/terrain"; import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select-ui-handler"; import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler"; import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run"; -import { GameModes, gameModes } from "./game-mode"; +import { GameMode, GameModes, getGameMode } from "./game-mode"; import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; import i18next from "./plugins/i18n"; import { Abilities } from "./data/enums/abilities"; import * as Overrides from "./overrides"; import { TextStyle, addTextObject } from "./ui/text"; import { Type } from "./data/type"; -import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./battle-scene-events"; +import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene"; import { ExpNotification } from "./enums/exp-notification"; @@ -202,14 +202,21 @@ export class TitlePhase extends Phase { if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { const options: OptionSelectItem[] = [ { - label: gameModes[GameModes.CLASSIC].getName(), + label: GameMode.getModeName(GameModes.CLASSIC), handler: () => { setModeAndEnd(GameModes.CLASSIC); return true; } }, { - label: gameModes[GameModes.ENDLESS].getName(), + label: GameMode.getModeName(GameModes.CHALLENGE), + handler: () => { + setModeAndEnd(GameModes.CHALLENGE); + return true; + } + }, + { + label: GameMode.getModeName(GameModes.ENDLESS), handler: () => { setModeAndEnd(GameModes.ENDLESS); return true; @@ -218,7 +225,7 @@ export class TitlePhase extends Phase { ]; if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { options.push({ - label: gameModes[GameModes.SPLICED_ENDLESS].getName(), + label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), handler: () => { setModeAndEnd(GameModes.SPLICED_ENDLESS); return true; @@ -307,7 +314,7 @@ export class TitlePhase extends Phase { this.scene.sessionSlotId = slotId; const generateDaily = (seed: string) => { - this.scene.gameMode = gameModes[GameModes.DAILY]; + this.scene.gameMode = getGameMode(GameModes.DAILY); this.scene.setSeed(seed); this.scene.resetSeed(1); @@ -369,7 +376,12 @@ export class TitlePhase extends Phase { end(): void { if (!this.loaded && !this.scene.gameMode.isDaily) { this.scene.arena.preloadBgm(); - this.scene.pushPhase(new SelectStarterPhase(this.scene, this.gameMode)); + this.scene.gameMode = getGameMode(this.gameMode); + if (this.gameMode === GameModes.CHALLENGE) { + this.scene.pushPhase(new SelectChallengePhase(this.scene)); + } else { + this.scene.pushPhase(new SelectStarterPhase(this.scene)); + } this.scene.newArena(this.scene.gameMode.getStartingBiome(this.scene)); } else { this.scene.playBgm(); @@ -378,7 +390,7 @@ export class TitlePhase extends Phase { this.scene.pushPhase(new EncounterPhase(this.scene, this.loaded)); if (this.loaded) { - const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()).length; + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true)); if (this.scene.currentBattle.double && availablePartyMembers > 1) { @@ -504,13 +516,24 @@ export class SelectGenderPhase extends Phase { } } -export class SelectStarterPhase extends Phase { - private gameMode: GameModes; - - constructor(scene: BattleScene, gameMode: GameModes) { +export class SelectChallengePhase extends Phase { + constructor(scene: BattleScene) { super(scene); + } - this.gameMode = gameMode; + start() { + super.start(); + + this.scene.playBgm("menu"); + + this.scene.ui.setMode(Mode.CHALLENGE_SELECT); + } +} + +export class SelectStarterPhase extends Phase { + + constructor(scene: BattleScene) { + super(scene); } start() { @@ -529,7 +552,7 @@ export class SelectStarterPhase extends Phase { this.scene.sessionSlotId = slotId; this.initBattle(starters); }); - }, this.gameMode); + }); } initBattle(starters: Starter[]) { @@ -638,7 +661,14 @@ export abstract class FieldPhase extends BattlePhase { const enemyField = this.scene.getEnemyField().filter(p => p.isActive()) as Pokemon[]; // We shuffle the list before sorting so speed ties produce random results - let orderedTargets: Pokemon[] = Utils.randSeedShuffle(playerField.concat(enemyField)).sort((a: Pokemon, b: Pokemon) => { + let orderedTargets: Pokemon[] = playerField.concat(enemyField); + // We seed it with the current turn to prevent an inconsistency where it + // was varying based on how long since you last reloaded + this.scene.executeWithSeedOffset(() => { + orderedTargets = Utils.randSeedShuffle(orderedTargets); + }, this.scene.currentBattle.turn, this.scene.waveSeed); + + orderedTargets.sort((a: Pokemon, b: Pokemon) => { const aSpeed = a?.getBattleStat(Stat.SPD) || 0; const bSpeed = b?.getBattleStat(Stat.SPD) || 0; @@ -994,7 +1024,15 @@ export class EncounterPhase extends BattlePhase { }); if (this.scene.currentBattle.battleType !== BattleType.TRAINER) { - enemyField.map(p => this.scene.pushPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()))); + enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => { + // is the player party initialized ? + const a = !!this.scene.getParty()?.length; + // how many player pokemon are on the field ? + const amountOnTheField = this.scene.getParty().filter(p => p.isOnField()).length; + // if it's a double, there should be 2, otherwise 1 + const b = this.scene.currentBattle.double ? amountOnTheField === 2 : amountOnTheField === 1; + return a && b; + })); const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier); if (ivScannerModifier) { enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6)))); @@ -1002,7 +1040,7 @@ export class EncounterPhase extends BattlePhase { } if (!this.loaded) { - const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()); + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); if (!availablePartyMembers[0].isOnField()) { this.scene.pushPhase(new SummonPhase(this.scene, 0)); @@ -1056,6 +1094,10 @@ export class NextEncounterPhase extends EncounterPhase { super(scene); } + start() { + super.start(); + } + doEncounter(): void { this.scene.playBgm(undefined, true); @@ -1135,6 +1177,9 @@ export class PostSummonPhase extends PokemonPhase { const pokemon = this.getPokemon(); + if (pokemon.status?.effect === StatusEffect.TOXIC) { + pokemon.status.turnCount = 0; + } this.scene.arena.applyTags(ArenaTrapTag, pokemon); applyPostSummonAbAttrs(PostSummonAbAttr, pokemon).then(() => this.end()); } @@ -1295,20 +1340,33 @@ export class SummonPhase extends PartyMemberPokemonPhase { */ preSummon(): void { const partyMember = this.getPokemon(); - // If the Pokemon about to be sent out is fainted, switch to the first non-fainted Pokemon - if (partyMember.isFainted()) { - console.warn("The Pokemon about to be sent out is fainted. Attempting to resolve..."); + // If the Pokemon about to be sent out is fainted or illegal under a challenge, switch to the first non-fainted legal Pokemon + if (!partyMember.isAllowedInBattle()) { + console.warn("The Pokemon about to be sent out is fainted or illegal under a challenge. Attempting to resolve..."); + + // First check if they're somehow still in play, if so remove them. + if (partyMember.isOnField()) { + partyMember.hideInfo(); + partyMember.setVisible(false); + this.scene.field.remove(partyMember); + this.scene.triggerPokemonFormChange(partyMember, SpeciesFormChangeActiveTrigger, true); + } + const party = this.getParty(); // Find the first non-fainted Pokemon index above the current one - const nonFaintedIndex = party.findIndex((p, i) => i > this.partyMemberIndex && !p.isFainted()); - if (nonFaintedIndex === -1) { + const legalIndex = party.findIndex((p, i) => i > this.partyMemberIndex && p.isAllowedInBattle()); + if (legalIndex === -1) { console.error("Party Details:\n", party); - throw new Error("All available Pokemon were fainted!"); + console.error("All available Pokemon were fainted or illegal!"); + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + this.end(); + return; } - // Swaps the fainted Pokemon and the first non-fainted Pokemon in the party - [party[this.partyMemberIndex], party[nonFaintedIndex]] = [party[nonFaintedIndex], party[this.partyMemberIndex]]; + // Swaps the fainted Pokemon and the first non-fainted legal Pokemon in the party + [party[this.partyMemberIndex], party[legalIndex]] = [party[legalIndex], party[this.partyMemberIndex]]; console.warn("Swapped %s %O with %s %O", partyMember?.name, partyMember, party[0]?.name, party[0]); } @@ -1352,7 +1410,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { if (this.fieldIndex === 1) { pokemon.setFieldPosition(FieldPosition.RIGHT, 0); } else { - const availablePartyMembers = this.getParty().filter(p => !p.isFainted()).length; + const availablePartyMembers = this.getParty().filter(p => p.isAllowedInBattle()).length; pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT); } @@ -1430,7 +1488,6 @@ export class SummonPhase extends PartyMemberPokemonPhase { if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) { this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); - this.queuePostSummon(); } } @@ -1461,6 +1518,10 @@ export class SwitchSummonPhase extends SummonPhase { this.batonPass = batonPass; } + start(): void { + super.start(); + } + preSummon(): void { if (!this.player) { if (this.slotIndex === -1) { @@ -1642,7 +1703,7 @@ export class ToggleDoublePositionPhase extends BattlePhase { const playerPokemon = this.scene.getPlayerField().find(p => p.isActive(true)); if (playerPokemon) { - playerPokemon.setFieldPosition(this.double && this.scene.getParty().filter(p => !p.isFainted()).length > 1 ? FieldPosition.LEFT : FieldPosition.CENTER, 500).then(() => { + playerPokemon.setFieldPosition(this.double && this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? FieldPosition.LEFT : FieldPosition.CENTER, 500).then(() => { if (playerPokemon.getFieldIndex() === 1) { const party = this.scene.getParty(); party[1] = party[0]; @@ -1742,6 +1803,34 @@ export class TurnInitPhase extends FieldPhase { start() { super.start(); + this.scene.getPlayerField().forEach(p => { + // If this pokemon is in play and evolved into something illegal under the current challenge, force a switch + if (p.isOnField() && !p.isAllowedInBattle()) { + this.scene.queueMessage(i18next.t("challenges:illegalEvolution", {"pokemon": p.name}), null, true); + + const allowedPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); + + if (!allowedPokemon.length) { + // If there are no longer any legal pokemon in the party, game over. + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + } else if (allowedPokemon.length >= this.scene.currentBattle.getBattlerCount() || (this.scene.currentBattle.double && !allowedPokemon[0].isActive(true))) { + // If there is at least one pokemon in the back that is legal to switch in, force a switch. + p.switchOut(false, true); + } else { + // If there are no pokemon in the back but we're not game overing, just hide the pokemon. + // This should only happen in double battles. + p.hideInfo(); + p.setVisible(false); + this.scene.field.remove(p); + this.scene.triggerPokemonFormChange(p, SpeciesFormChangeActiveTrigger, true); + } + if (allowedPokemon.length === 1 && this.scene.currentBattle.double) { + this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); + } + } + }); + //this.scene.pushPhase(new MoveAnimTestPhase(this.scene)); this.scene.eventTarget.dispatchEvent(new TurnInitEvent()); @@ -1776,9 +1865,15 @@ export class CommandPhase extends FieldPhase { super.start(); if (this.fieldIndex) { - const allyCommand = this.scene.currentBattle.turnCommands[this.fieldIndex - 1]; - if (allyCommand.command === Command.BALL || allyCommand.command === Command.RUN) { - this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand.command, skip: true }; + // If we somehow are attempting to check the right pokemon but there's only one pokemon out + // Switch back to the center pokemon. This can happen rarely in double battles with mid turn switching + if (this.scene.getPlayerField().filter(p => p.isActive()).length === 1) { + this.fieldIndex = FieldPosition.CENTER; + } else { + const allyCommand = this.scene.currentBattle.turnCommands[this.fieldIndex - 1]; + if (allyCommand.command === Command.BALL || allyCommand.command === Command.RUN) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand.command, skip: true }; + } } } @@ -2353,7 +2448,7 @@ export class BattleEndPhase extends BattlePhase { } } - for (const pokemon of this.scene.getParty().filter(p => !p.isFainted())) { + for (const pokemon of this.scene.getParty().filter(p => p.isAllowedInBattle())) { applyPostBattleAbAttrs(PostBattleAbAttr, pokemon); } @@ -3486,7 +3581,7 @@ export class DamagePhase extends PokemonPhase { this.scene.setFieldScale(0.75); this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); this.scene.currentBattle.double = true; - const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()); + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); if (availablePartyMembers.length > 1) { this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true)); if (!availablePartyMembers[1].isOnField()) { @@ -3568,11 +3663,11 @@ export class FaintPhase extends PokemonPhase { } if (this.player) { - const nonFaintedPartyMembers = this.scene.getParty().filter(p => !p.isFainted()); - const nonFaintedPartyMemberCount = nonFaintedPartyMembers.length; + const nonFaintedLegalPartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); + const nonFaintedPartyMemberCount = nonFaintedLegalPartyMembers.length; if (!nonFaintedPartyMemberCount) { this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } else if (nonFaintedPartyMemberCount >= this.scene.currentBattle.getBattlerCount() || (this.scene.currentBattle.double && !nonFaintedPartyMembers[0].isActive(true))) { + } else if (nonFaintedPartyMemberCount >= this.scene.currentBattle.getBattlerCount() || (this.scene.currentBattle.double && !nonFaintedLegalPartyMembers[0].isActive(true))) { this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false)); } if (nonFaintedPartyMemberCount === 1 && this.scene.currentBattle.double) { @@ -3966,7 +4061,7 @@ export class GameOverPhase extends BattlePhase { this.scene.gameData.loadSession(this.scene, this.scene.sessionSlotId).then(() => { this.scene.pushPhase(new EncounterPhase(this.scene, true)); - const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()).length; + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; this.scene.pushPhase(new SummonPhase(this.scene, 0)); if (this.scene.currentBattle.double && availablePartyMembers > 1) { @@ -4018,6 +4113,10 @@ export class GameOverPhase extends BattlePhase { this.scene.clearPhaseQueue(); this.scene.ui.clearText(); + if (this.victory && this.scene.gameMode.isChallenge) { + this.scene.gameMode.challenges.forEach(c => this.scene.validateAchvs(ChallengeAchv, c)); + } + const clear = (endCardPhase?: EndCardPhase) => { if (newClear) { this.handleUnlocks(); @@ -4221,17 +4320,17 @@ export class SwitchPhase extends BattlePhase { super.start(); // Skip modal switch if impossible - if (this.isModal && !this.scene.getParty().filter(p => !p.isFainted() && !p.isActive(true)).length) { + if (this.isModal && !this.scene.getParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) { return super.end(); } // Check if there is any space still in field - if (this.isModal && this.scene.getPlayerField().filter(p => !p.isFainted() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) { + if (this.isModal && this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) { return super.end(); } - // Override field index to 0 in case of double battle where 2/3 remaining party members fainted at once - const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => !p.isFainted()).length > 1 ? this.fieldIndex : 0; + // Override field index to 0 in case of double battle where 2/3 remaining legal party members fainted at once + const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? this.fieldIndex : 0; this.scene.ui.setMode(Mode.PARTY, this.isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH, fieldIndex, (slotIndex: integer, option: PartyOption) => { if (slotIndex >= this.scene.currentBattle.getBattlerCount() && slotIndex < 6) { @@ -4917,7 +5016,8 @@ export class SelectModifierPhase extends BattlePhase { let cost: integer; switch (rowCursor) { case 0: - if (!cursor) { + switch (cursor) { + case 0: const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers); if (this.scene.money < rerollCost) { this.scene.ui.playError(); @@ -4932,18 +5032,25 @@ export class SelectModifierPhase extends BattlePhase { this.scene.animateMoneyChanged(false); this.scene.playSound("buy"); } - } else if (cursor === 1) { + break; + case 1: this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => { if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; + && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; const itemModifier = itemModifiers[itemIndex]; this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity); } else { this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); } }, PartyUiHandler.FilterItemMaxStacks); - } else { + break; + case 2: + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + }); + break; + case 3: this.scene.lockModifierTiers = !this.scene.lockModifierTiers; const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler; uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); @@ -5091,15 +5198,15 @@ export class EggLapsePhase extends Phase { return Overrides.IMMEDIATE_HATCH_EGGS_OVERRIDE ? true : --egg.hatchWaves < 1; }); - let eggsToHatchCount: integer = eggsToHatch.length; + let eggCount: integer = eggsToHatch.length; - if (eggsToHatchCount) { + if (eggCount) { this.scene.queueMessage(i18next.t("battle:eggHatching")); for (const egg of eggsToHatch) { - this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg, eggsToHatchCount)); - if (eggsToHatchCount > 0) { - eggsToHatchCount--; + this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg, eggCount)); + if (eggCount > 0) { + eggCount--; } } diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 5356c94fe7f..5a6353d5f2c 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -88,50 +88,25 @@ export interface Localizable { localize(): void; } -const alternativeFonts = { - "ko": [ - new FontFace("emerald", "url(./fonts/PokePT_Wansung.ttf)"), - ], -}; +const fonts = [ + new FontFace("emerald", "url(./fonts/PokePT_Wansung.ttf)"), + new FontFace("emerald", "url(./fonts/pokemon-emerald-pro.ttf"), +]; -function loadFont(language: string) { - if (!alternativeFonts[language]) { - language = language.split(/[-_/]/)[0]; - } - if (alternativeFonts[language]) { - alternativeFonts[language].forEach((fontFace: FontFace) => { - document.fonts.add(fontFace); - }); - - const altFontLanguages = Object.keys(alternativeFonts); - altFontLanguages.splice(altFontLanguages.indexOf(language), 0); - } - - (Object.values(alternativeFonts)).forEach(fontFaces => { - fontFaces.forEach(fontFace => { - if (fontFace && fontFace.status === "loaded") { - document.fonts.delete(fontFace); - } - }); +function initFonts() { + fonts.forEach((fontFace: FontFace) => { + fontFace.load().then(f => document.fonts.add(f)).catch(e => console.error(e)); }); } -export function initI18n(): void { +export async function initI18n(): Promise { // Prevent reinitialization if (isInitialized) { return; } isInitialized = true; - let lang = ""; - if (localStorage.getItem("prLang")) { - lang = localStorage.getItem("prLang"); - } - - loadFont(lang); - i18next.on("languageChanged", lng=> { - loadFont(lng); - }); + initFonts(); /** * i18next is a localization library for maintaining and using translation resources. @@ -149,11 +124,16 @@ export function initI18n(): void { * A: In src/system/settings.ts, add a new case to the Setting.Language switch statement. */ - i18next.use(LanguageDetector).use(processor).use(new KoreanPostpositionProcessor()).init({ - lng: lang, + i18next.use(LanguageDetector); + i18next.use(processor); + i18next.use(new KoreanPostpositionProcessor()); + await i18next.init({ nonExplicitSupportedLngs: true, fallbackLng: "en", supportedLngs: ["en", "es", "fr", "it", "de", "zh", "pt", "ko"], + detection: { + lookupLocalStorage: "prLang" + }, debug: true, interpolation: { escapeValue: false, @@ -196,35 +176,16 @@ declare module "i18next" { interface CustomTypeOptions { defaultNS: "menu"; // Even if we don't use it, i18next requires a valid default namespace resources: { - menu: SimpleTranslationEntries; - menuUiHandler: SimpleTranslationEntries; - move: MoveTranslationEntries; - battle: SimpleTranslationEntries; - abilityTriggers: SimpleTranslationEntries; ability: AbilityTranslationEntries; - pokeball: SimpleTranslationEntries; - pokemon: SimpleTranslationEntries; - pokemonInfo: PokemonInfoTranslationEntries; - commandUiHandler: SimpleTranslationEntries; - fightUiHandler: SimpleTranslationEntries; - titles: SimpleTranslationEntries; - trainerClasses: SimpleTranslationEntries; - trainerNames: SimpleTranslationEntries; - tutorial: SimpleTranslationEntries; - starterSelectUiHandler: SimpleTranslationEntries; - splashMessages: SimpleTranslationEntries; - nature: SimpleTranslationEntries; - growth: SimpleTranslationEntries; - egg: SimpleTranslationEntries; - weather: SimpleTranslationEntries; - modifierType: ModifierTypeTranslationEntries; + abilityTriggers: SimpleTranslationEntries; + achv: AchievementTranslationEntries; + battle: SimpleTranslationEntries; battleMessageUiHandler: SimpleTranslationEntries; berry: BerryTranslationEntries; - achv: AchievementTranslationEntries; - gameStatsUiHandler: SimpleTranslationEntries; - voucher: SimpleTranslationEntries; biome: SimpleTranslationEntries; - pokemonInfoContainer: SimpleTranslationEntries; + challenges: SimpleTranslationEntries; + commandUiHandler: SimpleTranslationEntries; + PGMachv: AchievementTranslationEntries; PGMdialogue: DialogueTranslationEntries; PGMbattleSpecDialogue: SimpleTranslationEntries; PGMmiscDialogue: SimpleTranslationEntries; @@ -233,7 +194,31 @@ declare module "i18next" { PGFbattleSpecDialogue: SimpleTranslationEntries; PGFmiscDialogue: SimpleTranslationEntries; PGFdoubleBattleDialogue: DialogueTranslationEntries; + PGFachv: AchievementTranslationEntries; + egg: SimpleTranslationEntries; + fightUiHandler: SimpleTranslationEntries; + gameMode: SimpleTranslationEntries; + gameStatsUiHandler: SimpleTranslationEntries; + growth: SimpleTranslationEntries; + menu: SimpleTranslationEntries; + menuUiHandler: SimpleTranslationEntries; + modifierType: ModifierTypeTranslationEntries; + move: MoveTranslationEntries; + nature: SimpleTranslationEntries; partyUiHandler: SimpleTranslationEntries; + pokeball: SimpleTranslationEntries; + pokemon: SimpleTranslationEntries; + pokemonInfo: PokemonInfoTranslationEntries; + pokemonInfoContainer: SimpleTranslationEntries; + saveSlotSelectUiHandler: SimpleTranslationEntries; + splashMessages: SimpleTranslationEntries; + starterSelectUiHandler: SimpleTranslationEntries; + titles: SimpleTranslationEntries; + trainerClasses: SimpleTranslationEntries; + trainerNames: SimpleTranslationEntries; + tutorial: SimpleTranslationEntries; + voucher: SimpleTranslationEntries; + weather: SimpleTranslationEntries; }; } } @@ -245,3 +230,4 @@ export function getIsInitialized(): boolean { } let isInitialized = false; + diff --git a/src/system/achv.ts b/src/system/achv.ts index 364b7e0c579..f44ea2a9301 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -3,6 +3,9 @@ import BattleScene from "../battle-scene"; import { TurnHeldItemTransferModifier } from "../modifier/modifier"; import i18next from "../plugins/i18n"; import * as Utils from "../utils"; +import { PlayerGender } from "#app/data/enums/player-gender"; +import { ParseKeys } from "i18next"; +import { Challenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge.js"; export enum AchvTier { COMMON, @@ -35,9 +38,15 @@ export class Achv { this.localizationKey = localizationKey; } - getName(): string { + /** + * Get the name of the achievement based on the gender of the player + * @param playerGender - the gender of the player + * @returns the name of the achievement localized for the player gender + */ + getName(playerGender: PlayerGender): string { + const prefix = playerGender === PlayerGender.FEMALE ?"PGF" : "PGM"; // Localization key is used to get the name of the achievement - return i18next.t(`achv:${this.localizationKey}.name`); + return i18next.t(`${prefix}achv:${this.localizationKey}.name` as ParseKeys); } getDescription(): string { @@ -126,6 +135,12 @@ export class ModifierAchv extends Achv { } } +export class ChallengeAchv extends Achv { + constructor(localizationKey: string, name: string, description: string, iconImage: string, score: integer, challengeFunc: (challenge: Challenge) => boolean) { + super(localizationKey, name, description, iconImage, score, (_scene: BattleScene, args: any[]) => challengeFunc((args[0] as Challenge))); + } +} + /** * Get the description of an achievement from the localization file with all the necessary variables filled in @@ -133,87 +148,134 @@ export class ModifierAchv extends Achv { * @returns The description of the achievement */ export function getAchievementDescription(localizationKey: string): string { + // We need to get the player gender from the game data to add the correct prefix to the achievement name + let playerGender = PlayerGender.MALE; + if (this?.scene) { + playerGender = this.scene.gameData.gender; + } + let genderPrefix = "PGM"; + if (playerGender === PlayerGender.FEMALE) { + genderPrefix = "PGF"; + } + switch (localizationKey) { case "10K_MONEY": - return i18next.t("achv:MoneyAchv.description", {"moneyAmount": achvs._10K_MONEY.moneyAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:MoneyAchv.description` as ParseKeys, {"moneyAmount": achvs._10K_MONEY.moneyAmount.toLocaleString("en-US")}); case "100K_MONEY": - return i18next.t("achv:MoneyAchv.description", {"moneyAmount": achvs._100K_MONEY.moneyAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:MoneyAchv.description` as ParseKeys, {"moneyAmount": achvs._100K_MONEY.moneyAmount.toLocaleString("en-US")}); case "1M_MONEY": - return i18next.t("achv:MoneyAchv.description", {"moneyAmount": achvs._1M_MONEY.moneyAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:MoneyAchv.description` as ParseKeys, {"moneyAmount": achvs._1M_MONEY.moneyAmount.toLocaleString("en-US")}); case "10M_MONEY": - return i18next.t("achv:MoneyAchv.description", {"moneyAmount": achvs._10M_MONEY.moneyAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:MoneyAchv.description` as ParseKeys, {"moneyAmount": achvs._10M_MONEY.moneyAmount.toLocaleString("en-US")}); case "250_DMG": - return i18next.t("achv:DamageAchv.description", {"damageAmount": achvs._250_DMG.damageAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:DamageAchv.description` as ParseKeys, {"damageAmount": achvs._250_DMG.damageAmount.toLocaleString("en-US")}); case "1000_DMG": - return i18next.t("achv:DamageAchv.description", {"damageAmount": achvs._1000_DMG.damageAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:DamageAchv.description` as ParseKeys, {"damageAmount": achvs._1000_DMG.damageAmount.toLocaleString("en-US")}); case "2500_DMG": - return i18next.t("achv:DamageAchv.description", {"damageAmount": achvs._2500_DMG.damageAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:DamageAchv.description` as ParseKeys, {"damageAmount": achvs._2500_DMG.damageAmount.toLocaleString("en-US")}); case "10000_DMG": - return i18next.t("achv:DamageAchv.description", {"damageAmount": achvs._10000_DMG.damageAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:DamageAchv.description` as ParseKeys, {"damageAmount": achvs._10000_DMG.damageAmount.toLocaleString("en-US")}); case "250_HEAL": - return i18next.t("achv:HealAchv.description", {"healAmount": achvs._250_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); + return i18next.t(`${genderPrefix}achv:HealAchv.description` as ParseKeys, {"healAmount": achvs._250_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); case "1000_HEAL": - return i18next.t("achv:HealAchv.description", {"healAmount": achvs._1000_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); + return i18next.t(`${genderPrefix}achv:HealAchv.description` as ParseKeys, {"healAmount": achvs._1000_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); case "2500_HEAL": - return i18next.t("achv:HealAchv.description", {"healAmount": achvs._2500_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); + return i18next.t(`${genderPrefix}achv:HealAchv.description` as ParseKeys, {"healAmount": achvs._2500_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); case "10000_HEAL": - return i18next.t("achv:HealAchv.description", {"healAmount": achvs._10000_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); + return i18next.t(`${genderPrefix}achv:HealAchv.description` as ParseKeys, {"healAmount": achvs._10000_HEAL.healAmount.toLocaleString("en-US"), "HP": i18next.t("pokemonInfo:Stat.HPshortened")}); case "LV_100": - return i18next.t("achv:LevelAchv.description", {"level": achvs.LV_100.level}); + return i18next.t(`${genderPrefix}achv:LevelAchv.description` as ParseKeys, {"level": achvs.LV_100.level}); case "LV_250": - return i18next.t("achv:LevelAchv.description", {"level": achvs.LV_250.level}); + return i18next.t(`${genderPrefix}achv:LevelAchv.description` as ParseKeys, {"level": achvs.LV_250.level}); case "LV_1000": - return i18next.t("achv:LevelAchv.description", {"level": achvs.LV_1000.level}); + return i18next.t(`${genderPrefix}achv:LevelAchv.description` as ParseKeys, {"level": achvs.LV_1000.level}); case "10_RIBBONS": - return i18next.t("achv:RibbonAchv.description", {"ribbonAmount": achvs._10_RIBBONS.ribbonAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:RibbonAchv.description` as ParseKeys, {"ribbonAmount": achvs._10_RIBBONS.ribbonAmount.toLocaleString("en-US")}); case "25_RIBBONS": - return i18next.t("achv:RibbonAchv.description", {"ribbonAmount": achvs._25_RIBBONS.ribbonAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:RibbonAchv.description` as ParseKeys, {"ribbonAmount": achvs._25_RIBBONS.ribbonAmount.toLocaleString("en-US")}); case "50_RIBBONS": - return i18next.t("achv:RibbonAchv.description", {"ribbonAmount": achvs._50_RIBBONS.ribbonAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:RibbonAchv.description` as ParseKeys, {"ribbonAmount": achvs._50_RIBBONS.ribbonAmount.toLocaleString("en-US")}); case "75_RIBBONS": - return i18next.t("achv:RibbonAchv.description", {"ribbonAmount": achvs._75_RIBBONS.ribbonAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:RibbonAchv.description` as ParseKeys, {"ribbonAmount": achvs._75_RIBBONS.ribbonAmount.toLocaleString("en-US")}); case "100_RIBBONS": - return i18next.t("achv:RibbonAchv.description", {"ribbonAmount": achvs._100_RIBBONS.ribbonAmount.toLocaleString("en-US")}); + return i18next.t(`${genderPrefix}achv:RibbonAchv.description` as ParseKeys, {"ribbonAmount": achvs._100_RIBBONS.ribbonAmount.toLocaleString("en-US")}); case "TRANSFER_MAX_BATTLE_STAT": - return i18next.t("achv:TRANSFER_MAX_BATTLE_STAT.description"); + return i18next.t(`${genderPrefix}achv:TRANSFER_MAX_BATTLE_STAT.description` as ParseKeys); case "MAX_FRIENDSHIP": - return i18next.t("achv:MAX_FRIENDSHIP.description"); + return i18next.t(`${genderPrefix}achv:MAX_FRIENDSHIP.description` as ParseKeys); case "MEGA_EVOLVE": - return i18next.t("achv:MEGA_EVOLVE.description"); + return i18next.t(`${genderPrefix}achv:MEGA_EVOLVE.description` as ParseKeys); case "GIGANTAMAX": - return i18next.t("achv:GIGANTAMAX.description"); + return i18next.t(`${genderPrefix}achv:GIGANTAMAX.description` as ParseKeys); case "TERASTALLIZE": - return i18next.t("achv:TERASTALLIZE.description"); + return i18next.t(`${genderPrefix}achv:TERASTALLIZE.description` as ParseKeys); case "STELLAR_TERASTALLIZE": - return i18next.t("achv:STELLAR_TERASTALLIZE.description"); + return i18next.t(`${genderPrefix}achv:STELLAR_TERASTALLIZE.description` as ParseKeys); case "SPLICE": - return i18next.t("achv:SPLICE.description"); + return i18next.t(`${genderPrefix}achv:SPLICE.description` as ParseKeys); case "MINI_BLACK_HOLE": - return i18next.t("achv:MINI_BLACK_HOLE.description"); + return i18next.t(`${genderPrefix}achv:MINI_BLACK_HOLE.description` as ParseKeys); case "CATCH_MYTHICAL": - return i18next.t("achv:CATCH_MYTHICAL.description"); + return i18next.t(`${genderPrefix}achv:CATCH_MYTHICAL.description` as ParseKeys); case "CATCH_SUB_LEGENDARY": - return i18next.t("achv:CATCH_SUB_LEGENDARY.description"); + return i18next.t(`${genderPrefix}achv:CATCH_SUB_LEGENDARY.description` as ParseKeys); case "CATCH_LEGENDARY": - return i18next.t("achv:CATCH_LEGENDARY.description"); + return i18next.t(`${genderPrefix}achv:CATCH_LEGENDARY.description` as ParseKeys); case "SEE_SHINY": - return i18next.t("achv:SEE_SHINY.description"); + return i18next.t(`${genderPrefix}achv:SEE_SHINY.description` as ParseKeys); case "SHINY_PARTY": - return i18next.t("achv:SHINY_PARTY.description"); + return i18next.t(`${genderPrefix}achv:SHINY_PARTY.description` as ParseKeys); case "HATCH_MYTHICAL": - return i18next.t("achv:HATCH_MYTHICAL.description"); + return i18next.t(`${genderPrefix}achv:HATCH_MYTHICAL.description` as ParseKeys); case "HATCH_SUB_LEGENDARY": - return i18next.t("achv:HATCH_SUB_LEGENDARY.description"); + return i18next.t(`${genderPrefix}achv:HATCH_SUB_LEGENDARY.description` as ParseKeys); case "HATCH_LEGENDARY": - return i18next.t("achv:HATCH_LEGENDARY.description"); + return i18next.t(`${genderPrefix}achv:HATCH_LEGENDARY.description` as ParseKeys); case "HATCH_SHINY": - return i18next.t("achv:HATCH_SHINY.description"); + return i18next.t(`${genderPrefix}achv:HATCH_SHINY.description` as ParseKeys); case "HIDDEN_ABILITY": - return i18next.t("achv:HIDDEN_ABILITY.description"); + return i18next.t(`${genderPrefix}achv:HIDDEN_ABILITY.description` as ParseKeys); case "PERFECT_IVS": - return i18next.t("achv:PERFECT_IVS.description"); + return i18next.t(`${genderPrefix}achv:PERFECT_IVS.description` as ParseKeys); case "CLASSIC_VICTORY": - return i18next.t("achv:CLASSIC_VICTORY.description"); + return i18next.t(`${genderPrefix}achv:CLASSIC_VICTORY.description` as ParseKeys); + case "MONO_GEN_ONE": + return i18next.t(`${genderPrefix}achv:MONO_GEN_ONE.description` as ParseKeys); + case "MONO_GEN_TWO": + return i18next.t(`${genderPrefix}achv:MONO_GEN_TWO.description` as ParseKeys); + case "MONO_GEN_THREE": + return i18next.t(`${genderPrefix}achv:MONO_GEN_THREE.description` as ParseKeys); + case "MONO_GEN_FOUR": + return i18next.t(`${genderPrefix}achv:MONO_GEN_FOUR.description` as ParseKeys); + case "MONO_GEN_FIVE": + return i18next.t(`${genderPrefix}achv:MONO_GEN_FIVE.description` as ParseKeys); + case "MONO_GEN_SIX": + return i18next.t(`${genderPrefix}achv:MONO_GEN_SIX.description` as ParseKeys); + case "MONO_GEN_SEVEN": + return i18next.t(`${genderPrefix}achv:MONO_GEN_SEVEN.description` as ParseKeys); + case "MONO_GEN_EIGHT": + return i18next.t(`${genderPrefix}achv:MONO_GEN_EIGHT.description` as ParseKeys); + case "MONO_GEN_NINE": + return i18next.t(`${genderPrefix}achv:MONO_GEN_NINE.description` as ParseKeys); + case "MONO_NORMAL": + case "MONO_FIGHTING": + case "MONO_FLYING": + case "MONO_POISON": + case "MONO_GROUND": + case "MONO_ROCK": + case "MONO_BUG": + case "MONO_GHOST": + case "MONO_STEEL": + case "MONO_FIRE": + case "MONO_WATER": + case "MONO_GRASS": + case "MONO_ELECTRIC": + case "MONO_PSYCHIC": + case "MONO_ICE": + case "MONO_DRAGON": + case "MONO_DARK": + case "MONO_FAIRY": + return i18next.t(`${genderPrefix}achv:MonoType.description` as ParseKeys, {"type": i18next.t(`pokemonInfo:Type.${localizationKey.slice(5)}`)}); default: return ""; } @@ -241,26 +303,53 @@ export const achvs = { _50_RIBBONS: new RibbonAchv("50_RIBBONS","", 50, "ultra_ribbon", 50).setSecret(true), _75_RIBBONS: new RibbonAchv("75_RIBBONS","", 75, "rogue_ribbon", 75).setSecret(true), _100_RIBBONS: new RibbonAchv("100_RIBBONS","", 100, "master_ribbon", 100).setSecret(true), - TRANSFER_MAX_BATTLE_STAT: new Achv("TRANSFER_MAX_BATTLE_STAT","", "TRANSFER_MAX_BATTLE_STAT.description", "stick", 20), - MAX_FRIENDSHIP: new Achv("MAX_FRIENDSHIP", "", "MAX_FRIENDSHIP.description", "soothe_bell", 25), - MEGA_EVOLVE: new Achv("MEGA_EVOLVE", "", "MEGA_EVOLVE.description", "mega_bracelet", 50), - GIGANTAMAX: new Achv("GIGANTAMAX", "", "GIGANTAMAX.description", "dynamax_band", 50), - TERASTALLIZE: new Achv("TERASTALLIZE","", "TERASTALLIZE.description", "tera_orb", 25), - STELLAR_TERASTALLIZE: new Achv("STELLAR_TERASTALLIZE", "", "STELLAR_TERASTALLIZE.description", "stellar_tera_shard", 25).setSecret(true), - SPLICE: new Achv("SPLICE","", "SPLICE.description", "dna_splicers", 10), - MINI_BLACK_HOLE: new ModifierAchv("MINI_BLACK_HOLE","", "MINI_BLACK_HOLE.description", "mini_black_hole", 25, modifier => modifier instanceof TurnHeldItemTransferModifier).setSecret(), - CATCH_MYTHICAL: new Achv("CATCH_MYTHICAL","", "CATCH_MYTHICAL.description", "strange_ball", 50).setSecret(), - CATCH_SUB_LEGENDARY: new Achv("CATCH_SUB_LEGENDARY","", "CATCH_SUB_LEGENDARY.description", "rb", 75).setSecret(), - CATCH_LEGENDARY: new Achv("CATCH_LEGENDARY", "", "CATCH_LEGENDARY.description", "mb", 100).setSecret(), - SEE_SHINY: new Achv("SEE_SHINY", "", "SEE_SHINY.description", "pb_gold", 75), - SHINY_PARTY: new Achv("SHINY_PARTY", "", "SHINY_PARTY.description", "shiny_charm", 100).setSecret(true), - HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description", "pair_of_tickets", 75).setSecret(), - HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description", "mystic_ticket", 100).setSecret(), - HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description", "mystic_ticket", 125).setSecret(), - HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description", "golden_mystic_ticket", 100).setSecret(), - HIDDEN_ABILITY: new Achv("HIDDEN_ABILITY","", "HIDDEN_ABILITY.description", "ability_charm", 75), - PERFECT_IVS: new Achv("PERFECT_IVS","", "PERFECT_IVS.description", "blunder_policy", 100), - CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY","", "CLASSIC_VICTORY.description", "relic_crown", 150), + TRANSFER_MAX_BATTLE_STAT: new Achv("TRANSFER_MAX_BATTLE_STAT","", "TRANSFER_MAX_BATTLE_STAT.description","stick", 20), + MAX_FRIENDSHIP: new Achv("MAX_FRIENDSHIP", "", "MAX_FRIENDSHIP.description","soothe_bell", 25), + MEGA_EVOLVE: new Achv("MEGA_EVOLVE", "", "MEGA_EVOLVE.description","mega_bracelet", 50), + GIGANTAMAX: new Achv("GIGANTAMAX", "", "GIGANTAMAX.description","dynamax_band", 50), + TERASTALLIZE: new Achv("TERASTALLIZE","", "TERASTALLIZE.description","tera_orb", 25), + STELLAR_TERASTALLIZE: new Achv("STELLAR_TERASTALLIZE", "", "STELLAR_TERASTALLIZE.description","stellar_tera_shard", 25).setSecret(true), + SPLICE: new Achv("SPLICE","", "SPLICE.description","dna_splicers", 10), + MINI_BLACK_HOLE: new ModifierAchv("MINI_BLACK_HOLE","", "MINI_BLACK_HOLE.description","mini_black_hole", 25, modifier => modifier instanceof TurnHeldItemTransferModifier).setSecret(), + CATCH_MYTHICAL: new Achv("CATCH_MYTHICAL","", "CATCH_MYTHICAL.description","strange_ball", 50).setSecret(), + CATCH_SUB_LEGENDARY: new Achv("CATCH_SUB_LEGENDARY","", "CATCH_SUB_LEGENDARY.description","rb", 75).setSecret(), + CATCH_LEGENDARY: new Achv("CATCH_LEGENDARY", "", "CATCH_LEGENDARY.description","mb", 100).setSecret(), + SEE_SHINY: new Achv("SEE_SHINY", "", "SEE_SHINY.description","pb_gold", 75), + SHINY_PARTY: new Achv("SHINY_PARTY", "", "SHINY_PARTY.description","shiny_charm", 100).setSecret(true), + HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description","pair_of_tickets", 75).setSecret(), + HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description","mystic_ticket", 100).setSecret(), + HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description","mystic_ticket", 125).setSecret(), + HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description","golden_mystic_ticket", 100).setSecret(), + HIDDEN_ABILITY: new Achv("HIDDEN_ABILITY","", "HIDDEN_ABILITY.description","ability_charm", 75), + PERFECT_IVS: new Achv("PERFECT_IVS","", "PERFECT_IVS.description","blunder_policy", 100), + CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY","", "CLASSIC_VICTORY.description","relic_crown", 150), + MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE","", "MONO_GEN_ONE.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 1), + MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO","", "MONO_GEN_TWO.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 2), + MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE","", "MONO_GEN_THREE.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 3), + MONO_GEN_FOUR_VICTORY: new ChallengeAchv("MONO_GEN_FOUR","", "MONO_GEN_FOUR.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 4), + MONO_GEN_FIVE_VICTORY: new ChallengeAchv("MONO_GEN_FIVE","", "MONO_GEN_FIVE.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 5), + MONO_GEN_SIX_VICTORY: new ChallengeAchv("MONO_GEN_SIX","", "MONO_GEN_SIX.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 6), + MONO_GEN_SEVEN_VICTORY: new ChallengeAchv("MONO_GEN_SEVEN","", "MONO_GEN_SEVEN.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 7), + MONO_GEN_EIGHT_VICTORY: new ChallengeAchv("MONO_GEN_EIGHT","", "MONO_GEN_EIGHT.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 8), + MONO_GEN_NINE_VICTORY: new ChallengeAchv("MONO_GEN_NINE","", "MONO_GEN_NINE.description", "mystic_ticket", 100, c => c instanceof SingleGenerationChallenge && c.value === 9), + MONO_NORMAL: new ChallengeAchv("MONO_NORMAL","", "MONO_NORMAL.description", "silk_scarf", 100, c => c instanceof SingleTypeChallenge && c.value === 1), + MONO_FIGHTING: new ChallengeAchv("MONO_FIGHTING","", "MONO_FIGHTING.description", "black_belt", 100, c => c instanceof SingleTypeChallenge && c.value === 2), + MONO_FLYING: new ChallengeAchv("MONO_FLYING","", "MONO_FLYING.description", "sharp_beak", 100, c => c instanceof SingleTypeChallenge && c.value === 3), + MONO_POISON: new ChallengeAchv("MONO_POISON","", "MONO_POISON.description", "poison_barb", 100, c => c instanceof SingleTypeChallenge && c.value === 4), + MONO_GROUND: new ChallengeAchv("MONO_GROUND","", "MONO_GROUND.description", "soft_sand", 100, c => c instanceof SingleTypeChallenge && c.value === 5), + MONO_ROCK: new ChallengeAchv("MONO_ROCK","", "MONO_ROCK.description", "hard_stone", 100, c => c instanceof SingleTypeChallenge && c.value === 6), + MONO_BUG: new ChallengeAchv("MONO_BUG","", "MONO_BUG.description", "silver_powder", 100, c => c instanceof SingleTypeChallenge && c.value === 7), + MONO_GHOST: new ChallengeAchv("MONO_GHOST","", "MONO_GHOST.description", "spell_tag", 100, c => c instanceof SingleTypeChallenge && c.value === 8), + MONO_STEEL: new ChallengeAchv("MONO_STEEL","", "MONO_STEEL.description", "metal_coat", 100, c => c instanceof SingleTypeChallenge && c.value === 9), + MONO_FIRE: new ChallengeAchv("MONO_FIRE","", "MONO_FIRE.description", "charcoal", 100, c => c instanceof SingleTypeChallenge && c.value === 10), + MONO_WATER: new ChallengeAchv("MONO_WATER","", "MONO_WATER.description", "mystic_water", 100, c => c instanceof SingleTypeChallenge && c.value === 11), + MONO_GRASS: new ChallengeAchv("MONO_GRASS","", "MONO_GRASS.description", "miracle_seed", 100, c => c instanceof SingleTypeChallenge && c.value === 12), + MONO_ELECTRIC: new ChallengeAchv("MONO_ELECTRIC","", "MONO_ELECTRIC.description", "magnet", 100, c => c instanceof SingleTypeChallenge && c.value === 13), + MONO_PSYCHIC: new ChallengeAchv("MONO_PSYCHIC","", "MONO_PSYCHIC.description", "twisted_spoon", 100, c => c instanceof SingleTypeChallenge && c.value === 14), + MONO_ICE: new ChallengeAchv("MONO_ICE","", "MONO_ICE.description", "never_melt_ice", 100, c => c instanceof SingleTypeChallenge && c.value === 15), + MONO_DRAGON: new ChallengeAchv("MONO_DRAGON","", "MONO_DRAGON.description", "dragon_fang", 100, c => c instanceof SingleTypeChallenge && c.value === 16), + MONO_DARK: new ChallengeAchv("MONO_DARK","", "MONO_DARK.description", "black_glasses", 100, c => c instanceof SingleTypeChallenge && c.value === 17), + MONO_FAIRY: new ChallengeAchv("MONO_FAIRY","", "MONO_FAIRY.description", "fairy_feather", 100, c => c instanceof SingleTypeChallenge && c.value === 18), }; export function initAchievements() { diff --git a/src/system/challenge-data.ts b/src/system/challenge-data.ts new file mode 100644 index 00000000000..69df11dd395 --- /dev/null +++ b/src/system/challenge-data.ts @@ -0,0 +1,17 @@ +import { Challenge, copyChallenge } from "#app/data/challenge.js"; + +export default class ChallengeData { + public id: integer; + public value: integer; + public severity: integer; + + constructor(source: Challenge | any) { + this.id = source.id; + this.value = source.value; + this.severity = source.severity; + } + + toChallenge(): Challenge { + return copyChallenge(this); + } +} diff --git a/src/system/game-data.ts b/src/system/game-data.ts index c5e2cd6eb91..e9b67da2525 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -9,7 +9,7 @@ import PokemonData from "./pokemon-data"; import PersistentModifierData from "./modifier-data"; import ArenaData from "./arena-data"; import { Unlockables } from "./unlockables"; -import { GameModes, gameModes } from "../game-mode"; +import { GameModes, getGameMode } from "../game-mode"; import { BattleType } from "../battle"; import TrainerData from "./trainer-data"; import { trainerConfigs } from "../data/trainer-config"; @@ -32,12 +32,13 @@ import { OutdatedPhase, ReloadSessionPhase } from "#app/phases"; import { Variant, variantData } from "#app/data/variant"; import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad"; import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard"; -import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js"; +import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/events/arena"; import { Device } from "#app/enums/devices.js"; import { EnemyAttackStatusEffectChanceModifier } from "../modifier/modifier"; import { StatusEffect } from "#app/data/status-effect.js"; import { PlayerGender } from "#app/data/enums/player-gender"; import { GameDataType } from "#app/data/enums/game-data-type"; +import ChallengeData from "./challenge-data"; const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary @@ -107,6 +108,7 @@ export interface SessionSaveData { trainer: TrainerData; gameVersion: string; timestamp: integer; + challenges: ChallengeData[]; } interface Unlocks { @@ -780,7 +782,8 @@ export class GameData { battleType: scene.currentBattle.battleType, trainer: scene.currentBattle.battleType === BattleType.TRAINER ? new TrainerData(scene.currentBattle.trainer) : null, gameVersion: scene.game.config.gameVersion, - timestamp: new Date().getTime() + timestamp: new Date().getTime(), + challenges: scene.gameMode.challenges.map(c => new ChallengeData(c)) } as SessionSaveData; } @@ -829,7 +832,10 @@ export class GameData { const initSessionFromData = async sessionData => { console.debug(sessionData); - scene.gameMode = gameModes[sessionData.gameMode || GameModes.CLASSIC]; + scene.gameMode = getGameMode(sessionData.gameMode || GameModes.CLASSIC); + if (sessionData.challenges) { + scene.gameMode.challenges = sessionData.challenges.map(c => c.toChallenge()); + } scene.setSeed(sessionData.seed || scene.game.config.seed[0]); scene.resetSeed(); @@ -1075,6 +1081,17 @@ export class GameData { return new ArenaData(v); } + if (k === "challenges") { + const ret: ChallengeData[] = []; + if (v === null) { + v = []; + } + for (const c of v) { + ret.push(new ChallengeData(c)); + } + return ret; + } + return v; }) as SessionSaveData; } diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index f79393dac5c..fb446e1e081 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -4,7 +4,7 @@ import BattleScene from "../../battle-scene"; import { hasTouchscreen } from "../../touch-controls"; import { updateWindowType } from "../../ui/ui-theme"; import { PlayerGender } from "#app/data/enums/player-gender"; -import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js"; +import { CandyUpgradeNotificationChangedEvent } from "../../events/battle-scene"; import { MoneyFormat } from "../../enums/money-format"; import SettingsUiHandler from "#app/ui/settings/settings-ui-handler"; import { EaseType } from "#app/ui/enums/ease-type.js"; @@ -64,9 +64,11 @@ export const SettingKeys = { Sprite_Set: "SPRITE_SET", Fusion_Palette_Swaps: "FUSION_PALETTE_SWAPS", Player_Gender: "PLAYER_GENDER", + Type_Hints: "TYPE_HINTS", Master_Volume: "MASTER_VOLUME", BGM_Volume: "BGM_VOLUME", - SE_Volume: "SE_VOLUME" + SE_Volume: "SE_VOLUME", + Music_Preference: "MUSIC_PREFERENCE" }; /** @@ -267,6 +269,13 @@ export const Setting: Array = [ default: 0, type: SettingType.DISPLAY }, + { + key: SettingKeys.Type_Hints, + label: "Type hints", + options: OFF_ON, + default: 0, + type: SettingType.DISPLAY + }, { key: SettingKeys.Master_Volume, label: "Master Volume", @@ -287,6 +296,14 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 10, type: SettingType.AUDIO + }, + { + key: SettingKeys.Music_Preference, + label: "Music Preference", + options: ["Consistent", "Mixed"], + default: 0, + type: SettingType.AUDIO, + requireReload: true } ]; @@ -335,6 +352,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): scene.seVolume = value ? parseInt(Setting[index].options[value]) * 0.01 : 0; scene.updateSoundVolume(); break; + case SettingKeys.Music_Preference: + scene.musicPreference = value; + break; case SettingKeys.Damage_Numbers: scene.damageNumbersMode = value; break; @@ -435,6 +455,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): case SettingKeys.Vibration: scene.enableVibration = Setting[index].options[value] !== "Disabled" && hasTouchscreen(); break; + case SettingKeys.Type_Hints: + scene.typeHints = Setting[index].options[value] === "On"; + break; case SettingKeys.Language: if (value) { if (scene.ui) { diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index f94e29ff039..d8e7d97edf6 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -1,4 +1,4 @@ -import { GameModes, gameModes } from "../game-mode"; +import { GameMode, GameModes } from "../game-mode"; export enum Unlockables { ENDLESS_MODE, @@ -9,10 +9,10 @@ export enum Unlockables { export function getUnlockableName(unlockable: Unlockables) { switch (unlockable) { case Unlockables.ENDLESS_MODE: - return `${gameModes[GameModes.ENDLESS].getName()} Mode`; + return `${GameMode.getModeName(GameModes.ENDLESS)} Mode`; case Unlockables.MINI_BLACK_HOLE: return "Mini Black Hole"; case Unlockables.SPLICED_ENDLESS_MODE: - return `${gameModes[GameModes.SPLICED_ENDLESS].getName()} Mode`; + return `${GameMode.getModeName(GameModes.SPLICED_ENDLESS)} Mode`; } } diff --git a/src/system/voucher.ts b/src/system/voucher.ts index c11410400b5..f5c6a5eeacf 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -2,6 +2,7 @@ import BattleScene from "../battle-scene"; import { TrainerType } from "../data/enums/trainer-type"; import i18next from "../plugins/i18n"; import { Achv, AchvTier, achvs, getAchievementDescription } from "./achv"; +import { PlayerGender } from "#app/data/enums/player-gender"; export enum VoucherType { REGULAR, @@ -27,7 +28,12 @@ export class Voucher { return !this.conditionFunc || this.conditionFunc(scene, args); } - getName(): string { + /** + * Get the name of the voucher + * @param playerGender - this is ignored here. It's only there to match the signature of the function in the Achv class + * @returns the name of the voucher + */ + getName(playerGender: PlayerGender): string { return getVoucherTypeName(this.voucherType); } @@ -83,42 +89,40 @@ export const vouchers: Vouchers = {}; const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ]; -{ - (function() { - import("../data/trainer-config").then(tc => { - const trainerConfigs = tc.trainerConfigs; +export function initVouchers() { + import("../data/trainer-config").then(tc => { + const trainerConfigs = tc.trainerConfigs; - for (const achv of voucherAchvs) { - const voucherType = achv.score >= 150 - ? VoucherType.GOLDEN - : achv.score >= 100 - ? VoucherType.PREMIUM - : achv.score >= 75 - ? VoucherType.PLUS - : VoucherType.REGULAR; - vouchers[achv.id] = new Voucher(voucherType, getAchievementDescription(achv.localizationKey)); - } + for (const achv of voucherAchvs) { + const voucherType = achv.score >= 150 + ? VoucherType.GOLDEN + : achv.score >= 100 + ? VoucherType.PREMIUM + : achv.score >= 75 + ? VoucherType.PLUS + : VoucherType.REGULAR; + vouchers[achv.id] = new Voucher(voucherType, getAchievementDescription(achv.localizationKey)); + } - const bossTrainerTypes = Object.keys(trainerConfigs) - .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL); + const bossTrainerTypes = Object.keys(trainerConfigs) + .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL); - for (const trainerType of bossTrainerTypes) { - const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 - ? VoucherType.PLUS - : VoucherType.PREMIUM; - const key = TrainerType[trainerType]; - const trainerName = trainerConfigs[trainerType].name; - const trainer = trainerConfigs[trainerType]; - const title = trainer.title ? ` (${trainer.title})` : ""; - vouchers[key] = new Voucher( - voucherType, - `${i18next.t("voucher:defeatTrainer", { trainerName })} ${title}`, - ); - } - const voucherKeys = Object.keys(vouchers); - for (const k of voucherKeys) { - vouchers[k].id = k; - } - }); - })(); + for (const trainerType of bossTrainerTypes) { + const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 + ? VoucherType.PLUS + : VoucherType.PREMIUM; + const key = TrainerType[trainerType]; + const trainerName = trainerConfigs[trainerType].name; + const trainer = trainerConfigs[trainerType]; + const title = trainer.title ? ` (${trainer.title})` : ""; + vouchers[key] = new Voucher( + voucherType, + `${i18next.t("voucher:defeatTrainer", { trainerName })} ${title}`, + ); + } + const voucherKeys = Object.keys(vouchers); + for (const k of voucherKeys) { + vouchers[k].id = k; + } + }); } diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts index b8a1d65088f..861bb784853 100644 --- a/src/test/abilities/intimidate.test.ts +++ b/src/test/abilities/intimidate.test.ts @@ -5,16 +5,15 @@ import * as overrides from "#app/overrides"; import {Abilities} from "#app/data/enums/abilities"; import {Species} from "#app/data/enums/species"; import { - CheckSwitchPhase, CommandPhase, MessagePhase, - PostSummonPhase, - ShinySparklePhase, - ShowAbilityPhase, - StatChangePhase, - SummonPhase, - ToggleDoublePositionPhase, TurnInitPhase + CommandPhase, DamagePhase, + EnemyCommandPhase, + TurnInitPhase, } from "#app/phases"; import {Mode} from "#app/ui/ui"; import {BattleStat} from "#app/data/battle-stat"; +import {Moves} from "#app/data/enums/moves"; +import {getMovePosition} from "#app/test/utils/gameManagerUtils"; +import {Command} from "#app/ui/command-ui-handler"; describe("Abilities - Intimidate", () => { @@ -34,50 +33,303 @@ describe("Abilities - Intimidate", () => { beforeEach(() => { game = new GameManager(phaserGame); vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); - vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.INTIMIDATE); + vi.spyOn(overrides, "OPP_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.INTIMIDATE); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); }); - it("INTIMIDATE", async() => { + it("single - wild with switch", async() => { await game.runToSummon([ Species.MIGHTYENA, - Species.MIGHTYENA, + Species.POOCHYENA, ]); - await game.phaseInterceptor.run(PostSummonPhase); - - - expect(game.scene.getParty()[0].summonData).not.toBeUndefined(); - let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; - expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); - await game.phaseInterceptor.run(ShowAbilityPhase); - await game.phaseInterceptor.run(StatChangePhase); - battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; - expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - - - await game.phaseInterceptor.run(SummonPhase); - await game.phaseInterceptor.run(ShinySparklePhase, () => game.isCurrentPhase(ToggleDoublePositionPhase)); - await game.phaseInterceptor.run(ToggleDoublePositionPhase); game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { game.setMode(Mode.MESSAGE); game.endPhase(); - }); - await game.phaseInterceptor.run(CheckSwitchPhase); - await game.phaseInterceptor.run(PostSummonPhase); - - + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + expect(game.scene.getParty()[0].species.speciesId).toBe(Species.MIGHTYENA); let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + await game.switchPokemon(1); + expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); + + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + }, 20000); + + it("single - boss should only trigger once then switch", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10); + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + await game.switchPokemon(1); + expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); + + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + }, 20000); + + it("single - trainer should only trigger once with switch", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + await game.switchPokemon(1); + expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); + + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + }, 200000); + + it("double - trainer should only trigger once per pokemon", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(false); + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; + expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon2 = game.scene.getParty()[1].summonData.battleStats; + expect(battleStatsPokemon2[BattleStat.ATK]).toBe(-2); + }, 20000); + + it("double - wild: should only trigger once per pokemon", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(false); + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; + expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon2 = game.scene.getParty()[1].summonData.battleStats; + expect(battleStatsPokemon2[BattleStat.ATK]).toBe(-2); + }, 20000); + + it("double - boss: should only trigger once per pokemon", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(false); + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10); + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to(CommandPhase, false); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; + expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + + const battleStatsPokemon2 = game.scene.getParty()[1].summonData.battleStats; + expect(battleStatsPokemon2[BattleStat.ATK]).toBe(-2); + }, 20000); + + it("single - wild next wave opp triger once, us: none", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(2); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.AERIAL_ACE]); + await game.startBattle([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase); + await game.killPokemon(game.scene.currentBattle.enemyParty[0]); + expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); + await game.toNextWave(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); - await game.phaseInterceptor.run(ShowAbilityPhase); - game.scene.moveAnimations = null; // Mandatory to avoid crash - await game.phaseInterceptor.run(StatChangePhase); + }, 20000); + + it("single - wild next turn - no retrigger on next turn", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(2); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]); + await game.startBattle([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + console.log("===to new turn==="); + await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + }, 20000); + + it("single - trainer should only trigger once and each time he switch", async() => { + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.VOLT_SWITCH,Moves.VOLT_SWITCH,Moves.VOLT_SWITCH,Moves.VOLT_SWITCH]); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + console.log("===to new turn==="); + await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); + + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + console.log("===to new turn==="); + await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-3); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); + }, 200000); + + it("single - trainer should only trigger once whatever turn we are", async() => { + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + console.log("===to new turn==="); + await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); - await game.phaseInterceptor.run(MessagePhase); - await game.phaseInterceptor.run(TurnInitPhase); - await game.phaseInterceptor.run(CommandPhase); - }, 20000); + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + console.log("===to new turn==="); + await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + }, 200000); }); diff --git a/src/test/abilities/intrepid_sword.test.ts b/src/test/abilities/intrepid_sword.test.ts index f2e8eeb12cb..3a830df6845 100644 --- a/src/test/abilities/intrepid_sword.test.ts +++ b/src/test/abilities/intrepid_sword.test.ts @@ -5,11 +5,7 @@ import * as overrides from "#app/overrides"; import {Abilities} from "#app/data/enums/abilities"; import {Species} from "#app/data/enums/species"; import { - MessagePhase, - PostSummonPhase, - ShowAbilityPhase, - StatChangePhase, - ToggleDoublePositionPhase + CommandPhase, } from "#app/phases"; import {BattleStat} from "#app/data/battle-stat"; @@ -40,26 +36,10 @@ describe("Abilities - Intrepid Sword", () => { await game.runToSummon([ Species.ZACIAN, ]); - await game.phaseInterceptor.runFrom(PostSummonPhase).to(PostSummonPhase); - expect(game.scene.getParty()[0].summonData).not.toBeUndefined(); - let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; - expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); - await game.phaseInterceptor.mustRun(ShowAbilityPhase).catch((error) => expect(error).toBe(ShowAbilityPhase)); - await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase)); - battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + await game.phaseInterceptor.to(CommandPhase, false); + const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(1); - }, 20000); - - it("INTREPID SWORD on opponent", async() => { - await game.runToSummon([ - Species.ZACIAN, - ]); - let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; - expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); - await game.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase); - await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase)); - await game.phaseInterceptor.whenAboutToRun(MessagePhase); - battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(1); }, 20000); }); diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts new file mode 100644 index 00000000000..76bc3231f8a --- /dev/null +++ b/src/test/abilities/zen_mode.test.ts @@ -0,0 +1,142 @@ +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 {Abilities} from "#app/data/enums/abilities"; +import {Species} from "#app/data/enums/species"; +import { + CommandPhase, + DamagePhase, + EnemyCommandPhase, + MessagePhase, + PostSummonPhase, + SwitchPhase, + SwitchSummonPhase, + TurnEndPhase, TurnInitPhase, + TurnStartPhase, +} from "#app/phases"; +import {Mode} from "#app/ui/ui"; +import {Stat} from "#app/data/pokemon-stat"; +import {Moves} from "#app/data/enums/moves"; +import {getMovePosition} from "#app/test/utils/gameManagerUtils"; +import {Command} from "#app/ui/command-ui-handler"; +import {QuietFormChangePhase} from "#app/form-change-phase"; + + +describe("Abilities - Zen mode", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + const moveToUse = Moves.SPLASH; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + }); + + it("ZEN MODE - not enough damage to change form", async() => { + const moveToUse = Moves.SPLASH; + await game.startBattle([ + Species.DARMANITAN, + ]); + game.scene.getParty()[0].stats[Stat.SPD] = 1; + game.scene.getParty()[0].stats[Stat.HP] = 100; + game.scene.getParty()[0].hp = 100; + expect(game.scene.getParty()[0].formIndex).toBe(0); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, moveToUse); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false); + // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); + const damagePhase = game.scene.getCurrentPhase() as DamagePhase; + damagePhase.updateAmount(40); + await game.phaseInterceptor.runFrom(DamagePhase).to(TurnEndPhase, false); + expect(game.scene.getParty()[0].hp).toBeLessThan(100); + expect(game.scene.getParty()[0].formIndex).toBe(0); + }, 20000); + + it("ZEN MODE - enough damage to change form", async() => { + const moveToUse = Moves.SPLASH; + await game.startBattle([ + Species.DARMANITAN, + ]); + game.scene.getParty()[0].stats[Stat.SPD] = 1; + game.scene.getParty()[0].stats[Stat.HP] = 1000; + game.scene.getParty()[0].hp = 100; + expect(game.scene.getParty()[0].formIndex).toBe(0); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, moveToUse); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(QuietFormChangePhase); + await game.phaseInterceptor.to(TurnInitPhase, false); + expect(game.scene.getParty()[0].hp).not.toBe(100); + expect(game.scene.getParty()[0].formIndex).not.toBe(0); + }, 20000); + + it("ZEN MODE - kill pokemon while on zen mode", async() => { + const moveToUse = Moves.SPLASH; + await game.startBattle([ + Species.DARMANITAN, + Species.CHARIZARD, + ]); + game.scene.getParty()[0].stats[Stat.SPD] = 1; + game.scene.getParty()[0].stats[Stat.HP] = 1000; + game.scene.getParty()[0].hp = 100; + expect(game.scene.getParty()[0].formIndex).toBe(0); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, moveToUse); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false); + // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); + const damagePhase = game.scene.getCurrentPhase() as DamagePhase; + damagePhase.updateAmount(80); + await game.phaseInterceptor.runFrom(DamagePhase).to(QuietFormChangePhase); + expect(game.scene.getParty()[0].hp).not.toBe(100); + expect(game.scene.getParty()[0].formIndex).not.toBe(0); + await game.killPokemon(game.scene.getParty()[0]); + expect(game.scene.getParty()[0].isFainted()).toBe(true); + await game.phaseInterceptor.run(MessagePhase); + await game.phaseInterceptor.run(EnemyCommandPhase); + await game.phaseInterceptor.run(TurnStartPhase); + game.onNextPrompt("SwitchPhase", Mode.PARTY, () => { + game.scene.unshiftPhase(new SwitchSummonPhase(game.scene, 0, 1, false, false)); + game.scene.ui.setMode(Mode.MESSAGE); + }); + game.onNextPrompt("SwitchPhase", Mode.MESSAGE, () => { + game.endPhase(); + }); + await game.phaseInterceptor.run(SwitchPhase); + await game.phaseInterceptor.to(PostSummonPhase); + expect(game.scene.getParty()[1].formIndex).toBe(1); + }, 20000); +}); diff --git a/src/test/battle/battle-order.test.ts b/src/test/battle/battle-order.test.ts index e481150fafe..7ace7dae224 100644 --- a/src/test/battle/battle-order.test.ts +++ b/src/test/battle/battle-order.test.ts @@ -5,7 +5,7 @@ import * as overrides from "#app/overrides"; import {Abilities} from "#app/data/enums/abilities"; import {Species} from "#app/data/enums/species"; import { - CommandPhase, EnemyCommandPhase, + CommandPhase, EnemyCommandPhase, SelectTargetPhase, TurnStartPhase } from "#app/phases"; import {Mode} from "#app/ui/ui"; @@ -55,7 +55,6 @@ describe("Battle order", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.whenAboutToRun(TurnStartPhase); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); expect(order[0]).toBe(2); @@ -77,7 +76,6 @@ describe("Battle order", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.whenAboutToRun(TurnStartPhase); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); expect(order[0]).toBe(0); @@ -118,9 +116,7 @@ describe("Battle order", () => { const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; handler.processInput(Button.ACTION); }); - await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase); - await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.whenAboutToRun(TurnStartPhase); + await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); expect(order.indexOf(0)).toBeGreaterThan(order.indexOf(2)); @@ -163,9 +159,7 @@ describe("Battle order", () => { const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; handler.processInput(Button.ACTION); }); - await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase); - await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.whenAboutToRun(TurnStartPhase); + await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); expect(order.indexOf(3)).toBeLessThan(order.indexOf(0)); @@ -207,9 +201,7 @@ describe("Battle order", () => { const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; handler.processInput(Button.ACTION); }); - await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase); - await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.whenAboutToRun(TurnStartPhase); + await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); expect(order.indexOf(1)).toBeLessThan(order.indexOf(0)); diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index 521b56a8db2..9077cf00076 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -1,40 +1,29 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; -import {generateStarter, getMovePosition, waitUntil,} from "#app/test/utils/gameManagerUtils"; +import {generateStarter, getMovePosition,} from "#app/test/utils/gameManagerUtils"; import {Mode} from "#app/ui/ui"; import {GameModes} from "#app/game-mode"; import {Species} from "#app/data/enums/species"; import * as overrides from "../../overrides"; import {Command} from "#app/ui/command-ui-handler"; import { - BattleEndPhase, - BerryPhase, - CommandPhase, - DamagePhase, - EggLapsePhase, + CommandPhase, DamagePhase, EncounterPhase, EnemyCommandPhase, - FaintPhase, LoginPhase, - MessagePhase, - MoveEffectPhase, - MoveEndPhase, - MovePhase, - PostSummonPhase, SelectGenderPhase, SelectModifierPhase, SelectStarterPhase, - StatChangePhase, + SummonPhase, TitlePhase, - TurnEndPhase, - TurnInitPhase, - TurnStartPhase, - VictoryPhase, + TurnInitPhase, VictoryPhase, } from "#app/phases"; import {Moves} from "#app/data/enums/moves"; import GameManager from "#app/test/utils/gameManager"; import Phaser from "phaser"; import {allSpecies} from "#app/data/pokemon-species"; import {PlayerGender} from "#app/data/enums/player-gender"; +import { getGameMode } from "#app/game-mode.js"; +import {Abilities} from "#app/data/enums/abilities"; describe("Test Battle Phase", () => { let phaserGame: Phaser.Game; @@ -54,22 +43,6 @@ describe("Test Battle Phase", () => { game = new GameManager(phaserGame); }); - it("test phase interceptor with remove", async() => { - await game.phaseInterceptor.run(LoginPhase); - - await game.phaseInterceptor.run(LoginPhase, () => { - return game.phaseInterceptor.log.includes("LoginPhase"); - }); - - game.scene.gameData.gender = PlayerGender.MALE; - await game.phaseInterceptor.remove(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase)); - - await game.phaseInterceptor.run(TitlePhase); - await waitUntil(() => game.scene.ui?.getMode() === Mode.TITLE); - - expect(game.scene.ui?.getMode()).toBe(Mode.TITLE); - }, 100000); - it("test phase interceptor with prompt", async() => { await game.phaseInterceptor.run(LoginPhase); @@ -86,7 +59,7 @@ describe("Test Battle Phase", () => { expect(game.scene.ui?.getMode()).toBe(Mode.TITLE); expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); - }, 100000); + }, 20000); it("test phase interceptor with prompt with preparation for a future prompt", async() => { await game.phaseInterceptor.run(LoginPhase); @@ -108,13 +81,13 @@ describe("Test Battle Phase", () => { expect(game.scene.ui?.getMode()).toBe(Mode.TITLE); expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); - }, 100000); + }, 20000); it("newGame one-liner", async() => { await game.startBattle(); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); - }, 100000); + }, 20000); it("do attack wave 3 - single battle - regular - OHKO", async() => { vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); @@ -122,6 +95,8 @@ describe("Test Battle Phase", () => { vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); await game.startBattle(); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -131,28 +106,8 @@ describe("Test Battle Phase", () => { const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.run(TurnStartPhase); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.run(MessagePhase); - await game.phaseInterceptor.run(MoveEffectPhase); - await game.phaseInterceptor.run(DamagePhase); - await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(FaintPhase)); - await game.phaseInterceptor.run(FaintPhase); - await game.phaseInterceptor.run(MessagePhase); - - await game.phaseInterceptor.run(VictoryPhase); - await game.phaseInterceptor.run(MoveEndPhase); - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.run(BerryPhase); - await game.phaseInterceptor.run(TurnEndPhase); - await game.phaseInterceptor.run(BattleEndPhase); - await game.phaseInterceptor.run(EggLapsePhase); - await game.phaseInterceptor.run(SelectModifierPhase); - expect(game.scene.ui?.getMode()).toBe(Mode.MODIFIER_SELECT); - expect(game.scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name); - }, 100000); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase, false); + }, 20000); it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async() => { vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); @@ -160,7 +115,8 @@ describe("Test Battle Phase", () => { vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(5); vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]); - vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP]); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]); vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); await game.startBattle(); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -170,35 +126,8 @@ describe("Test Battle Phase", () => { const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await game.phaseInterceptor.run(EnemyCommandPhase); - await game.phaseInterceptor.run(TurnStartPhase); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.run(MessagePhase); - await game.phaseInterceptor.run(MoveEffectPhase); - await game.phaseInterceptor.run(DamagePhase); - await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase)); - await game.phaseInterceptor.run(MoveEndPhase); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEffectPhase)); - await game.phaseInterceptor.run(MoveEffectPhase); - game.scene.moveAnimations = null; // Mandatory to avoid the crash - await game.phaseInterceptor.run(StatChangePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase) || game.isCurrentPhase(DamagePhase)); - await game.phaseInterceptor.run(DamagePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase)); - await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase)); - await game.phaseInterceptor.run(MoveEndPhase); - - await game.phaseInterceptor.run(BerryPhase); - await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(TurnEndPhase)); - await game.phaseInterceptor.run(TurnEndPhase); - - await game.phaseInterceptor.run(TurnInitPhase); - await game.phaseInterceptor.run(CommandPhase); - await waitUntil(() => game.scene.ui?.getMode() === Mode.COMMAND); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); - }, 100000); + await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase, false); + }, 20000); it("load 100% data file", async() => { await game.importData("src/test/utils/saves/everything.prsv"); @@ -207,7 +136,7 @@ describe("Test Battle Phase", () => { return species.caughtAttr !== 0n; }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); - }, 50000); + }, 20000); it("start battle with selected team", async() => { await game.startBattle([ @@ -218,25 +147,7 @@ describe("Test Battle Phase", () => { expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CHARIZARD); expect(game.scene.getParty()[1].species.speciesId).toBe(Species.CHANSEY); expect(game.scene.getParty()[2].species.speciesId).toBe(Species.MEW); - }, 50000); - - it("assert next phase", async() => { - await game.phaseInterceptor.run(LoginPhase); - game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { - game.scene.gameData.gender = PlayerGender.MALE; - game.endPhase(); - }, () => game.isCurrentPhase(TitlePhase)); - await game.phaseInterceptor.mustRun(SelectGenderPhase).catch((error) => expect(error).toBe(SelectGenderPhase)); - await game.phaseInterceptor.mustRun(TitlePhase).catch((error) => expect(error).toBe(TitlePhase)); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { - const starters = generateStarter(game.scene); - const selectStarterPhase = new SelectStarterPhase(game.scene, GameModes.CLASSIC); - game.scene.pushPhase(new EncounterPhase(game.scene, false)); - selectStarterPhase.initBattle(starters); - }); - await game.phaseInterceptor.mustRun(EncounterPhase).catch((error) => expect(error).toBe(EncounterPhase)); - await game.phaseInterceptor.mustRun(PostSummonPhase).catch((error) => expect(error).toBe(PostSummonPhase)); - }, 50000); + }, 20000); it("test remove random battle seed int", async() => { for (let i=0; i<10; i++) { @@ -244,5 +155,173 @@ describe("Test Battle Phase", () => { expect(rand).toBe(14); } }); + + it("wrong phase", async() => { + await game.phaseInterceptor.run(LoginPhase); + await game.phaseInterceptor.run(LoginPhase).catch((e) => { + expect(e).toBe("Wrong phase: this is SelectGenderPhase and not LoginPhase"); + }); + }, 20000); + + it("wrong phase but skip", async() => { + await game.phaseInterceptor.run(LoginPhase); + await game.phaseInterceptor.run(LoginPhase, () => game.isCurrentPhase(SelectGenderPhase)); + }, 20000); + + it("good run", async() => { + await game.phaseInterceptor.run(LoginPhase); + game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + game.scene.gameData.gender = PlayerGender.MALE; + game.endPhase(); + }, () => game.isCurrentPhase(TitlePhase)); + await game.phaseInterceptor.run(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase)); + await game.phaseInterceptor.run(TitlePhase); + }, 20000); + + it("good run from select gender to title", async() => { + await game.phaseInterceptor.run(LoginPhase); + game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + game.scene.gameData.gender = PlayerGender.MALE; + game.endPhase(); + }, () => game.isCurrentPhase(TitlePhase)); + await game.phaseInterceptor.runFrom(SelectGenderPhase).to(TitlePhase); + }, 20000); + + it("good run to SummonPhase phase", async() => { + await game.phaseInterceptor.run(LoginPhase); + game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + game.scene.gameData.gender = PlayerGender.MALE; + game.endPhase(); + }, () => game.isCurrentPhase(TitlePhase)); + game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.scene.gameMode = getGameMode(GameModes.CLASSIC); + const starters = generateStarter(game.scene); + const selectStarterPhase = new SelectStarterPhase(game.scene); + game.scene.pushPhase(new EncounterPhase(game.scene, false)); + selectStarterPhase.initBattle(starters); + }); + await game.phaseInterceptor.runFrom(SelectGenderPhase).to(SummonPhase); + }, 20000); + + it("2vs1", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("1vs1", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + await game.startBattle([ + Species.BLASTOISE, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("2vs2", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("4vs2", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + Species.DARKRAI, + Species.GABITE, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("kill opponent pokemon", async() => { + const moveToUse = Moves.SPLASH; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + await game.startBattle([ + Species.DARMANITAN, + Species.CHARIZARD, + ]); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const movePosition = getMovePosition(game.scene, 0, moveToUse); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + await game.phaseInterceptor.to(DamagePhase, false); + await game.killPokemon(game.scene.currentBattle.enemyParty[0]); + expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); + await game.phaseInterceptor.to(VictoryPhase, false); + }, 200000); + + it("to next turn", async() => { + const moveToUse = Moves.SPLASH; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + await game.startBattle(); + const turn = game.scene.currentBattle.turn; + game.doAttack(0); + await game.toNextTurn(); + expect(game.scene.currentBattle.turn).toBeGreaterThan(turn); + }, 20000); + + it("to next wave with pokemon killed, single", async() => { + const moveToUse = Moves.SPLASH; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + await game.startBattle(); + const waveIndex = game.scene.currentBattle.waveIndex; + game.doAttack(0); + await game.doKillOpponents(); + await game.toNextWave(); + expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex); + }, 20000); }); diff --git a/src/test/battle/error-handling.test.ts b/src/test/battle/error-handling.test.ts new file mode 100644 index 00000000000..8b94c108bc1 --- /dev/null +++ b/src/test/battle/error-handling.test.ts @@ -0,0 +1,45 @@ +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; +import GameManager from "#app/test/utils/gameManager"; +import Phaser from "phaser"; +import * as overrides from "#app/overrides"; +import {Species} from "#app/data/enums/species"; +import {Moves} from "#app/data/enums/moves"; +import {Abilities} from "#app/data/enums/abilities"; + +describe("Test Battle Phase", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + const moveToUse = Moves.SPLASH; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + }); + + it.skip("to next turn", async() => { + await game.startBattle(); + const turn = game.scene.currentBattle.turn; + game.doAttack(0); + await game.toNextTurn(); + expect(game.scene.currentBattle.turn).toBeGreaterThan(turn); + }, 20000); +}); + diff --git a/src/test/battle/special_battle.test.ts b/src/test/battle/special_battle.test.ts new file mode 100644 index 00000000000..5a95d57afea --- /dev/null +++ b/src/test/battle/special_battle.test.ts @@ -0,0 +1,137 @@ +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; +import {Mode} from "#app/ui/ui"; +import {Species} from "#app/data/enums/species"; +import * as overrides from "../../overrides"; +import { + CommandPhase, +} from "#app/phases"; +import {Moves} from "#app/data/enums/moves"; +import GameManager from "#app/test/utils/gameManager"; +import Phaser from "phaser"; +import {Abilities} from "#app/data/enums/abilities"; + +describe("Test Battle Phase", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); + }); + + it("startBattle 2vs1 boss", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs2 boss", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs2 trainer", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs1 trainer", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs1 rival", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(8); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs2 rival", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(8); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 1vs1 trainer", async() => { + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.BLASTOISE, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 2vs2 trainer", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); + + it("startBattle 4vs2 trainer", async() => { + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([ + Species.BLASTOISE, + Species.CHARIZARD, + Species.DARKRAI, + Species.GABITE, + ]); + expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + }, 20000); +}); + diff --git a/src/test/inputs/inputs.test.ts b/src/test/inputs/inputs.test.ts index 4924ade0fc4..5acee145011 100644 --- a/src/test/inputs/inputs.test.ts +++ b/src/test/inputs/inputs.test.ts @@ -48,13 +48,8 @@ describe("Inputs", () => { }); it("Mobile - test touch holding for 1000ms - 4 input", async () => { - await game.inputsHandler.pressTouch("dpadUp", 1000); - expect(game.inputsHandler.log.length).toBe(4); - }); - - it("keyboard - test input holding for 1ms - 1 input", async() => { - await game.inputsHandler.pressKeyboardKey(cfg_keyboard_qwerty.deviceMapping.KEY_ARROW_UP, 1); - expect(game.inputsHandler.log.length).toBe(1); + await game.inputsHandler.pressTouch("dpadUp", 1050); + expect(game.inputsHandler.log.length).toBe(5); }); it("keyboard - test input holding for 200ms - 1 input", async() => { @@ -68,13 +63,8 @@ describe("Inputs", () => { }); it("keyboard - test input holding for 1000ms - 4 input", async() => { - await game.inputsHandler.pressKeyboardKey(cfg_keyboard_qwerty.deviceMapping.KEY_ARROW_UP, 1000); - expect(game.inputsHandler.log.length).toBe(4); - }); - - it("keyboard - test input holding for 2000ms - 8 input", async() => { - await game.inputsHandler.pressKeyboardKey(cfg_keyboard_qwerty.deviceMapping.KEY_ARROW_UP, 2000); - expect(game.inputsHandler.log.length).toBe(8); + await game.inputsHandler.pressKeyboardKey(cfg_keyboard_qwerty.deviceMapping.KEY_ARROW_UP, 1050); + expect(game.inputsHandler.log.length).toBe(5); }); it("gamepad - test input holding for 1ms - 1 input", async() => { @@ -93,13 +83,8 @@ describe("Inputs", () => { }); it("gamepad - test input holding for 1000ms - 4 input", async() => { - await game.inputsHandler.pressGamepadButton(pad_xbox360.deviceMapping.RC_S, 1000); - expect(game.inputsHandler.log.length).toBe(4); - }); - - it("gamepad - test input holding for 2000ms - 8 input", async() => { - await game.inputsHandler.pressGamepadButton(pad_xbox360.deviceMapping.RC_S, 2000); - expect(game.inputsHandler.log.length).toBe(8); + await game.inputsHandler.pressGamepadButton(pad_xbox360.deviceMapping.RC_S, 1050); + expect(game.inputsHandler.log.length).toBe(5); }); }); diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts new file mode 100644 index 00000000000..e3d5fd77a44 --- /dev/null +++ b/src/test/moves/spikes.test.ts @@ -0,0 +1,128 @@ +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 {Abilities} from "#app/data/enums/abilities"; +import {Species} from "#app/data/enums/species"; +import { + CommandPhase +} from "#app/phases"; +import {Moves} from "#app/data/enums/moves"; + + +describe("Moves - Spikes", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.scene.battleStyle = 1; + vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "OPP_PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION); + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPIKES,Moves.SPLASH, Moves.ROAR]); + }); + + it("single - wild - stay on field - no damage", async() => { + // player set spikes on the field and do splash for 3 turns + // opponent do splash for 4 turns + // nobody should take damage + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + await game.phaseInterceptor.to(CommandPhase, true); + const initialHp = game.scene.getParty()[0].hp; + expect(game.scene.getParty()[0].hp).toBe(initialHp); + game.doAttack(0); + await game.toNextTurn(); + game.doAttack(1); + await game.toNextTurn(); + game.doAttack(1); + await game.toNextTurn(); + game.doAttack(1); + await game.toNextTurn(); + game.doAttack(1); + await game.toNextTurn(); + expect(game.scene.getParty()[0].hp).toBe(initialHp); + console.log(game.textInterceptor.logs); + }, 20000); + + it("single - wild - take some damage", async() => { + // player set spikes on the field and switch back to back + // opponent do splash for 2 turns + // nobody should take damage + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + await game.phaseInterceptor.to(CommandPhase, false); + + const initialHp = game.scene.getParty()[0].hp; + await game.switchPokemon(1, false); + await game.phaseInterceptor.run(CommandPhase); + await game.phaseInterceptor.to(CommandPhase, false); + + await game.switchPokemon(1, false); + await game.phaseInterceptor.run(CommandPhase); + await game.phaseInterceptor.to(CommandPhase, false); + + expect(game.scene.getParty()[0].hp).toBe(initialHp); + }, 20000); + + it("trainer - wild - force switch opponent - should take damage", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + // player set spikes on the field and do splash for 3 turns + // opponent do splash for 4 turns + // nobody should take damage + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + await game.phaseInterceptor.to(CommandPhase, true); + const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; + game.doAttack(0); + await game.toNextTurn(); + game.doAttack(2); + await game.toNextTurn(); + expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); + }, 20000); + + it("trainer - wild - force switch by himself opponent - should take damage", async() => { + vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(5000); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(0); + // turn 1: player set spikes, opponent do splash + // turn 2: player do splash, opponent switch pokemon + // opponent pokemon should trigger spikes and lose HP + await game.runToSummon([ + Species.MIGHTYENA, + Species.POOCHYENA, + ]); + await game.phaseInterceptor.to(CommandPhase, true); + const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; + game.doAttack(0); + await game.toNextTurn(); + + game.forceOpponentToSwitch(); + game.doAttack(1); + await game.toNextTurn(); + expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); + }, 20000); + +}); diff --git a/src/test/phases/phases.test.ts b/src/test/phases/phases.test.ts index abb7ac2c975..009526ebe41 100644 --- a/src/test/phases/phases.test.ts +++ b/src/test/phases/phases.test.ts @@ -28,7 +28,8 @@ describe("Phases", () => { describe("LoginPhase", () => { it("should start the login phase", async () => { const loginPhase = new LoginPhase(scene); - loginPhase.start(); + scene.pushPhase(loginPhase); + await game.phaseInterceptor.run(LoginPhase); expect(scene.ui.getMode()).to.equal(Mode.MESSAGE); }); }); @@ -36,16 +37,18 @@ describe("Phases", () => { describe("TitlePhase", () => { it("should start the title phase", async () => { const titlePhase = new TitlePhase(scene); - titlePhase.start(); - expect(scene.ui.getMode()).to.equal(Mode.MESSAGE); + scene.pushPhase(titlePhase); + await game.phaseInterceptor.run(TitlePhase); + expect(scene.ui.getMode()).to.equal(Mode.TITLE); }); }); describe("UnavailablePhase", () => { it("should start the unavailable phase", async () => { const unavailablePhase = new UnavailablePhase(scene); - unavailablePhase.start(); + scene.pushPhase(unavailablePhase); + await game.phaseInterceptor.run(UnavailablePhase); expect(scene.ui.getMode()).to.equal(Mode.UNAVAILABLE); - }); + }, 20000); }); }); diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index 802542da259..9f323a2839c 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -15,9 +15,9 @@ import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; import {OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler"; import {Gender} from "#app/data/gender"; +import {allSpecies} from "#app/data/pokemon-species"; import {Nature} from "#app/data/nature"; import {Abilities} from "#app/data/enums/abilities"; -import {allSpecies} from "#app/data/pokemon-species"; describe("UI - Starter select", () => { @@ -51,12 +51,13 @@ describe("UI - Starter select", () => { currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -73,21 +74,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -99,19 +99,25 @@ describe("UI - Starter select", () => { it("Bulbasaur - shiny - variant 2 female hardy overgrow", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.CYCLE_GENDER); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -128,21 +134,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -153,15 +158,19 @@ describe("UI - Starter select", () => { expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.OVERGROW); }, 20000); - it("Bulbasaur - shiny - variant 2 female lonely cholorophyl", async() => { + it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); @@ -169,7 +178,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.CYCLE_NATURE); handler.processInput(Button.CYCLE_ABILITY); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -186,21 +197,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -211,21 +221,27 @@ describe("UI - Starter select", () => { expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.CHLOROPHYLL); }, 20000); - it("Bulbasaur - shiny - variant 2 female", async() => { + it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.CYCLE_GENDER); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -242,21 +258,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -268,19 +283,25 @@ describe("UI - Starter select", () => { it("Bulbasaur - not shiny", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.CYCLE_SHINY); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -297,21 +318,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -320,76 +340,28 @@ describe("UI - Starter select", () => { expect(game.scene.getParty()[0].variant).toBe(0); }, 20000); - it("Bulbasaur - shiny - variant 0", async() => { - await game.importData("src/test/utils/saves/everything.prsv"); - await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { - const currentPhase = game.scene.getCurrentPhase() as TitlePhase; - currentPhase.gameMode = GameModes.CLASSIC; - currentPhase.end(); - }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.RIGHT); - handler.processInput(Button.V); - handler.processInput(Button.ACTION); - }); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; - await new Promise((resolve) => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { - optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; - options = optionSelectUiHandler.getOptionsWithScroll(); - resolve(); - }); - }); - expect(options.some(option => option.label === "Add to Party")).toBe(true); - expect(options.some(option => option.label === "Toggle IVs")).toBe(true); - expect(options.some(option => option.label === "Manage Moves")).toBe(true); - expect(options.some(option => option.label === "Use Candies")).toBe(true); - expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); - - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - await game.phaseInterceptor.whenAboutToRun(EncounterPhase); - - expect(game.scene.getParty()[0].species.speciesId).toBe(Species.BULBASAUR); - expect(game.scene.getParty()[0].shiny).toBe(true); - expect(game.scene.getParty()[0].variant).toBe(0); - }, 20000); - it("Bulbasaur - shiny - variant 1", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.V); handler.processInput(Button.V); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -406,21 +378,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -429,15 +400,19 @@ describe("UI - Starter select", () => { expect(game.scene.getParty()[0].variant).toBe(1); }, 20000); - it("Bulbasaur - shiny - variant 1", async() => { + it("Bulbasaur - shiny - variant 2", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); @@ -445,7 +420,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.V); handler.processInput(Button.V); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -462,21 +439,20 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Cancel")).toBe(true); optionSelectUiHandler.processInput(Button.ACTION); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.SUBMIT); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { - const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; - saveSlotSelectUiHandler.processInput(Button.ACTION); - }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); + await new Promise((resolve) => { + game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.SUBMIT); + }); + game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; + handler.processInput(Button.ACTION); + }); + game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; + saveSlotSelectUiHandler.processInput(Button.ACTION); + resolve(); + }); }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); @@ -485,15 +461,19 @@ describe("UI - Starter select", () => { expect(game.scene.getParty()[0].variant).toBe(2); }, 20000); - it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column ", async() => { + it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); @@ -501,7 +481,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.RIGHT); handler.processInput(Button.RIGHT); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -526,6 +508,7 @@ describe("UI - Starter select", () => { resolve(); }); }); + expect(starterSelectUiHandler.starterGens[0]).toBe(0); expect(starterSelectUiHandler.starterCursors[0]).toBe(3); expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18); @@ -539,23 +522,23 @@ describe("UI - Starter select", () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CATERPIE); }, 20000); - it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1) ", async() => { + it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1)", async() => { await game.importData("src/test/utils/saves/everything.prsv"); + const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { + const species = game.scene.gameData.dexData[key]; + return species.caughtAttr !== 0n; + }).length; + expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase)); game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); @@ -564,7 +547,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.RIGHT); handler.processInput(Button.DOWN); handler.processInput(Button.ACTION); + game.phaseInterceptor.unlock(); }); + await game.phaseInterceptor.run(SelectStarterPhase); let options: OptionSelectItem[]; let optionSelectUiHandler: OptionSelectUiHandler; await new Promise((resolve) => { @@ -589,6 +574,7 @@ describe("UI - Starter select", () => { resolve(); }); }); + expect(starterSelectUiHandler.starterGens[0]).toBe(0); expect(starterSelectUiHandler.starterCursors[0]).toBe(12); expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18); @@ -602,10 +588,6 @@ describe("UI - Starter select", () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { - const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; - handler.processInput(Button.ACTION); - }); await game.phaseInterceptor.whenAboutToRun(EncounterPhase); expect(game.scene.getParty()[0].species.speciesId).toBe(Species.NIDORAN_M); }, 20000); diff --git a/src/test/utils/TextInterceptor.ts b/src/test/utils/TextInterceptor.ts index d3048f23f74..34b55aa30ac 100644 --- a/src/test/utils/TextInterceptor.ts +++ b/src/test/utils/TextInterceptor.ts @@ -1,16 +1,17 @@ export default class TextInterceptor { private scene; - private logs = []; + public logs = []; constructor(scene) { this.scene = scene; scene.messageWrapper = this; } showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer): void { + console.log(text); this.logs.push(text); } getLatestMessage(): string { - return this.logs[this.logs.length - 1]; + return this.logs.pop(); } } diff --git a/src/test/utils/errorInterceptor.ts b/src/test/utils/errorInterceptor.ts new file mode 100644 index 00000000000..7f06c47fd39 --- /dev/null +++ b/src/test/utils/errorInterceptor.ts @@ -0,0 +1,50 @@ +export default class ErrorInterceptor { + private static instance: ErrorInterceptor; + public running; + + constructor() { + this.running = []; + } + + public static getInstance(): ErrorInterceptor { + if (!ErrorInterceptor.instance) { + ErrorInterceptor.instance = new ErrorInterceptor(); + } + return ErrorInterceptor.instance; + } + + clear() { + this.running = []; + } + + add(obj) { + this.running.push(obj); + } + + remove(obj) { + const index = this.running.indexOf(obj); + if (index !== -1) { + this.running.splice(index, 1); + } + } +} + + +process.on("uncaughtException", (error) => { + console.log(error); + const toStop = ErrorInterceptor.getInstance().running; + for (const elm of toStop) { + elm.rejectAll(error); + } + global.testFailed = true; +}); + +// Global error handler for unhandled promise rejections +process.on("unhandledRejection", (reason, promise) => { + console.log(reason); + const toStop = ErrorInterceptor.getInstance().running; + for (const elm of toStop) { + elm.rejectAll(reason); + } + global.testFailed = true; +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index cc759fd1563..6035d382c24 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -2,30 +2,34 @@ import GameWrapper from "#app/test/utils/gameWrapper"; import {Mode} from "#app/ui/ui"; import {generateStarter, waitUntil} from "#app/test/utils/gameManagerUtils"; import { - CheckSwitchPhase, CommandPhase, EncounterPhase, - LoginPhase, - PostSummonPhase, + FaintPhase, + LoginPhase, NewBattlePhase, SelectGenderPhase, SelectStarterPhase, - SummonPhase, - TitlePhase, - ToggleDoublePositionPhase, + TitlePhase, TurnInitPhase, } from "#app/phases"; import BattleScene from "#app/battle-scene.js"; import PhaseInterceptor from "#app/test/utils/phaseInterceptor"; import TextInterceptor from "#app/test/utils/TextInterceptor"; -import {expect} from "vitest"; -import {GameModes} from "#app/game-mode"; +import {GameModes, getGameMode} from "#app/game-mode"; import fs from "fs"; -import { AES, enc } from "crypto-js"; +import {AES, enc} from "crypto-js"; import {updateUserInfo} from "#app/account"; import {Species} from "#app/data/enums/species"; import {PlayerGender} from "#app/data/enums/player-gender"; import {GameDataType} from "#app/data/enums/game-data-type"; import InputsHandler from "#app/test/utils/inputsHandler"; import {ExpNotification} from "#app/enums/exp-notification"; +import ErrorInterceptor from "#app/test/utils/errorInterceptor"; +import {EnemyPokemon, PlayerPokemon} from "#app/field/pokemon"; +import {MockClock} from "#app/test/utils/mocks/mockClock"; +import {Command} from "#app/ui/command-ui-handler"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; +import {Button} from "#app/enums/buttons"; +import PartyUiHandler, {PartyUiMode} from "#app/ui/party-ui-handler"; +import Trainer from "#app/field/trainer"; /** * Class to manage the game state and transitions between phases. @@ -43,6 +47,8 @@ export default class GameManager { * @param bypassLogin - Whether to bypass the login phase. */ constructor(phaserGame: Phaser.Game, bypassLogin: boolean = true) { + localStorage.clear(); + ErrorInterceptor.getInstance().clear(); BattleScene.prototype.randBattleSeedInt = (arg) => arg-1; this.gameWrapper = new GameWrapper(phaserGame, bypassLogin); this.scene = new BattleScene(); @@ -85,31 +91,31 @@ export default class GameManager { * @param callback - The callback to execute. * @param expireFn - Optional function to determine if the prompt has expired. */ - onNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn?: () => void) { - this.phaseInterceptor.addToNextPrompt(phaseTarget, mode, callback, expireFn); + onNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn?: () => void, awaitingActionInput: boolean = false) { + this.phaseInterceptor.addToNextPrompt(phaseTarget, mode, callback, expireFn, awaitingActionInput); } /** * Runs the game to the title phase. * @returns A promise that resolves when the title phase is reached. */ - runToTitle(): Promise { - return new Promise(async(resolve) => { - await this.phaseInterceptor.run(LoginPhase); - this.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { - this.scene.gameData.gender = PlayerGender.MALE; - this.endPhase(); - }, () => this.isCurrentPhase(TitlePhase)); - await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase)); - await this.phaseInterceptor.run(TitlePhase); - this.scene.gameSpeed = 5; - this.scene.moveAnimations = false; - this.scene.showLevelUpStats = false; - this.scene.expGainsSpeed = 3; - this.scene.expParty = ExpNotification.SKIP; - this.scene.hpBarSpeed = 3; - resolve(); - }); + async runToTitle(): Promise { + await this.phaseInterceptor.run(LoginPhase); + + this.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + this.scene.gameData.gender = PlayerGender.MALE; + this.endPhase(); + }, () => this.isCurrentPhase(TitlePhase)); + + await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase)); + await this.phaseInterceptor.run(TitlePhase); + + this.scene.gameSpeed = 5; + this.scene.moveAnimations = false; + this.scene.showLevelUpStats = false; + this.scene.expGainsSpeed = 3; + this.scene.expParty = ExpNotification.SKIP; + this.scene.hpBarSpeed = 3; } /** @@ -117,47 +123,99 @@ export default class GameManager { * @param species - Optional array of species to summon. * @returns A promise that resolves when the summon phase is reached. */ - runToSummon(species?: Species[]): Promise { - return new Promise(async(resolve) => { - await this.runToTitle(); - this.onNextPrompt("TitlePhase", Mode.TITLE, () => { - const starters = generateStarter(this.scene, species); - const selectStarterPhase = new SelectStarterPhase(this.scene, GameModes.CLASSIC); - this.scene.pushPhase(new EncounterPhase(this.scene, false)); - selectStarterPhase.initBattle(starters); - }); - await this.phaseInterceptor.run(EncounterPhase); - resolve(); + async runToSummon(species?: Species[]) { + await this.runToTitle(); + + this.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.scene.gameMode = getGameMode(GameModes.CLASSIC); + const starters = generateStarter(this.scene, species); + const selectStarterPhase = new SelectStarterPhase(this.scene); + this.scene.pushPhase(new EncounterPhase(this.scene, false)); + selectStarterPhase.initBattle(starters); }); + + await this.phaseInterceptor.run(EncounterPhase); } /** - * Starts a battle. + * Transitions to the start of a battle. * @param species - Optional array of species to start the battle with. * @returns A promise that resolves when the battle is started. */ - startBattle(species?: Species[]): Promise { - return new Promise(async(resolve) => { - await this.runToSummon(species); - await this.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase); - await this.phaseInterceptor.run(SummonPhase, () => this.isCurrentPhase(CheckSwitchPhase) || this.isCurrentPhase(PostSummonPhase)); - this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); - this.endPhase(); - }, () => this.isCurrentPhase(PostSummonPhase)); - this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); - this.endPhase(); - }, () => this.isCurrentPhase(PostSummonPhase)); - await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase)); - await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase)); - await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase); - await waitUntil(() => this.scene.ui?.getMode() === Mode.COMMAND); - console.log("==================[New Turn]=================="); - expect(this.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(this.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); - return resolve(); + async startBattle(species?: Species[]) { + await this.runToSummon(species); + + this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.setMode(Mode.MESSAGE); + this.endPhase(); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); + + this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.setMode(Mode.MESSAGE); + this.endPhase(); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); + + await this.phaseInterceptor.to(CommandPhase); + console.log("==================[New Turn]=================="); + } + + /** + * Emulate a player attack + * @param movePosition the index of the move in the pokemon's moveset array + */ + doAttack(movePosition: integer) { + this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + this.scene.ui.setMode(Mode.FIGHT, (this.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); }); + this.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + } + + /** Faint all opponents currently on the field */ + async doKillOpponents() { + await this.killPokemon(this.scene.currentBattle.enemyParty[0]); + if (this.scene.currentBattle.double) { + await this.killPokemon(this.scene.currentBattle.enemyParty[1]); + } + } + + /** Emulate selecting a modifier (item) */ + doSelectModifier() { + this.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler; + handler.processInput(Button.CANCEL); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase), true); + + this.onNextPrompt("SelectModifierPhase", Mode.CONFIRM, () => { + const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler; + handler.processInput(Button.ACTION); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase)); + } + + forceOpponentToSwitch() { + const originalMatchupScore = Trainer.prototype.getPartyMemberMatchupScores; + Trainer.prototype.getPartyMemberMatchupScores = () => { + Trainer.prototype.getPartyMemberMatchupScores = originalMatchupScore; + return [[1, 100], [1, 100]]; + }; + } + + /** Transition to the next upcoming {@linkcode CommandPhase} */ + async toNextTurn() { + await this.phaseInterceptor.to(CommandPhase); + } + + /** Emulate selecting a modifier (item) and transition to the next upcoming {@linkcode CommandPhase} */ + async toNextWave() { + this.doSelectModifier(); + + this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.setMode(Mode.MESSAGE); + this.endPhase(); + }, () => this.isCurrentPhase(TurnInitPhase)); + + await this.toNextTurn(); } /** @@ -220,4 +278,28 @@ export default class GameManager { } return updateUserInfo(); } + + async killPokemon(pokemon: PlayerPokemon | EnemyPokemon) { + (this.scene.time as MockClock).overrideDelay = 0.01; + return new Promise(async(resolve, reject) => { + pokemon.hp = 0; + this.scene.pushPhase(new FaintPhase(this.scene, pokemon.getBattlerIndex(), true)); + await this.phaseInterceptor.to(FaintPhase).catch((e) => reject(e)); + (this.scene.time as MockClock).overrideDelay = undefined; + resolve(); + }); + } + + async switchPokemon(pokemonIndex: number, toNext: boolean = true) { + this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + this.scene.ui.setMode(Mode.PARTY, PartyUiMode.SWITCH, (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(), null, PartyUiHandler.FilterNonFainted); + }); + this.onNextPrompt("CommandPhase", Mode.PARTY, () => { + (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, pokemonIndex, false); + }); + if (toNext) { + await this.phaseInterceptor.run(CommandPhase); + await this.phaseInterceptor.to(CommandPhase); + } + } } diff --git a/src/test/utils/gameManagerUtils.ts b/src/test/utils/gameManagerUtils.ts index 4a72006faa6..1b7bbdabaf0 100644 --- a/src/test/utils/gameManagerUtils.ts +++ b/src/test/utils/gameManagerUtils.ts @@ -3,7 +3,7 @@ import {getDailyRunStarters} from "#app/data/daily-run"; import {Gender} from "#app/data/gender"; import {Species} from "#app/data/enums/species"; import {Starter} from "#app/ui/starter-select-ui-handler"; -import {GameModes, gameModes} from "#app/game-mode"; +import {GameModes, getGameMode} from "#app/game-mode"; import {getPokemonSpecies, getPokemonSpeciesForm} from "#app/data/pokemon-species"; import {PlayerPokemon} from "#app/field/pokemon"; @@ -49,7 +49,7 @@ function getTestRunStarters(scene, seed, species) { return getDailyRunStarters(scene, seed); } const starters: Starter[] = []; - const startingLevel = gameModes[GameModes.CLASSIC].getStartingLevel(); + const startingLevel = getGameMode(GameModes.CLASSIC).getStartingLevel(); for (const specie of species) { const starterSpeciesForm = getPokemonSpeciesForm(specie, 0); diff --git a/src/test/utils/gameWrapper.ts b/src/test/utils/gameWrapper.ts index c9aed9865db..da54471a7e3 100644 --- a/src/test/utils/gameWrapper.ts +++ b/src/test/utils/gameWrapper.ts @@ -86,7 +86,6 @@ export default class GameWrapper { frames: {}, }); Pokemon.prototype.enableMask = () => null; - localStorage.clear(); } setScene(scene: BattleScene) { @@ -121,7 +120,7 @@ export default class GameWrapper { pause: () => null, setRate: () => null, add: () => this.scene.sound, - get: () => this.scene.sound, + get: () => ({...this.scene.sound, totalDuration: 0}), getAllPlaying: () => [], manager: { game: this.game, @@ -132,6 +131,13 @@ export default class GameWrapper { key: "", }; + this.scene.cameras = { + main: { + setPostPipeline: () => null, + removePostPipeline: () => null, + }, + } + this.scene.tweens = { add: (data) => { if (data.onComplete) { diff --git a/src/test/utils/inputsHandler.ts b/src/test/utils/inputsHandler.ts index fd961ed3ef6..043dcffbdb9 100644 --- a/src/test/utils/inputsHandler.ts +++ b/src/test/utils/inputsHandler.ts @@ -3,7 +3,7 @@ import Phaser from "phaser"; import {InputsController} from "#app/inputs-controller"; import pad_xbox360 from "#app/configs/inputs/pad_xbox360"; import {holdOn} from "#app/test/utils/gameManagerUtils"; -import {initTouchControls} from "#app/touch-controls"; +import TouchControl from "#app/touch-controls"; import { JSDOM } from "jsdom"; import fs from "fs"; @@ -54,10 +54,8 @@ export default class InputsHandler { } init(): void { - setInterval(() => { - this.inputController.update(); - }); - initTouchControls(this.inputController.events); + const touchControl = new TouchControl(this.scene); + touchControl.deactivatePressedKey(); //test purpose this.events = this.inputController.events; this.scene.input.gamepad.emit("connected", this.fakePad); this.listenInputs(); diff --git a/src/test/utils/mocks/mockClock.ts b/src/test/utils/mocks/mockClock.ts index 0d5ea68ed59..ba12dc002cc 100644 --- a/src/test/utils/mocks/mockClock.ts +++ b/src/test/utils/mocks/mockClock.ts @@ -2,8 +2,10 @@ import Clock = Phaser.Time.Clock; export class MockClock extends Clock { + public overrideDelay: number; constructor(scene) { super(scene); + this.overrideDelay = undefined; setInterval(() => { /* To simulate frame update @@ -14,4 +16,9 @@ export class MockClock extends Clock { this.update(this.systems.game.loop.time, 100); }, 100); } + + addEvent(config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig): Phaser.Time.TimerEvent { + const cfg = { ...config, delay: this.overrideDelay || config.delay}; + return super.addEvent(cfg); + } } diff --git a/src/test/utils/mocks/mocksContainer/mockSprite.ts b/src/test/utils/mocks/mocksContainer/mockSprite.ts index 30effe185ad..699dea31ad5 100644 --- a/src/test/utils/mocks/mocksContainer/mockSprite.ts +++ b/src/test/utils/mocks/mocksContainer/mockSprite.ts @@ -143,6 +143,7 @@ export default class MockSprite { play() { // return this.phaserSprite.play(); + return this; } setPipelineData(key, value) { diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts index f219a6d1bad..1dd440fde7c 100644 --- a/src/test/utils/mocks/mocksContainer/mockText.ts +++ b/src/test/utils/mocks/mocksContainer/mockText.ts @@ -7,9 +7,12 @@ export default class MockText { private scene; private textureManager; public list = []; + public style; + constructor(textureManager, x, y, content, styleOptions) { this.scene = textureManager.scene; this.textureManager = textureManager; + this.style = {}; // Phaser.GameObjects.TextStyle.prototype.setStyle = () => null; // Phaser.GameObjects.Text.prototype.updateText = () => null; // Phaser.Textures.TextureManager.prototype.addCanvas = () => {}; @@ -136,6 +139,15 @@ export default class MockText { // return this.phaserText.setX(x); } + /** + * Sets the position of this Game Object. + * @param x The x position of this Game Object. Default 0. + * @param y The y position of this Game Object. If not set it will use the `x` value. Default x. + * @param z The z position of this Game Object. Default 0. + * @param w The w position of this Game Object. Default 0. + */ + setPosition(x?: number, y?: number, z?: number, w?: number) { } + setText(text) { // Sets the text this Game Object will display. // return this.phaserText.setText(text); diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 2915f2e614b..9e7745c8a37 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -1,15 +1,43 @@ import { BattleEndPhase, BerryPhase, - CheckSwitchPhase, CommandPhase, DamagePhase, EggLapsePhase, - EncounterPhase, EnemyCommandPhase, FaintPhase, - LoginPhase, MessagePhase, MoveEffectPhase, MoveEndPhase, MovePhase, NewBattlePhase, NextEncounterPhase, + CheckSwitchPhase, + CommandPhase, + DamagePhase, + EggLapsePhase, + EncounterPhase, + EnemyCommandPhase, + FaintPhase, + LoginPhase, + MessagePhase, + MoveEffectPhase, + MoveEndPhase, + MovePhase, + NewBattlePhase, + NextEncounterPhase, PostSummonPhase, - SelectGenderPhase, SelectModifierPhase, - SelectStarterPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase, - TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, VictoryPhase + SelectGenderPhase, + SelectModifierPhase, + SelectStarterPhase, + SelectTargetPhase, + ShinySparklePhase, + ShowAbilityPhase, + StatChangePhase, + SummonPhase, + SwitchPhase, + SwitchSummonPhase, + TitlePhase, + ToggleDoublePositionPhase, + TurnEndPhase, + TurnInitPhase, + TurnStartPhase, + UnavailablePhase, + VictoryPhase } from "#app/phases"; -import {Mode} from "#app/ui/ui"; +import UI, {Mode} from "#app/ui/ui"; +import {Phase} from "#app/phase"; +import ErrorInterceptor from "#app/test/utils/errorInterceptor"; +import {QuietFormChangePhase} from "#app/form-change-phase"; export default class PhaseInterceptor { public scene; @@ -21,6 +49,9 @@ export default class PhaseInterceptor { private intervalRun; private prompts; private phaseFrom; + private inProgress; + private originalSetMode; + private originalSuperEnd; /** * List of phases with their corresponding start methods. @@ -56,6 +87,15 @@ export default class PhaseInterceptor { [MoveEndPhase, this.startPhase], [StatChangePhase, this.startPhase], [ShinySparklePhase, this.startPhase], + [SelectTargetPhase, this.startPhase], + [UnavailablePhase, this.startPhase], + [QuietFormChangePhase, this.startPhase], + [SwitchPhase, this.startPhase], + [SwitchSummonPhase, this.startPhase], + ]; + + private endBySetMode = [ + TitlePhase, SelectGenderPhase, CommandPhase ]; /** @@ -67,8 +107,17 @@ export default class PhaseInterceptor { this.log = []; this.onHold = []; this.prompts = []; + this.startPromptHandler(); this.initPhases(); - this.startPromptHander(); + } + + rejectAll(error) { + if (this.inProgress) { + clearInterval(this.promptInterval); + clearInterval(this.interval); + clearInterval(this.intervalRun); + this.inProgress.onError(error); + } } /** @@ -86,20 +135,33 @@ export default class PhaseInterceptor { * @param phaseTo - The phase to transition to. * @returns A promise that resolves when the transition is complete. */ - async to(phaseTo): Promise { - return new Promise(async (resolve) => { - await this.run(this.phaseFrom); - this.phaseFrom = null; + async to(phaseTo, runTarget: boolean = true): Promise { + return new Promise(async (resolve, reject) => { + ErrorInterceptor.getInstance().add(this); + if (this.phaseFrom) { + await this.run(this.phaseFrom).catch((e) => reject(e)); + this.phaseFrom = null; + } const targetName = typeof phaseTo === "string" ? phaseTo : phaseTo.name; - this.intervalRun = setInterval(async () => { + this.intervalRun = setInterval(async() => { const currentPhase = this.onHold?.length && this.onHold[0]; - if (currentPhase && currentPhase.name !== targetName) { - await this.run(currentPhase.name); - } else if (currentPhase.name === targetName) { - await this.run(currentPhase.name); + if (currentPhase && currentPhase.name === targetName) { clearInterval(this.intervalRun); + if (!runTarget) { + return resolve(); + } + await this.run(currentPhase).catch((e) => { + clearInterval(this.intervalRun); + return reject(e); + }); return resolve(); } + if (currentPhase && currentPhase.name !== targetName) { + await this.run(currentPhase).catch((e) => { + clearInterval(this.intervalRun); + return reject(e); + }); + } }); }); } @@ -111,92 +173,53 @@ export default class PhaseInterceptor { * @returns A promise that resolves when the phase is run. */ run(phaseTarget, skipFn?): Promise { - this.scene.moveAnimations = null; // Mandatory to avoid crash - return new Promise(async (resolve) => { - this.waitUntil(phaseTarget, skipFn).then(() => { - const currentPhase = this.onHold.shift(); - currentPhase.call(); - resolve(); - }).catch(() => { - resolve(); - }); - }); - } - - /** - * Method to ensure a phase is run, to throw error on test if not. - * @param phaseTarget - The phase to run. - * @returns A promise that resolves when the phase is run. - */ - mustRun(phaseTarget): Promise { const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name; this.scene.moveAnimations = null; // Mandatory to avoid crash return new Promise(async (resolve, reject) => { + ErrorInterceptor.getInstance().add(this); const interval = setInterval(async () => { - const currentPhase = this.onHold?.length && this.onHold[0]; - if (currentPhase && currentPhase.name !== targetName) { - reject(currentPhase); - } else if (currentPhase && currentPhase.name === targetName) { + const currentPhase = this.onHold.shift(); + if (currentPhase) { + if (currentPhase.name !== targetName) { + clearInterval(interval); + const skip = skipFn && skipFn(currentPhase.name); + if (skip) { + this.onHold.unshift(currentPhase); + ErrorInterceptor.getInstance().remove(this); + return resolve(); + } + clearInterval(interval); + return reject(`Wrong phase: this is ${currentPhase.name} and not ${targetName}`); + } clearInterval(interval); - await this.run(phaseTarget); - resolve(); + this.inProgress = { + name: currentPhase.name, + callback: () => { + ErrorInterceptor.getInstance().remove(this); + resolve(); + }, + onError: (error) => reject(error), + }; + currentPhase.call(); } }); }); } - /** - * Method to execute actions when about to run a phase. Does not run the phase, stop right before. - * @param phaseTarget - The phase to run. - * @param skipFn - Optional skip function. - * @returns A promise that resolves when the phase is about to run. - */ whenAboutToRun(phaseTarget, skipFn?): Promise { - return new Promise(async (resolve) => { - this.waitUntil(phaseTarget, skipFn).then(() => { - resolve(); - }).catch(() => { - resolve(); - }); - }); - } - - /** - * Method to remove a phase from the list. - * @param phaseTarget - The phase to remove. - * @param skipFn - Optional skip function. - * @returns A promise that resolves when the phase is removed. - */ - remove(phaseTarget, skipFn?): Promise { - return new Promise(async (resolve) => { - this.waitUntil(phaseTarget, skipFn).then(() => { - this.onHold.shift(); - this.scene.getCurrentPhase().end(); - resolve(); - }).catch(() => { - resolve(); - }); - }); - } - - /** - * Method to wait until a specific phase is reached. - * @param phaseTarget - The phase to wait for. - * @param skipFn - Optional skip function. - * @returns A promise that resolves when the phase is reached. - */ - waitUntil(phaseTarget, skipFn?): Promise { const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name; - return new Promise((resolve, reject) => { - this.interval = setInterval(() => { - const currentPhase = this.onHold?.length && this.onHold[0] && this.onHold[0].name; - // if the currentPhase here is not filled, it means it's a phase we haven't added to the list - if (currentPhase === targetName) { - clearInterval(this.interval); - return resolve(); - } else if (skipFn && skipFn()) { - clearInterval(this.interval); - return reject("Skipped phase"); + this.scene.moveAnimations = null; // Mandatory to avoid crash + return new Promise(async (resolve, reject) => { + ErrorInterceptor.getInstance().add(this); + const interval = setInterval(async () => { + const currentPhase = this.onHold.shift(); + if (currentPhase) { + if (currentPhase.name !== targetName) { + this.onHold.unshift(currentPhase); + } else { + clearInterval(interval); + resolve(); + } } }); }); @@ -206,10 +229,17 @@ export default class PhaseInterceptor { * Method to initialize phases and their corresponding methods. */ initPhases() { - for (const [phase, method] of this.PHASES) { + this.originalSetMode = UI.prototype.setMode; + this.originalSuperEnd = Phase.prototype.end; + UI.prototype.setMode = (mode, ...args) => this.setMode.call(this, mode, ...args); + Phase.prototype.end = () => this.superEndPhase.call(this); + for (const [phase, methodStart] of this.PHASES) { const originalStart = phase.prototype.start; - this.phases[phase.name] = originalStart; - phase.prototype.start = () => method.call(this, phase); + this.phases[phase.name] = { + start: originalStart, + endBySetMode: this.endBySetMode.some((elm) => elm.name === phase.name), + }; + phase.prototype.start = () => methodStart.call(this, phase); } } @@ -223,24 +253,60 @@ export default class PhaseInterceptor { this.onHold.push({ name: phase.name, call: () => { - this.phases[phase.name].apply(instance); + this.phases[phase.name].start.apply(instance); } }); } + unlock() { + this.inProgress?.callback(); + this.inProgress = undefined; + } + + /** + * Method to end a phase and log it. + * @param phase - The phase to start. + */ + superEndPhase() { + const instance = this.scene.getCurrentPhase(); + this.originalSuperEnd.apply(instance); + this.inProgress?.callback(); + this.inProgress = undefined; + } + + /** + * m2m to set mode. + * @param phase - The phase to start. + */ + setMode(mode: Mode, ...args: any[]): Promise { + const currentPhase = this.scene.getCurrentPhase(); + const instance = this.scene.ui; + console.log("setMode", mode, args); + const ret = this.originalSetMode.apply(instance, [mode, ...args]); + if (!this.phases[currentPhase.constructor.name]) { + throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptior PHASES list`); + } + if (this.phases[currentPhase.constructor.name].endBySetMode) { + this.inProgress?.callback(); + this.inProgress = undefined; + } + return ret; + } + /** * Method to start the prompt handler. */ - startPromptHander() { + startPromptHandler() { this.promptInterval = setInterval(() => { if (this.prompts.length) { const actionForNextPrompt = this.prompts[0]; const expireFn = actionForNextPrompt.expireFn && actionForNextPrompt.expireFn(); const currentMode = this.scene.ui.getMode(); const currentPhase = this.scene.getCurrentPhase().constructor.name; + const currentHandler = this.scene.ui.getHandler(); if (expireFn) { this.prompts.shift(); - } else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget) { + } else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget && currentHandler.active && (!actionForNextPrompt.awaitingActionInput || (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))) { this.prompts.shift().callback(); } } @@ -254,12 +320,13 @@ export default class PhaseInterceptor { * @param callback - The callback function to execute. * @param expireFn - The function to determine if the prompt has expired. */ - addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn: () => void) { + addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn: () => void, awaitingActionInput: boolean = false) { this.prompts.push({ phaseTarget, mode, callback, - expireFn + expireFn, + awaitingActionInput }); } @@ -271,9 +338,12 @@ export default class PhaseInterceptor { */ restoreOg() { for (const [phase] of this.PHASES) { - phase.prototype.start = this.phases[phase.name]; + phase.prototype.start = this.phases[phase.name].start; } + UI.prototype.setMode = this.originalSetMode; + Phase.prototype.end = this.originalSuperEnd; clearInterval(this.promptInterval); clearInterval(this.interval); + clearInterval(this.intervalRun); } } diff --git a/src/test/vitest.setup.ts b/src/test/vitest.setup.ts index 8729e7796f0..8dac707255a 100644 --- a/src/test/vitest.setup.ts +++ b/src/test/vitest.setup.ts @@ -9,7 +9,9 @@ import {initSpecies} from "#app/data/pokemon-species"; import {initMoves} from "#app/data/move"; import {initAbilities} from "#app/data/ability"; import {initAchievements} from "#app/system/achv.js"; +import { initVouchers } from "#app/system/voucher.js"; +initVouchers(); initAchievements(); initStatsKeys(); initPokemonPrevolutions(); @@ -19,3 +21,5 @@ initPokemonForms(); initSpecies(); initMoves(); initAbilities(); + +global.testFailed = false; diff --git a/src/touch-controls.ts b/src/touch-controls.ts index 3b734e01467..d5a3197f833 100644 --- a/src/touch-controls.ts +++ b/src/touch-controls.ts @@ -1,25 +1,164 @@ import {Button} from "./enums/buttons"; import EventEmitter = Phaser.Events.EventEmitter; +import BattleScene from "./battle-scene"; -// Create a map to store key bindings -export const keys = new Map(); -// Create a map to store keys that are currently pressed -export const keysDown = new Map(); -// Variable to store the ID of the last touched element -let lastTouchedId: string; +const repeatInputDelayMillis = 250; -/** - * Initialize touch controls by binding keys to buttons. - * - * @param events - The event emitter for handling input events. - */ -export function initTouchControls(events: EventEmitter): void { - preventElementZoom(document.querySelector("#dpad")); - preventElementZoom(document.querySelector("#apad")); - // Select all elements with the 'data-key' attribute and bind keys to them - for (const button of document.querySelectorAll("[data-key]")) { - // @ts-ignore - Bind the key to the button using the dataset key - bindKey(button, button.dataset.key, events); +export default class TouchControl { + events: EventEmitter; + private buttonLock: string[] = new Array(); + private inputInterval: NodeJS.Timeout[] = new Array(); + + constructor(scene: BattleScene) { + this.events = scene.game.events; + this.init(); + } + + /** + * Initialize touch controls by binding keys to buttons. + */ + init() { + this.preventElementZoom(document.querySelector("#dpad")); + this.preventElementZoom(document.querySelector("#apad")); + // Select all elements with the 'data-key' attribute and bind keys to them + for (const button of document.querySelectorAll("[data-key]")) { + // @ts-ignore - Bind the key to the button using the dataset key + this.bindKey(button, button.dataset.key); + } + } + + /** + * Binds a node to a specific key to simulate keyboard events on touch. + * + * @param node - The DOM element to bind the key to. + * @param key - The key to simulate. + * @param events - The event emitter for handling input events. + * + * @remarks + * This function binds touch events to a node to simulate 'keydown' and 'keyup' keyboard events. + * It adds the key to the keys map and tracks the keydown state. When a touch starts, it simulates + * a 'keydown' event and adds an 'active' class to the node. When the touch ends, it simulates a 'keyup' + * event, removes the keydown state, and removes the 'active' class from the node and the last touched element. + */ + bindKey(node: HTMLElement, key: string) { + node.addEventListener("touchstart", event => { + event.preventDefault(); + this.touchButtonDown(node, key); + }); + + node.addEventListener("touchend", event => { + event.preventDefault(); + this.touchButtonUp(node, key, event.target["id"]); + }); + } + + touchButtonDown(node: HTMLElement, key: string) { + if (this.buttonLock.includes(key)) { + return; + } + this.simulateKeyboardEvent("keydown", key); + clearInterval(this.inputInterval[key]); + this.inputInterval[key] = setInterval(() => { + this.simulateKeyboardEvent("keydown", key); + }, repeatInputDelayMillis); + this.buttonLock.push(key); + node.classList.add("active"); + + } + + touchButtonUp(node: HTMLElement, key: string, id: string) { + if (!this.buttonLock.includes(key)) { + return; + } + this.simulateKeyboardEvent("keyup", key); + + node.classList.remove("active"); + + document.getElementById(id)?.classList.remove("active"); + const index = this.buttonLock.indexOf(key); + this.buttonLock.splice(index, 1); + clearInterval(this.inputInterval[key]); + } + + /** + * Simulates a keyboard event on the canvas. + * + * @param eventType - The type of the keyboard event ('keydown' or 'keyup'). + * @param key - The key to simulate. + * + * @remarks + * This function checks if the key exists in the Button enum. If it does, it retrieves the corresponding button + * and emits the appropriate event ('input_down' or 'input_up') based on the event type. + */ + simulateKeyboardEvent(eventType: string, key: string) { + if (!Button.hasOwnProperty(key)) { + return; + } + const button = Button[key]; + + switch (eventType) { + case "keydown": + this.events.emit("input_down", { + controller_type: "keyboard", + button: button, + isTouch: true + }); + break; + case "keyup": + this.events.emit("input_up", { + controller_type: "keyboard", + button: button, + isTouch: true + }); + break; + } + } + + /** + * {@link https://stackoverflow.com/a/39778831/4622620|Source} + * + * Prevent zoom on specified element + * @param {HTMLElement} element + */ + preventElementZoom(element: HTMLElement): void { + if (!element) { + return; + } + element.addEventListener("touchstart", (event: TouchEvent) => { + + if (!(event.currentTarget instanceof HTMLElement)) { + return; + } + + const currentTouchTimeStamp = event.timeStamp; + const previousTouchTimeStamp = Number(event.currentTarget.dataset.lastTouchTimeStamp) || currentTouchTimeStamp; + const timeStampDifference = currentTouchTimeStamp - previousTouchTimeStamp; + const fingers = event.touches.length; + event.currentTarget.dataset.lastTouchTimeStamp = String(currentTouchTimeStamp); + + if (!timeStampDifference || timeStampDifference > 500 || fingers > 1) { + return; + } // not double-tap + + event.preventDefault(); + + if (event.target instanceof HTMLElement) { + event.target.click(); + } + }); + } + + /** + * Deactivates all currently pressed keys. + */ + deactivatePressedKey(): void { + for (const key of Object.keys(this.inputInterval)) { + clearInterval(this.inputInterval[key]); + } + for (const button of document.querySelectorAll("[data-key]")) { + button.classList.remove("active"); + } + this.buttonLock = []; } } @@ -47,111 +186,3 @@ export function isMobile(): boolean { })(navigator.userAgent || navigator.vendor || window["opera"]); return ret; } - -/** - * Simulates a keyboard event on the canvas. - * - * @param eventType - The type of the keyboard event ('keydown' or 'keyup'). - * @param key - The key to simulate. - * @param events - The event emitter for handling input events. - * - * @remarks - * This function checks if the key exists in the Button enum. If it does, it retrieves the corresponding button - * and emits the appropriate event ('input_down' or 'input_up') based on the event type. - */ -function simulateKeyboardEvent(eventType: string, key: string, events: EventEmitter) { - if (!Button.hasOwnProperty(key)) { - return; - } - const button = Button[key]; - - switch (eventType) { - case "keydown": - events.emit("input_down", { - controller_type: "keyboard", - button: button, - }); - break; - case "keyup": - events.emit("input_up", { - controller_type: "keyboard", - button: button, - }); - break; - } -} - -/** - * Binds a node to a specific key to simulate keyboard events on touch. - * - * @param node - The DOM element to bind the key to. - * @param key - The key to simulate. - * @param events - The event emitter for handling input events. - * - * @remarks - * This function binds touch events to a node to simulate 'keydown' and 'keyup' keyboard events. - * It adds the key to the keys map and tracks the keydown state. When a touch starts, it simulates - * a 'keydown' event and adds an 'active' class to the node. When the touch ends, it simulates a 'keyup' - * event, removes the keydown state, and removes the 'active' class from the node and the last touched element. - */ -function bindKey(node: HTMLElement, key: string, events) { - keys.set(node.id, key); - - node.addEventListener("touchstart", event => { - event.preventDefault(); - simulateKeyboardEvent("keydown", key, events); - keysDown.set(event.target["id"], node.id); - node.classList.add("active"); - }); - - node.addEventListener("touchend", event => { - event.preventDefault(); - - const pressedKey = keysDown.get(event.target["id"]); - if (pressedKey && keys.has(pressedKey)) { - const key = keys.get(pressedKey); - simulateKeyboardEvent("keyup", key, events); - } - - keysDown.delete(event.target["id"]); - node.classList.remove("active"); - - if (lastTouchedId) { - document.getElementById(lastTouchedId).classList.remove("active"); - } - }); -} - -/** - * {@link https://stackoverflow.com/a/39778831/4622620|Source} - * - * Prevent zoom on specified element - * @param {HTMLElement} element - */ -function preventElementZoom(element: HTMLElement): void { - if (!element) { - return; - } - element.addEventListener("touchstart", (event: TouchEvent) => { - - if (!(event.currentTarget instanceof HTMLElement)) { - return; - } - - const currentTouchTimeStamp = event.timeStamp; - const previousTouchTimeStamp = Number(event.currentTarget.dataset.lastTouchTimeStamp) || currentTouchTimeStamp; - const timeStampDifference = currentTouchTimeStamp - previousTouchTimeStamp; - const fingers = event.touches.length; - event.currentTarget.dataset.lastTouchTimeStamp = String(currentTouchTimeStamp); - - if (!timeStampDifference || timeStampDifference > 500 || fingers > 1) { - return; - } // not double-tap - - event.preventDefault(); - - if (event.target instanceof HTMLElement) { - event.target.click(); - } - }); -} diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index d068cbebde7..21d0d0841e6 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -30,8 +30,23 @@ export class UiInputs { this.listenInputs(); } + detectInputMethod(evt): void { + if (evt.controller_type === "keyboard") { + //if the touch property is present and defined, then this is a simulated keyboard event from the touch screen + if (evt.hasOwnProperty("isTouch") && evt.isTouch) { + this.scene.inputMethod = "touch"; + } else { + this.scene.inputMethod = "keyboard"; + } + } else if (evt.controller_type === "gamepad") { + this.scene.inputMethod = "gamepad"; + } + } + listenInputs(): void { this.events.on("input_down", (event) => { + this.detectInputMethod(event); + const actions = this.getActionsKeyDown(); if (!actions.hasOwnProperty(event.button)) { return; @@ -147,20 +162,13 @@ export class UiInputs { } case Mode.TITLE: case Mode.COMMAND: - case Mode.FIGHT: - case Mode.BALL: - case Mode.TARGET_SELECT: - case Mode.SAVE_SLOT: - case Mode.PARTY: - case Mode.SUMMARY: - case Mode.STARTER_SELECT: - case Mode.OPTION_SELECT: + case Mode.MODIFIER_SELECT: this.scene.ui.setOverlayMode(Mode.MENU); break; - case Mode.CONFIRM: + case Mode.STARTER_SELECT: + this.buttonTouch(); + break; case Mode.MENU: - case Mode.SETTINGS: - case Mode.ACHIEVEMENTS: this.scene.ui.revertMode(); this.scene.playSound("select"); break; diff --git a/src/ui/achv-bar.ts b/src/ui/achv-bar.ts index f24fda0792b..9e9b20795e3 100644 --- a/src/ui/achv-bar.ts +++ b/src/ui/achv-bar.ts @@ -2,6 +2,7 @@ import BattleScene from "../battle-scene"; import { Achv, getAchievementDescription } from "../system/achv"; import { Voucher } from "../system/voucher"; import { TextStyle, addTextObject } from "./text"; +import { PlayerGender } from "#app/data/enums/player-gender"; export default class AchvBar extends Phaser.GameObjects.Container { private defaultWidth: number; @@ -14,11 +15,13 @@ export default class AchvBar extends Phaser.GameObjects.Container { private descriptionText: Phaser.GameObjects.Text; private queue: (Achv | Voucher)[] = []; + private playerGender: PlayerGender; public shown: boolean; constructor(scene: BattleScene) { super(scene, scene.game.canvas.width / 6, 0); + this.playerGender = scene.gameData.gender; } setup(): void { @@ -64,7 +67,7 @@ export default class AchvBar extends Phaser.GameObjects.Container { this.bg.setTexture(`achv_bar${tier ? `_${tier + 1}` : ""}`); this.icon.setFrame(achv.getIconImage()); - this.titleText.setText(achv.getName()); + this.titleText.setText(achv.getName(this.playerGender)); this.scoreText.setVisible(achv instanceof Achv); if (achv instanceof Achv) { this.descriptionText.setText(getAchievementDescription((achv as Achv).localizationKey)); @@ -96,13 +99,13 @@ export default class AchvBar extends Phaser.GameObjects.Container { ease: "Sine.easeOut" }); - this.scene.time.delayedCall(10000, () => this.hide()); + this.scene.time.delayedCall(10000, () => this.hide(this.playerGender)); this.setVisible(true); this.shown = true; } - protected hide(): void { + protected hide(playerGender: PlayerGender): void { if (!this.shown) { return; } diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index a73f7560282..464a967cbfd 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -3,9 +3,11 @@ import { Button } from "../enums/buttons"; import i18next from "../plugins/i18n"; import { Achv, achvs, getAchievementDescription } from "../system/achv"; import MessageUiHandler from "./message-ui-handler"; -import { TextStyle, addTextObject } from "./text"; +import { addTextObject, TextStyle } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import { PlayerGender } from "#app/data/enums/player-gender"; +import { ParseKeys } from "i18next"; export default class AchvsUiHandler extends MessageUiHandler { private achvsContainer: Phaser.GameObjects.Container; @@ -33,7 +35,14 @@ export default class AchvsUiHandler extends MessageUiHandler { const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24); headerBg.setOrigin(0, 0); - const headerText = addTextObject(this.scene, 0, 0, i18next.t("achv:Achievements.name"), TextStyle.SETTINGS_LABEL); + // We need to get the player gender from the game data to add the correct prefix to the achievement name + const playerGender = this.scene.gameData.gender; + let genderPrefix = "PGM"; + if (playerGender === PlayerGender.FEMALE) { + genderPrefix = "PGF"; + } + + const headerText = addTextObject(this.scene, 0, 0, i18next.t(`${genderPrefix}achv:Achievements.name` as ParseKeys), TextStyle.SETTINGS_LABEL); headerText.setOrigin(0, 0); headerText.setPositionRelative(headerBg, 8, 4); @@ -137,7 +146,14 @@ export default class AchvsUiHandler extends MessageUiHandler { } protected showAchv(achv: Achv) { - achv.name = i18next.t(`achv:${achv.localizationKey}.name`); + // We need to get the player gender from the game data to add the correct prefix to the achievement name + const playerGender = this.scene.gameData.gender; + let genderPrefix = "PGM"; + if (playerGender === PlayerGender.FEMALE) { + genderPrefix = "PGF"; + } + + achv.name = i18next.t(`${genderPrefix}achv:${achv.localizationKey}.name` as ParseKeys); achv.description = getAchievementDescription(achv.localizationKey); const achvUnlocks = this.scene.gameData.achvUnlocks; const unlocked = achvUnlocks.hasOwnProperty(achv.id); @@ -145,7 +161,7 @@ export default class AchvsUiHandler extends MessageUiHandler { this.titleText.setText(unlocked ? achv.name : "???"); this.showText(!hidden ? achv.description : ""); this.scoreText.setText(`${achv.score}pt`); - this.unlockText.setText(unlocked ? new Date(achvUnlocks[achv.id]).toLocaleDateString() : i18next.t("achv:Locked.name")); + this.unlockText.setText(unlocked ? new Date(achvUnlocks[achv.id]).toLocaleDateString() : i18next.t(`${genderPrefix}achv:Locked.name` as ParseKeys)); } processInput(button: Button): boolean { diff --git a/src/ui/arena-flyout.ts b/src/ui/arena-flyout.ts index e854de2006b..5793582d6c4 100644 --- a/src/ui/arena-flyout.ts +++ b/src/ui/arena-flyout.ts @@ -4,8 +4,8 @@ import { ArenaTagSide } 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"; -import { ArenaEvent, ArenaEventType, TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js"; -import { BattleSceneEventType, TurnEndEvent } from "#app/battle-scene-events.js"; +import { ArenaEvent, ArenaEventType, TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/field/events/arena"; +import { BattleSceneEventType, TurnEndEvent } from "../events/battle-scene"; import { ArenaTagType } from "#app/data/enums/arena-tag-type.js"; import TimeOfDayWidget from "./time-of-day-widget"; import * as Utils from "../utils"; diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index 9a9e3ef46a9..812969a988d 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -4,7 +4,7 @@ import * as Utils from "../utils"; import BattleScene from "#app/battle-scene.js"; import { UiTheme } from "#app/enums/ui-theme.js"; import Move from "#app/data/move.js"; -import { BattleSceneEventType, BerryUsedEvent, MoveUsedEvent } from "#app/battle-scene-events.js"; +import { BattleSceneEventType, BerryUsedEvent, MoveUsedEvent } from "../events/battle-scene"; import { BerryType } from "#app/data/enums/berry-type.js"; import { Moves } from "#app/data/enums/moves.js"; @@ -55,6 +55,9 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { /** The array of {@linkcode MoveInfo} used to track moves for the {@linkcode Pokemon} linked to the flyout */ private moveInfo: MoveInfo[] = new Array(); + /** Current state of the flyout's visibility */ + public flyoutVisible: boolean = false; + // Stores callbacks in a variable so they can be unsubscribed from when destroyed private readonly onMoveUsedEvent = (event: Event) => this.onMoveUsed(event); private readonly onBerryUsedEvent = (event: Event) => this.onBerryUsed(event); @@ -170,6 +173,8 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { /** Animates the flyout to either show or hide it by applying a fade and translation */ toggleFlyout(visible: boolean): void { + this.flyoutVisible = visible; + this.scene.tweens.add({ targets: this.flyoutParent, x: visible ? this.anchorX : this.anchorX - this.translationX, diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 9fb81f89698..c246af73d07 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -9,6 +9,7 @@ import { Type, getTypeRgb } from "../data/type"; import { getVariantTint } from "#app/data/variant"; import { BattleStat } from "#app/data/battle-stat"; import BattleFlyout from "./battle-flyout"; +import { WindowVariant, addWindow } from "./ui-theme"; const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; @@ -52,6 +53,13 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private type3Icon: Phaser.GameObjects.Sprite; private expBar: Phaser.GameObjects.Image; + // #region Type effectiveness hint objects + private effectivenessContainer: Phaser.GameObjects.Container; + private effectivenessWindow: Phaser.GameObjects.NineSlice; + private effectivenessText: Phaser.GameObjects.Text; + private currentEffectiveness?: string; + // #endregion + public expMaskRect: Phaser.GameObjects.Graphics; private statsContainer: Phaser.GameObjects.Container; @@ -59,7 +67,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private statValuesContainer: Phaser.GameObjects.Container; private statNumbers: Phaser.GameObjects.Sprite[]; - public flyoutMenu: BattleFlyout; + public flyoutMenu?: BattleFlyout; constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); @@ -250,6 +258,19 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.type3Icon.setName("icon_type_3"); this.type3Icon.setOrigin(0, 0); this.add(this.type3Icon); + + if (!this.player) { + this.effectivenessContainer = this.scene.add.container(0, 0); + this.effectivenessContainer.setPositionRelative(this.type1Icon, 22, 4); + this.effectivenessContainer.setVisible(false); + this.add(this.effectivenessContainer); + + this.effectivenessText = addTextObject(this.scene, 5, 4.5, "", TextStyle.BATTLE_INFO); + this.effectivenessWindow = addWindow((this.scene as BattleScene), 0, 0, 0, 20, false, false, null, null, WindowVariant.XTHIN); + + this.effectivenessContainer.add(this.effectivenessWindow); + this.effectivenessContainer.add(this.effectivenessText); + } } initInfo(pokemon: Pokemon) { @@ -711,6 +732,39 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }); } + /** + * Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary + */ + toggleFlyout(visible: boolean): void { + this.flyoutMenu?.toggleFlyout(visible); + + if (visible) { + this.effectivenessContainer?.setVisible(false); + } else { + this.updateEffectiveness(this.currentEffectiveness); + } + } + + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + if (this.player) { + return; + } + this.currentEffectiveness = effectiveness; + + if (!(this.scene as BattleScene).typeHints || effectiveness === undefined || this.flyoutMenu.flyoutVisible) { + this.effectivenessContainer.setVisible(false); + return; + } + + this.effectivenessText.setText(effectiveness); + this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth; + this.effectivenessContainer.setVisible(true); + } + getBaseY(): number { return this.baseY; } diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts new file mode 100644 index 00000000000..092d954eae7 --- /dev/null +++ b/src/ui/challenges-select-ui-handler.ts @@ -0,0 +1,330 @@ +import BattleScene from "../battle-scene"; +import { TextStyle, addTextObject } from "./text"; +import { Mode } from "./ui"; +import UiHandler from "./ui-handler"; +import { addWindow } from "./ui-theme"; +import {Button} from "../enums/buttons"; +import i18next from "#app/plugins/i18n.js"; +import { SelectStarterPhase, TitlePhase } from "#app/phases.js"; +import { Challenge } from "#app/data/challenge.js"; + +/** + * Handles all the UI for choosing optional challenges. + */ +export default class GameChallengesUiHandler extends UiHandler { + private challengesContainer: Phaser.GameObjects.Container; + private valuesContainer: Phaser.GameObjects.Container; + + private scrollCursor: integer; + + private optionsBg: Phaser.GameObjects.NineSlice; + + // private difficultyText: Phaser.GameObjects.Text; + + private descriptionText: Phaser.GameObjects.Text; + + private challengeLabels: Phaser.GameObjects.Text[]; + private challengeValueLabels: Phaser.GameObjects.Text[]; + + private cursorObj: Phaser.GameObjects.NineSlice; + + private startCursor: Phaser.GameObjects.NineSlice; + + constructor(scene: BattleScene, mode?: Mode) { + super(scene, mode); + } + + setup() { + const ui = this.getUi(); + + this.challengesContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1); + + 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); + + // 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.setOrigin(0, 0); + + const headerText = addTextObject(this.scene, 0, 0, i18next.t("challenges:title"), TextStyle.SETTINGS_LABEL); + headerText.setOrigin(0, 0); + headerText.setPositionRelative(headerBg, 8, 4); + + // const difficultyBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 18) - 2, 24); + // difficultyBg.setOrigin(0, 0); + // difficultyBg.setPositionRelative(headerBg, headerBg.width, 0); + + // this.difficultyText = addTextObject(this.scene, 0, 0, "0", TextStyle.SETTINGS_LABEL); + // this.difficultyText.setOrigin(0, 0); + // this.difficultyText.setPositionRelative(difficultyBg, 8, 4); + + // const difficultyName = addTextObject(this.scene, 0, 0, i18next.t("challenges:points"), TextStyle.SETTINGS_LABEL); + // difficultyName.setOrigin(0, 0); + // 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.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.setOrigin(0, 0); + descriptionBg.setPositionRelative(this.optionsBg, this.optionsBg.width, 0); + + this.descriptionText = addTextObject(this.scene, 0, 0, "", TextStyle.SETTINGS_LABEL); + 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.setOrigin(0, 0); + startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height); + + const startText = addTextObject(this.scene, 0, 0, i18next.t("challenges:start"), TextStyle.SETTINGS_LABEL); + 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.setOrigin(0, 0); + this.startCursor.setPositionRelative(startBg, 4, 4); + this.startCursor.setVisible(false); + + this.valuesContainer = this.scene.add.container(0, 0); + + 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); + + this.valuesContainer.add(this.challengeLabels[i]); + + this.challengeValueLabels[i] = addTextObject(this.scene, 0, 28 + i * 16, "", TextStyle.SETTINGS_LABEL); + this.challengeValueLabels[i].setPositionRelative(this.challengeLabels[i], 100, 0); + + this.valuesContainer.add(this.challengeValueLabels[i]); + } + + this.challengesContainer.add(headerBg); + this.challengesContainer.add(headerText); + // this.challengesContainer.add(difficultyBg); + // this.challengesContainer.add(this.difficultyText); + // this.challengesContainer.add(difficultyName); + this.challengesContainer.add(this.optionsBg); + this.challengesContainer.add(descriptionBg); + this.challengesContainer.add(this.descriptionText); + this.challengesContainer.add(startBg); + this.challengesContainer.add(startText); + this.challengesContainer.add(this.startCursor); + this.challengesContainer.add(this.valuesContainer); + + ui.add(this.challengesContainer); + + this.setCursor(0); + this.setScrollCursor(0); + + this.challengesContainer.setVisible(false); + } + + + updateText(): void { + if (this.scene.gameMode.challenges.length > 0) { + this.descriptionText.text = this.getActiveChallenge().getDescription(); + this.descriptionText.updateText(); + } + + // 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 { + super.show(args); + + this.startCursor.setVisible(false); + this.challengesContainer.setVisible(true); + this.setCursor(0); + + this.updateText(); + + this.getUi().moveTo(this.challengesContainer, this.getUi().length - 1); + + this.getUi().hideTooltip(); + + return true; + } + + /** + * Processes input from a specified button. + * This method handles navigation through a UI menu, including movement through menu items + * and handling special actions like cancellation. Each button press may adjust the cursor + * position or the menu scroll, and plays a sound effect if the action was successful. + * + * @param button - The button pressed by the user. + * @returns `true` if the action associated with the button was successfully processed, `false` otherwise. + */ + processInput(button: Button): boolean { + const ui = this.getUi(); + // Defines the maximum number of rows that can be displayed on the screen. + const rowsToDisplay = 9; + + let success = false; + + if (button === Button.CANCEL) { + if (this.startCursor.visible) { + this.startCursor.setVisible(false); + this.cursorObj?.setVisible(true); + } else { + this.scene.clearPhaseQueue(); + this.scene.pushPhase(new TitlePhase(this.scene)); + this.scene.getCurrentPhase().end(); + } + success = true; + } else if (button === Button.SUBMIT || button === Button.ACTION) { + if (this.startCursor.visible) { + 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); + if (totalDifficulty >= totalMinDifficulty) { + this.scene.unshiftPhase(new SelectStarterPhase(this.scene)); + this.scene.getCurrentPhase().end(); + success = true; + } else { + success = false; + } + } else { + this.startCursor.setVisible(true); + this.cursorObj?.setVisible(false); + success = true; + } + } else { + switch (button) { + case Button.UP: + if (this.cursor === 0) { + if (this.scrollCursor === 0) { + // When at the top of the menu and pressing UP, move to the bottommost item. + if (this.scene.gameMode.challenges.length > rowsToDisplay) { // If there are more than 9 challenges, scroll to the bottom + // First, set the cursor to the last visible element, preparing for the scroll to the end. + const successA = this.setCursor(rowsToDisplay - 1); + // Then, adjust the scroll to display the bottommost elements of the menu. + const successB = this.setScrollCursor(this.scene.gameMode.challenges.length - rowsToDisplay); + success = successA && successB; // success is just there to play the little validation sound effect + } else { // If there are 9 or less challenges, just move to the bottom one + success = this.setCursor(this.scene.gameMode.challenges.length - 1); + } + } else { + success = this.setScrollCursor(this.scrollCursor - 1); + } + } else { + success = this.setCursor(this.cursor - 1); + } + if (success) { + this.updateText(); + } + break; + case Button.DOWN: + if (this.cursor === rowsToDisplay - 1) { + if (this.scrollCursor < this.scene.gameMode.challenges.length - rowsToDisplay) { + // When at the bottom and pressing DOWN, scroll if possible. + success = this.setScrollCursor(this.scrollCursor + 1); + } else { + // When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item. + // First, set the cursor to the first visible element, preparing for the scroll to the top. + const successA = this.setCursor(0); + // Then, adjust the scroll to display the topmost elements of the menu. + const successB = this.setScrollCursor(0); + success = successA && successB; // success is just there to play the little validation sound effect + } + } else if (this.scene.gameMode.challenges.length < rowsToDisplay && this.cursor === this.scene.gameMode.challenges.length - 1) { + // When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item. + success = this.setCursor(0); + } else { + success = this.setCursor(this.cursor + 1); + } + if (success) { + this.updateText(); + } + break; + case Button.LEFT: + // Moves the option cursor left, if possible. + success = this.getActiveChallenge().decreaseValue(); + if (success) { + this.updateText(); + } + break; + case Button.RIGHT: + // Moves the option cursor right, if possible. + success = this.getActiveChallenge().increaseValue(); + if (success) { + this.updateText(); + } + break; + } + } + + // Plays a select sound effect if an action was successfully processed. + if (success) { + ui.playSelect(); + } + + return success; + } + + setCursor(cursor: integer): boolean { + let ret = super.setCursor(cursor); + + if (!this.cursorObj) { + this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 9) - 10, 16, 1, 1, 1, 1); + this.cursorObj.setOrigin(0, 0); + this.valuesContainer.add(this.cursorObj); + } + + ret ||= !this.cursorObj.visible; + this.cursorObj.setVisible(true); + + this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16); + + return ret; + } + + setScrollCursor(scrollCursor: integer): boolean { + if (scrollCursor === this.scrollCursor) { + return false; + } + + this.scrollCursor = scrollCursor; + + this.setCursor(this.cursor); + + return true; + } + + getActiveChallenge(): Challenge { + return this.scene.gameMode.challenges[this.cursor + this.scrollCursor]; + } + + clear() { + super.clear(); + this.challengesContainer.setVisible(false); + this.eraseCursor(); + } + + eraseCursor() { + if (this.cursorObj) { + this.cursorObj.destroy(); + } + this.cursorObj = null; + } +} diff --git a/src/ui/egg-counter-container.ts b/src/ui/egg-counter-container.ts new file mode 100644 index 00000000000..1c5779ef777 --- /dev/null +++ b/src/ui/egg-counter-container.ts @@ -0,0 +1,88 @@ +import BattleScene from "#app/battle-scene.js"; +import { addWindow } from "./ui-theme"; +import { addTextObject, TextStyle } from "./text"; +import { EggCountChangedEvent, EggEventType } from "#app/events/egg.js"; +import EggHatchSceneHandler from "./egg-hatch-scene-handler"; + +/** + * A container that displays the count of hatching eggs. + * Extends Phaser.GameObjects.Container. + */ +export default class EggCounterContainer extends Phaser.GameObjects.Container { + private readonly WINDOW_DEFAULT_WIDTH = 37; + private readonly WINDOW_MEDIUM_WIDTH = 42; + private readonly WINDOW_HEIGHT = 26; + private readonly onEggCountChangedEvent = (event: Event) => this.onEggCountChanged(event); + + private battleScene: BattleScene; + private eggCount: integer; + private eggCountWindow: Phaser.GameObjects.NineSlice; + private eggCountText: Phaser.GameObjects.Text; + + /** + * @param {BattleScene} scene - The scene to which this container belongs. + * @param {number} eggCount - The number of eggs to hatch. + */ + constructor(scene: BattleScene, eggCount: integer) { + super(scene, 0, 0); + this.eggCount = eggCount; + this.battleScene = scene; + + const uiHandler = this.battleScene.ui.getHandler() as EggHatchSceneHandler; + + uiHandler.eventTarget.addEventListener(EggEventType.EGG_COUNT_CHANGED, this.onEggCountChangedEvent); + this.setup(); + } + + /** + * Sets up the container, creating the window, egg sprite, and egg count text. + */ + private setup(): void { + const windowWidth = this.eggCount > 9 ? this.WINDOW_MEDIUM_WIDTH : this.WINDOW_DEFAULT_WIDTH; + + this.eggCountWindow = addWindow(this.battleScene, 5, 5, windowWidth, this.WINDOW_HEIGHT); + this.setVisible(this.eggCount > 1); + + this.add(this.eggCountWindow); + + const eggSprite = this.battleScene.add.sprite(19, 18, "egg", "egg_0"); + eggSprite.setScale(0.32); + + this.eggCountText = addTextObject(this.battleScene, 28, 13, `${this.eggCount}`, TextStyle.MESSAGE, { fontSize: "66px" }); + + this.add(eggSprite); + this.add(this.eggCountText); + } + + /** + * Resets the window size to the default width and height. + */ + private setWindowToDefaultSize(): void { + this.eggCountWindow.setSize(this.WINDOW_DEFAULT_WIDTH, this.WINDOW_HEIGHT); + } + + /** + * Handles window size, the egg count to show, and whether it should be displayed. + * + * @param event {@linkcode Event} being sent + * @returns void + */ + private onEggCountChanged(event: Event): void { + const eggCountChangedEvent = event as EggCountChangedEvent; + if (!eggCountChangedEvent) { + return; + } + + const eggCount = eggCountChangedEvent.eggCount; + + if (eggCount < 10) { + this.setWindowToDefaultSize(); + } + + if (eggCount > 0) { + this.eggCountText.setText(eggCount.toString()); + } else { + this.eggCountText.setVisible(false); + } + } +} diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index f0e55e04801..96874f439ff 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -156,15 +156,27 @@ export default class EggGachaUiHandler extends MessageUiHandler { this.eggGachaOptionSelectBg.setOrigin(1, 1); this.eggGachaOptionsContainer.add(this.eggGachaOptionSelectBg); + const multiplierOne = "x1"; + const multiplierTen = "x10"; const pullOptions = [ - { multiplier: "x1", description: `1 ${i18next.t("egg:pull")}` }, - { multiplier: "x10", description: `10 ${i18next.t("egg:pulls")}` }, - { multiplier: "x1", description: `5 ${i18next.t("egg:pulls")}` }, - { multiplier: "x1", description: `10 ${i18next.t("egg:pulls")}` }, - { multiplier: "x1", description: `25 ${i18next.t("egg:pulls")}` } + { multiplier: multiplierOne, description: `1 ${i18next.t("egg:pull")}`, icon: getVoucherTypeIcon(VoucherType.REGULAR) }, + { multiplier: multiplierTen, description: `10 ${i18next.t("egg:pulls")}`, icon: getVoucherTypeIcon(VoucherType.REGULAR) }, + { multiplier: multiplierOne, description: `5 ${i18next.t("egg:pulls")}`, icon: getVoucherTypeIcon(VoucherType.PLUS) }, + { multiplier: multiplierOne, description: `10 ${i18next.t("egg:pulls")}`, icon: getVoucherTypeIcon(VoucherType.PREMIUM) }, + { multiplier: multiplierOne, description: `25 ${i18next.t("egg:pulls")}`, icon: getVoucherTypeIcon(VoucherType.GOLDEN) } ]; - const pullOptionsText = pullOptions.map(option => ` ${option.multiplier.padEnd(4)} ${option.description}`).join("\n"); + const { resolvedLanguage } = i18next; + const pullOptionsText = pullOptions.map(option =>{ + const desc = option.description.split(" "); + if (desc[0].length < 2) { + desc[0] += ["zh", "ko"].includes(resolvedLanguage.substring(0,2)) ? " " : " "; + } + if (option.multiplier === multiplierOne) { + desc[0] = " " + desc[0]; + } + return ` ${option.multiplier.padEnd(5)}${desc.join(" ")}`; + }).join("\n"); const optionText = addTextObject( this.scene, @@ -181,9 +193,8 @@ export default class EggGachaUiHandler extends MessageUiHandler { optionText.setPositionRelative(this.eggGachaOptionSelectBg, 16, 9); - new Array(5).fill(null).map((_, i) => { - const voucherType = i < 2 ? VoucherType.REGULAR : i === 2 ? VoucherType.PLUS : i === 3 ? VoucherType.PREMIUM : VoucherType.GOLDEN; - const icon = this.scene.add.sprite(0, 0, "items", getVoucherTypeIcon(voucherType)); + pullOptions.forEach((option, i) => { + const icon = this.scene.add.sprite(0, 0, "items", option.icon); icon.setScale(0.5); icon.setPositionRelative(this.eggGachaOptionSelectBg, 20, 17 + i * 16); this.eggGachaOptionsContainer.add(icon); @@ -396,7 +407,8 @@ export default class EggGachaUiHandler extends MessageUiHandler { const timestamp = new Date().getTime(); for (const tier of tiers) { - const egg = new Egg(Utils.randInt(EGG_SEED, EGG_SEED * tier), this.gachaCursor, getEggTierDefaultHatchWaves(tier), timestamp); + const eggId = Utils.randInt(EGG_SEED, EGG_SEED * tier); + const egg = new Egg(eggId, this.gachaCursor, getEggTierDefaultHatchWaves(tier), timestamp); if (egg.isManaphyEgg()) { this.scene.gameData.gameStats.manaphyEggsPulled++; egg.hatchWaves = getEggTierDefaultHatchWaves(EggTier.ULTRA); diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index 5a4c984234c..94affc2e751 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -7,6 +7,14 @@ import {Button} from "../enums/buttons"; export default class EggHatchSceneHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; + /** + * Allows subscribers to listen for events + * + * Current Events: + * - {@linkcode EggEventType.EGG_COUNT_CHANGED} {@linkcode EggCountChangedEvent} + */ + public readonly eventTarget: EventTarget = new EventTarget(); + constructor(scene: BattleScene) { super(scene, Mode.EGG_HATCH_SCENE); } diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts index 92c7faf5477..653789d4a20 100644 --- a/src/ui/egg-list-ui-handler.ts +++ b/src/ui/egg-list-ui-handler.ts @@ -98,13 +98,6 @@ export default class EggListUiHandler extends MessageUiHandler { let e = 0; - /*this.scene.gameData.eggs = [ - new Egg(1, 1, 5, new Date().getTime()), - new Egg(1 + EGG_SEED, 1, 15, new Date().getTime()), - new Egg(1 + EGG_SEED * 2, 1, 50, new Date().getTime()), - new Egg(1 + EGG_SEED * 3, GachaType.LEGENDARY, 100, new Date().getTime()) - ];*/ - for (const egg of this.scene.gameData.eggs) { const x = (e % 11) * 18; const y = Math.floor(e / 11) * 18; diff --git a/src/ui/eggs-to-hatch-count-container.ts b/src/ui/eggs-to-hatch-count-container.ts deleted file mode 100644 index 693e4666220..00000000000 --- a/src/ui/eggs-to-hatch-count-container.ts +++ /dev/null @@ -1,54 +0,0 @@ -import BattleScene from "#app/battle-scene.js"; -import { addWindow } from "./ui-theme"; -import { addTextObject, TextStyle } from "./text"; - -/** - * A container that displays the count of hatching eggs. - * Extends Phaser.GameObjects.Container. - */ -export default class EggsToHatchCountContainer extends Phaser.GameObjects.Container { - private readonly WINDOW_DEFAULT_WIDTH = 37; - private readonly WINDOW_MEDIUM_WIDTH = 42; - private readonly WINDOW_HEIGHT = 26; - - private eggsToHatchCount: integer; - private eggsToHatchCountWindow: Phaser.GameObjects.NineSlice; - - public eggCountText: Phaser.GameObjects.Text; - - /** - * @param {BattleScene} scene - The scene to which this container belongs. - * @param {number} eggsToHatchCount - The number of eggs to hatch. - */ - constructor(scene: BattleScene, eggsToHatchCount: integer) { - super(scene, 0, 0); - this.eggsToHatchCount = eggsToHatchCount; - } - - /** - * Sets up the container, creating the window, egg sprite, and egg count text. - */ - setup(): void { - const windowWidth = this.eggsToHatchCount > 9 ? this.WINDOW_MEDIUM_WIDTH : this.WINDOW_DEFAULT_WIDTH; - - this.eggsToHatchCountWindow = addWindow(this.scene as BattleScene, 5, 5, windowWidth, this.WINDOW_HEIGHT); - this.setVisible(this.eggsToHatchCount > 1); - - this.add(this.eggsToHatchCountWindow); - - const eggSprite = this.scene.add.sprite(19, 18, "egg", "egg_0"); - eggSprite.setScale(0.32); - - this.eggCountText = addTextObject(this.scene, 28, 13, `${this.eggsToHatchCount}`, TextStyle.MESSAGE, { fontSize: "66px" }); - - this.add(eggSprite); - this.add(this.eggCountText); - } - - /** - * Resets the window size to the default width and height. - */ - setWindowToDefaultSize(): void { - this.eggsToHatchCountWindow.setSize(this.WINDOW_DEFAULT_WIDTH, this.WINDOW_HEIGHT); - } -} diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index acbf66b7075..657c8b7e311 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -1,6 +1,6 @@ import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; -import { Type } from "../data/type"; +import { getTypeDamageMultiplierColor, Type } from "../data/type"; import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; @@ -9,6 +9,7 @@ import { CommandPhase } from "../phases"; import { MoveCategory } from "#app/data/move.js"; import i18next from "../plugins/i18n"; import {Button} from "../enums/buttons"; +import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; export default class FightUiHandler extends UiHandler { private movesContainer: Phaser.GameObjects.Container; @@ -162,7 +163,8 @@ export default class FightUiHandler extends UiHandler { ui.add(this.cursorObj); } - const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset(); + const pokemon = (this.scene.getCurrentPhase() as CommandPhase).getPokemon(); + const moveset = pokemon.getMoveset(); const hasMove = cursor < moveset.length; @@ -179,6 +181,26 @@ export default class FightUiHandler extends UiHandler { this.ppText.setText(`${Utils.padInt(pp, 2, " ")}/${Utils.padInt(maxPP, 2, " ")}`); this.powerText.setText(`${power >= 0 ? power : "---"}`); this.accuracyText.setText(`${accuracy >= 0 ? accuracy : "---"}`); + + const ppPercentLeft = pp / maxPP; + + //** Determines TextStyle according to percentage of PP remaining */ + let ppColorStyle = TextStyle.MOVE_PP_FULL; + if (ppPercentLeft > 0.25 && ppPercentLeft <= 0.5) { + ppColorStyle = TextStyle.MOVE_PP_HALF_FULL; + } else if (ppPercentLeft > 0 && ppPercentLeft <= 0.25) { + ppColorStyle = TextStyle.MOVE_PP_NEAR_EMPTY; + } else if (ppPercentLeft === 0) { + ppColorStyle = TextStyle.MOVE_PP_EMPTY; + } + + //** Changes the text color and shadow according to the determined TextStyle */ + this.ppText.setColor(this.getTextColor(ppColorStyle, false)); + this.ppText.setShadowColor(this.getTextColor(ppColorStyle, true)); + + pokemon.getOpponents().forEach((opponent) => { + opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); + }); } this.typeIcon.setVisible(hasMove); @@ -195,17 +217,60 @@ export default class FightUiHandler extends UiHandler { return changed; } + /** + * Gets multiplier text for a pokemon's move against a specific opponent + * Returns undefined if it's a status move + */ + private getEffectivenessText(pokemon: Pokemon, opponent: Pokemon, pokemonMove: PokemonMove): string | undefined { + const effectiveness = opponent.getMoveEffectiveness(pokemon, pokemonMove); + if (effectiveness === undefined) { + return undefined; + } + + return `${effectiveness}x`; + } + displayMoves() { - const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset(); - for (let m = 0; m < 4; m++) { - const moveText = addTextObject(this.scene, m % 2 === 0 ? 0 : 100, m < 2 ? 0 : 16, "-", TextStyle.WINDOW); - if (m < moveset.length) { - moveText.setText(moveset[m].getName()); + const pokemon = (this.scene.getCurrentPhase() as CommandPhase).getPokemon(); + const moveset = pokemon.getMoveset(); + + for (let moveIndex = 0; moveIndex < 4; moveIndex++) { + const moveText = addTextObject(this.scene, moveIndex % 2 === 0 ? 0 : 100, moveIndex < 2 ? 0 : 16, "-", TextStyle.WINDOW); + + if (moveIndex < moveset.length) { + const pokemonMove = moveset[moveIndex]; + moveText.setText(pokemonMove.getName()); + moveText.setColor(this.getMoveColor(pokemon, pokemonMove) ?? moveText.style.color); } + this.movesContainer.add(moveText); } } + /** + * Returns a specific move's color based on its type effectiveness against opponents + * If there are multiple opponents, the highest effectiveness' color is returned + * @returns A color or undefined if the default color should be used + */ + private getMoveColor(pokemon: Pokemon, pokemonMove: PokemonMove): string | undefined { + if (!this.scene.typeHints) { + return undefined; + } + + const opponents = pokemon.getOpponents(); + if (opponents.length <= 0) { + return undefined; + } + + const moveColors = opponents.map((opponent) => { + return opponent.getMoveEffectiveness(pokemon, pokemonMove); + }).sort((a, b) => b - a).map((effectiveness) => { + return getTypeDamageMultiplierColor(effectiveness, "offense"); + }); + + return moveColors[0]; + } + clear() { super.clear(); this.clearMoves(); @@ -222,6 +287,11 @@ export default class FightUiHandler extends UiHandler { clearMoves() { this.movesContainer.removeAll(true); + + const opponents = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getOpponents(); + opponents.forEach((opponent) => { + opponent.updateEffectiveness(undefined); + }); } eraseCursor() { diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index eda36919d3b..57a02257810 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -89,7 +89,7 @@ const displayStats: DisplayStats = { }, highestMoney: { label_key: "highestMoney", - sourceFunc: gameData => Utils.formatFancyLargeNumber(gameData.gameStats.highestMoney, 3), + sourceFunc: gameData => Utils.formatFancyLargeNumber(gameData.gameStats.highestMoney), }, highestDamage: { label_key: "highestDamage", diff --git a/src/ui/loading-modal-ui-handler.ts b/src/ui/loading-modal-ui-handler.ts index c0d0ff9067b..c335b59de9f 100644 --- a/src/ui/loading-modal-ui-handler.ts +++ b/src/ui/loading-modal-ui-handler.ts @@ -1,3 +1,4 @@ +import i18next from "i18next"; import BattleScene from "../battle-scene"; import { ModalUiHandler } from "./modal-ui-handler"; import { addTextObject, TextStyle } from "./text"; @@ -31,7 +32,7 @@ export default class LoadingModalUiHandler extends ModalUiHandler { setup(): void { super.setup(); - const label = addTextObject(this.scene, this.getWidth() / 2, this.getHeight() / 2, "Loading…", TextStyle.WINDOW); + const label = addTextObject(this.scene, this.getWidth() / 2, this.getHeight() / 2, i18next.t("menu:loading"), TextStyle.WINDOW); label.setOrigin(0.5, 0.5); this.modalContainer.add(label); diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 61941c28b2c..9a17f6e344d 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -9,6 +9,7 @@ import { handleTutorial, Tutorial } from "../tutorial"; import {Button} from "../enums/buttons"; import MoveInfoOverlay from "./move-info-overlay"; import { allMoves } from "../data/move"; +import * as Utils from "./../utils"; export const SHOP_OPTIONS_ROW_LIMIT = 6; @@ -17,6 +18,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { private rerollButtonContainer: Phaser.GameObjects.Container; private lockRarityButtonContainer: Phaser.GameObjects.Container; private transferButtonContainer: Phaser.GameObjects.Container; + private checkButtonContainer: Phaser.GameObjects.Container; private rerollCostText: Phaser.GameObjects.Text; private lockRarityButtonText: Phaser.GameObjects.Text; private moveInfoOverlay : MoveInfoOverlay; @@ -44,7 +46,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { this.modifierContainer = this.scene.add.container(0, 0); ui.add(this.modifierContainer); - this.transferButtonContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 1, -64); + this.transferButtonContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 71, -64); this.transferButtonContainer.setName("container-transfer-btn"); this.transferButtonContainer.setVisible(false); ui.add(this.transferButtonContainer); @@ -54,6 +56,16 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { transferButtonText.setOrigin(1, 0); this.transferButtonContainer.add(transferButtonText); + this.checkButtonContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 1, -64); + this.checkButtonContainer.setName("container-use-btn"); + this.checkButtonContainer.setVisible(false); + ui.add(this.checkButtonContainer); + + const checkButtonText = addTextObject(this.scene, -4, -2, "Check Team", TextStyle.PARTY); + checkButtonText.setName("text-use-btn"); + checkButtonText.setOrigin(1, 0); + this.checkButtonContainer.add(checkButtonText); + this.rerollButtonContainer = this.scene.add.container(16, -64); this.rerollButtonContainer.setName("container-reroll-brn"); this.rerollButtonContainer.setVisible(false); @@ -120,6 +132,9 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { this.transferButtonContainer.setVisible(false); this.transferButtonContainer.setAlpha(0); + this.checkButtonContainer.setVisible(false); + this.checkButtonContainer.setAlpha(0); + this.rerollButtonContainer.setVisible(false); this.rerollButtonContainer.setAlpha(0); @@ -203,12 +218,14 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { } this.rerollButtonContainer.setAlpha(0); + this.checkButtonContainer.setAlpha(0); this.lockRarityButtonContainer.setAlpha(0); this.rerollButtonContainer.setVisible(true); + this.checkButtonContainer.setVisible(true); this.lockRarityButtonContainer.setVisible(canLockRarities); this.scene.tweens.add({ - targets: [ this.rerollButtonContainer, this.lockRarityButtonContainer ], + targets: [ this.rerollButtonContainer, this.lockRarityButtonContainer, this.checkButtonContainer ], alpha: 1, duration: 250 }); @@ -266,7 +283,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { } else { switch (button) { case Button.UP: - if (!this.rowCursor && this.cursor === 2) { + if (this.rowCursor === 0 && this.cursor === 3) { success = this.setCursor(0); } else if (this.rowCursor < this.shopOptionsRows.length + 1) { success = this.setRowCursor(this.rowCursor + 1); @@ -275,13 +292,29 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { case Button.DOWN: if (this.rowCursor) { success = this.setRowCursor(this.rowCursor - 1); - } else if (this.lockRarityButtonContainer.visible && !this.cursor) { - success = this.setCursor(2); + } else if (this.lockRarityButtonContainer.visible && this.cursor === 0) { + success = this.setCursor(3); } break; case Button.LEFT: if (!this.rowCursor) { - success = this.cursor === 1 && this.rerollButtonContainer.visible && this.setCursor(0); + switch (this.cursor) { + case 0: + success = false; + break; + case 1: + success = this.rerollButtonContainer.visible && this.setCursor(0); + break; + case 2: + if (this.transferButtonContainer.visible) { + success = this.setCursor(1); + } else if (this.rerollButtonContainer.visible) { + success = this.setCursor(0); + } else { + success = false; + } + break; + } } else if (this.cursor) { success = this.setCursor(this.cursor - 1); } else if (this.rowCursor === 1 && this.rerollButtonContainer.visible) { @@ -290,7 +323,21 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { break; case Button.RIGHT: if (!this.rowCursor) { - success = this.cursor !== 1 && this.transferButtonContainer.visible && this.setCursor(1); + switch (this.cursor) { + case 0: + if (this.transferButtonContainer.visible) { + success = this.setCursor(1); + } else { + success = this.setCursor(2); + } + break; + case 1: + success = this.setCursor(2); + break; + case 2: + success = false; + break; + } } else if (this.cursor < this.getRowItems(this.rowCursor) - 1) { success = this.setCursor(this.cursor + 1); } else if (this.rowCursor === 1 && this.transferButtonContainer.visible) { @@ -336,12 +383,15 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { // prepare the move overlay to be shown with the toggle this.moveInfoOverlay.show(allMoves[type.moveId]); } - } else if (!cursor) { + } else if (cursor === 0) { this.cursorObj.setPosition(6, this.lockRarityButtonContainer.visible ? -72 : -60); ui.showText("Spend money to reroll your item options."); } else if (cursor === 1) { - this.cursorObj.setPosition((this.scene.game.canvas.width / 6) - 50, -60); + this.cursorObj.setPosition((this.scene.game.canvas.width / 6) - 120, -60); ui.showText("Transfer a held item from one Pokémon to another."); + } else if (cursor === 2) { + this.cursorObj.setPosition((this.scene.game.canvas.width / 6) - 60, -60); + ui.showText("Check your team or use a form changing item."); } else { this.cursorObj.setPosition(6, -60); ui.showText("Lock item rarities on reroll (affects reroll cost)."); @@ -353,14 +403,15 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { setRowCursor(rowCursor: integer): boolean { const lastRowCursor = this.rowCursor; - if (rowCursor !== lastRowCursor && (rowCursor || this.rerollButtonContainer.visible || this.transferButtonContainer.visible)) { + if (rowCursor !== lastRowCursor) { this.rowCursor = rowCursor; let newCursor = Math.round(this.cursor / Math.max(this.getRowItems(lastRowCursor) - 1, 1) * (this.getRowItems(rowCursor) - 1)); - if (!rowCursor) { - if (!newCursor && !this.rerollButtonContainer.visible) { + if (rowCursor === 0) { + if (newCursor === 0 && !this.rerollButtonContainer.visible) { newCursor = 1; - } else if (newCursor && !this.transferButtonContainer.visible) { - newCursor = 0; + } + if (newCursor === 1 && !this.transferButtonContainer.visible) { + newCursor = 2; } } this.cursor = -1; @@ -374,7 +425,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { private getRowItems(rowCursor: integer): integer { switch (rowCursor) { case 0: - return 2; + return 3; case 1: return this.options.length; default: @@ -398,7 +449,9 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { updateRerollCostText(): void { const canReroll = this.scene.money >= this.rerollCost; - this.rerollCostText.setText(`₽${this.rerollCost.toLocaleString("en-US")}`); + const formattedMoney = Utils.formatMoney(this.scene.moneyFormat, this.rerollCost); + + this.rerollCostText.setText(`₽${formattedMoney}`); this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED)); this.rerollCostText.setShadowColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED, true)); } @@ -434,7 +487,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { onComplete: () => options.forEach(o => o.destroy()) }); - [ this.rerollButtonContainer, this.transferButtonContainer, this.lockRarityButtonContainer ].forEach(container => { + [ this.rerollButtonContainer, this.checkButtonContainer, this.transferButtonContainer, this.lockRarityButtonContainer ].forEach(container => { if (container.visible) { this.scene.tweens.add({ targets: container, @@ -656,7 +709,9 @@ class ModifierOption extends Phaser.GameObjects.Container { const scene = this.scene as BattleScene; const textStyle = this.modifierTypeOption.cost <= scene.money ? TextStyle.MONEY : TextStyle.PARTY_RED; - this.itemCostText.setText(`₽${this.modifierTypeOption.cost.toLocaleString("en-US")}`); + const formattedMoney = Utils.formatMoney(scene.moneyFormat, this.modifierTypeOption.cost); + + this.itemCostText.setText(`₽${formattedMoney}`); this.itemCostText.setColor(getTextColor(textStyle, false, scene.uiTheme)); this.itemCostText.setShadowColor(getTextColor(textStyle, true, scene.uiTheme)); } diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 425a9dd788d..d965345d3de 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,4 +1,4 @@ -import { CommandPhase } from "../phases"; +import { CommandPhase, SelectModifierPhase } from "../phases"; import BattleScene from "../battle-scene"; import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; @@ -17,6 +17,7 @@ import { addWindow } from "./ui-theme"; import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms"; import { getVariantTint } from "#app/data/variant"; import {Button} from "../enums/buttons"; +import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import MoveInfoOverlay from "./move-info-overlay"; import i18next from "i18next"; @@ -33,7 +34,8 @@ export enum PartyUiMode { REMEMBER_MOVE_MODIFIER, MODIFIER_TRANSFER, SPLICE, - RELEASE + RELEASE, + CHECK } export enum PartyOption { @@ -120,6 +122,20 @@ export default class PartyUiHandler extends MessageUiHandler { return null; }; + /** + * For consistency reasons, this looks like the above filters. However this is used only internally and is always enforced for switching. + * @param pokemon The pokemon to check. + * @returns + */ + private FilterChallengeLegal = (pokemon: PlayerPokemon) => { + const challengeAllowed = new Utils.BooleanHolder(true); + applyChallenges(this.scene.gameMode, ChallengeType.POKEMON_IN_BATTLE, pokemon, challengeAllowed); + if (!challengeAllowed.value) { + return `${pokemon.name} can't be used in\nthis challenge!`; + } + return null; + }; + private static FilterAllMoves = (_pokemonMove: PokemonMove) => null; public static FilterItemMaxStacks = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => { @@ -280,6 +296,9 @@ export default class PartyUiHandler extends MessageUiHandler { let filterResult: string; if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) { filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon); + if (filterResult === null && (option === PartyOption.SEND_OUT || option === PartyOption.PASS_BATON)) { + filterResult = this.FilterChallengeLegal(pokemon); + } if (filterResult === null && this.partyUiMode === PartyUiMode.MOVE_MODIFIER) { filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]); } @@ -293,7 +312,7 @@ export default class PartyUiHandler extends MessageUiHandler { if (this.partyUiMode !== PartyUiMode.SPLICE) { this.clearOptions(); } - if (this.selectCallback) { + if (this.selectCallback && this.partyUiMode !== PartyUiMode.CHECK) { if (option === PartyOption.TRANSFER) { if (this.transferCursor !== this.cursor) { (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.transferQuantities[this.transferOptionCursor], this.cursor); @@ -315,11 +334,8 @@ export default class PartyUiHandler extends MessageUiHandler { selectCallback(this.cursor, option); } } else { - if (option >= PartyOption.FORM_CHANGE_ITEM && this.scene.getCurrentPhase() instanceof CommandPhase) { - switch (this.partyUiMode) { - case PartyUiMode.SWITCH: - case PartyUiMode.FAINT_SWITCH: - case PartyUiMode.POST_BATTLE_SWITCH: + if (option >= PartyOption.FORM_CHANGE_ITEM && this.scene.getCurrentPhase() instanceof SelectModifierPhase) { + if (this.partyUiMode === PartyUiMode.CHECK) { let formChangeItemModifiers = this.scene.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]; if (formChangeItemModifiers.find(m => m.active)) { formChangeItemModifiers = formChangeItemModifiers.filter(m => m.active); @@ -327,7 +343,6 @@ export default class PartyUiHandler extends MessageUiHandler { const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM]; modifier.active = !modifier.active; this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger, false, true); - break; } } else if (this.cursor) { (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, this.cursor, option === PartyOption.PASS_BATON); @@ -373,7 +388,7 @@ export default class PartyUiHandler extends MessageUiHandler { } else if (option === PartyOption.RELEASE) { this.clearOptions(); ui.playSelect(); - if (this.cursor >= this.scene.currentBattle.getBattlerCount()) { + if (this.cursor >= this.scene.currentBattle.getBattlerCount() || !pokemon.isAllowedInBattle()) { this.showText(`Do you really want to release ${pokemon.name}?`, null, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => { ui.setMode(Mode.PARTY); @@ -690,15 +705,6 @@ export default class PartyUiHandler extends MessageUiHandler { this.options.push(PartyOption.PASS_BATON); } } - if (this.scene.getCurrentPhase() instanceof CommandPhase) { - formChangeItemModifiers = this.scene.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]; - if (formChangeItemModifiers.find(m => m.active)) { - formChangeItemModifiers = formChangeItemModifiers.filter(m => m.active); - } - for (let i = 0; i < formChangeItemModifiers.length; i++) { - this.options.push(PartyOption.FORM_CHANGE_ITEM + i); - } - } break; case PartyUiMode.REVIVAL_BLESSING: this.options.push(PartyOption.REVIVE); @@ -724,6 +730,17 @@ export default class PartyUiHandler extends MessageUiHandler { case PartyUiMode.RELEASE: this.options.push(PartyOption.RELEASE); break; + case PartyUiMode.CHECK: + if (this.scene.getCurrentPhase() instanceof SelectModifierPhase) { + formChangeItemModifiers = this.scene.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]; + if (formChangeItemModifiers.find(m => m.active)) { + formChangeItemModifiers = formChangeItemModifiers.filter(m => m.active); + } + for (let i = 0; i < formChangeItemModifiers.length; i++) { + this.options.push(PartyOption.FORM_CHANGE_ITEM + i); + } + } + break; } this.options.push(PartyOption.SUMMARY); diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 1ffa32d2394..f28cf2e8a48 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -6,6 +6,7 @@ import { getNatureName } from "../data/nature"; import { Type } from "../data/type"; import Pokemon from "../field/pokemon"; import i18next from "../plugins/i18n"; +import { DexAttr } from "../system/game-data"; import * as Utils from "../utils"; import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; @@ -39,7 +40,7 @@ const languageSettings: { [key: string]: LanguageSetting } = { }, "pt": { infoContainerTextSize: "60px", - infoContainerLabelXPos: -16, + infoContainerLabelXPos: -15, infoContainerTextXPos: -12, }, }; @@ -47,19 +48,24 @@ const languageSettings: { [key: string]: LanguageSetting } = { export default class PokemonInfoContainer extends Phaser.GameObjects.Container { private readonly infoWindowWidth = 104; - private pokemonGenderLabelText: Phaser.GameObjects.Text; + private pokemonFormLabelText: Phaser.GameObjects.Text; + private pokemonFormText: Phaser.GameObjects.Text; private pokemonGenderText: Phaser.GameObjects.Text; + private pokemonGenderNewText: Phaser.GameObjects.Text; private pokemonAbilityLabelText: Phaser.GameObjects.Text; private pokemonAbilityText: Phaser.GameObjects.Text; private pokemonNatureLabelText: Phaser.GameObjects.Text; private pokemonNatureText: BBCodeText; private pokemonShinyIcon: Phaser.GameObjects.Image; + private pokemonShinyNewIcon: Phaser.GameObjects.Text; private pokemonFusionShinyIcon: Phaser.GameObjects.Image; private pokemonMovesContainer: Phaser.GameObjects.Container; private pokemonMovesContainers: Phaser.GameObjects.Container[]; private pokemonMoveBgs: Phaser.GameObjects.NineSlice[]; private pokemonMoveLabels: Phaser.GameObjects.Text[]; + private numCharsBeforeCutoff = 16; + private initialX: number; private movesContainerInitialX: number; @@ -137,34 +143,44 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { // The font size should be set by language const infoContainerTextSize = textSettings?.infoContainerTextSize || "64px"; - this.pokemonGenderLabelText = addTextObject(this.scene, infoContainerLabelXPos, 18, i18next.t("pokemonInfoContainer:gender"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); - this.pokemonGenderLabelText.setOrigin(1, 0); - this.pokemonGenderLabelText.setVisible(false); - this.pokemonGenderLabelText.setName("text-pkmn-gender-label"); - this.add(this.pokemonGenderLabelText); + this.pokemonFormLabelText = addTextObject(this.scene, infoContainerLabelXPos, 19, i18next.t("pokemonInfoContainer:form"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonFormLabelText.setOrigin(1, 0); + this.pokemonFormLabelText.setVisible(false); + this.add(this.pokemonFormLabelText); - this.pokemonGenderText = addTextObject(this.scene, infoContainerTextXPos, 18, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonFormText = addTextObject(this.scene, infoContainerTextXPos, 19, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonFormText.setOrigin(0, 0); + this.pokemonFormText.setVisible(false); + this.add(this.pokemonFormText); + + this.pokemonGenderText = addTextObject(this.scene, -42, -61, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); this.pokemonGenderText.setOrigin(0, 0); this.pokemonGenderText.setVisible(false); this.pokemonGenderText.setName("text-pkmn-gender"); this.add(this.pokemonGenderText); - this.pokemonAbilityLabelText = addTextObject(this.scene, infoContainerLabelXPos, 28, i18next.t("pokemonInfoContainer:ability"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonGenderNewText = addTextObject(this.scene, -36, -61, "", TextStyle.WINDOW, { fontSize: "64px" }); + this.pokemonGenderNewText.setOrigin(0, 0); + this.pokemonGenderNewText.setVisible(false); + this.pokemonGenderNewText.setName("text-pkmn-new-gender"); + this.add(this.pokemonGenderNewText); + + this.pokemonAbilityLabelText = addTextObject(this.scene, infoContainerLabelXPos, 29, i18next.t("pokemonInfoContainer:ability"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); this.pokemonAbilityLabelText.setOrigin(1, 0); this.pokemonAbilityLabelText.setName("text-pkmn-ability-label"); this.add(this.pokemonAbilityLabelText); - this.pokemonAbilityText = addTextObject(this.scene, infoContainerTextXPos, 28, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonAbilityText = addTextObject(this.scene, infoContainerTextXPos, 29, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); this.pokemonAbilityText.setOrigin(0, 0); this.pokemonAbilityText.setName("text-pkmn-ability"); this.add(this.pokemonAbilityText); - this.pokemonNatureLabelText = addTextObject(this.scene, infoContainerLabelXPos, 38, i18next.t("pokemonInfoContainer:nature"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonNatureLabelText = addTextObject(this.scene, infoContainerLabelXPos, 39, i18next.t("pokemonInfoContainer:nature"), TextStyle.WINDOW, { fontSize: infoContainerTextSize }); this.pokemonNatureLabelText.setOrigin(1, 0); this.pokemonNatureLabelText.setName("text-pkmn-nature-label"); this.add(this.pokemonNatureLabelText); - this.pokemonNatureText = addBBCodeTextObject(this.scene, infoContainerTextXPos, 38, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize, lineSpacing: 3, maxLines: 2 }); + this.pokemonNatureText = addBBCodeTextObject(this.scene, infoContainerTextXPos, 39, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize, lineSpacing: 3, maxLines: 2 }); this.pokemonNatureText.setOrigin(0, 0); this.pokemonNatureText.setName("text-pkmn-nature"); this.add(this.pokemonNatureText); @@ -176,6 +192,12 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonShinyIcon.setName("img-pkmn-shiny-icon"); this.add(this.pokemonShinyIcon); + this.pokemonShinyNewIcon = addTextObject(this.scene, this.pokemonShinyIcon.x + 12, this.pokemonShinyIcon.y, "", TextStyle.WINDOW, { fontSize: infoContainerTextSize }); + this.pokemonShinyNewIcon.setOrigin(0, 0); + this.pokemonShinyNewIcon.setName("text-pkmn-shiny-new-icon"); + this.add(this.pokemonShinyNewIcon); + this.pokemonShinyNewIcon.setVisible(false); + this.pokemonFusionShinyIcon = this.scene.add.image(this.pokemonShinyIcon.x, this.pokemonShinyIcon.y, "shiny_star_2"); this.pokemonFusionShinyIcon.setOrigin(0, 0); this.pokemonFusionShinyIcon.setScale(0.75); @@ -187,23 +209,88 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { show(pokemon: Pokemon, showMoves: boolean = false, speedMultiplier: number = 1): Promise { return new Promise(resolve => { + const caughtAttr = BigInt(pokemon.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr); if (pokemon.gender > Gender.GENDERLESS) { this.pokemonGenderText.setText(getGenderSymbol(pokemon.gender)); this.pokemonGenderText.setColor(getGenderColor(pokemon.gender)); this.pokemonGenderText.setShadowColor(getGenderColor(pokemon.gender, true)); - this.pokemonGenderLabelText.setVisible(true); this.pokemonGenderText.setVisible(true); + + const newGender = BigInt(Math.pow(2, pokemon.gender)) * DexAttr.MALE; + this.pokemonGenderNewText.setText("(+)"); + this.pokemonGenderNewText.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonGenderNewText.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); + this.pokemonGenderNewText.setVisible((newGender & caughtAttr) === BigInt(0)); } else { + this.pokemonGenderNewText.setVisible(false); this.pokemonGenderText.setVisible(false); } + if (pokemon.species.forms?.[pokemon.formIndex]?.formName) { + this.pokemonFormLabelText.setVisible(true); + this.pokemonFormText.setVisible(true); + const newForm = BigInt(Math.pow(2, pokemon.formIndex)) * DexAttr.DEFAULT_FORM; + + if ((newForm & caughtAttr) === BigInt(0)) { + this.pokemonFormLabelText.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonFormLabelText.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); + } else { + this.pokemonFormLabelText.setColor(getTextColor(TextStyle.WINDOW, false, this.scene.uiTheme)); + this.pokemonFormLabelText.setShadowColor(getTextColor(TextStyle.WINDOW, true, this.scene.uiTheme)); + } + + const formName = pokemon.species.forms?.[pokemon.formIndex]?.formName; + this.pokemonFormText.setText(formName.length > this.numCharsBeforeCutoff ? formName.substring(0, this.numCharsBeforeCutoff - 3) + "..." : formName); + if (formName.length > this.numCharsBeforeCutoff) { + this.pokemonFormText.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.pokemonFormText.width, this.pokemonFormText.height), Phaser.Geom.Rectangle.Contains); + this.pokemonFormText.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, pokemon.species.forms?.[pokemon.formIndex]?.formName, true)); + this.pokemonFormText.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); + } else { + this.pokemonFormText.disableInteractive(); + } + } else { + this.pokemonFormLabelText.setVisible(false); + this.pokemonFormText.setVisible(false); + this.pokemonFormText.disableInteractive(); + } + const abilityTextStyle = pokemon.abilityIndex === (pokemon.species.ability2 ? 2 : 1) ? TextStyle.MONEY : TextStyle.WINDOW; this.pokemonAbilityText.setText(pokemon.getAbility(true).name); this.pokemonAbilityText.setColor(getTextColor(abilityTextStyle, false, this.scene.uiTheme)); this.pokemonAbilityText.setShadowColor(getTextColor(abilityTextStyle, true, this.scene.uiTheme)); + /** + * If the opposing Pokemon only has 1 normal ability and is using the hidden ability it should have the same behavior + * if it had 2 normal abilities. This code checks if that is the case and uses the correct opponent Pokemon abilityIndex (2) + * for calculations so it aligns with where the hidden ability is stored in the starter data's abilityAttr (4) + */ + const opponentPokemonOneNormalAbility = (pokemon.species.getAbilityCount() === 2); + const opponentPokemonAbilityIndex = (opponentPokemonOneNormalAbility && pokemon.abilityIndex === 1) ? 2 : pokemon.abilityIndex; + const opponentPokemonAbilityAttr = Math.pow(2, opponentPokemonAbilityIndex); + + const rootFormHasHiddenAbility = pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr & opponentPokemonAbilityAttr; + + if (!rootFormHasHiddenAbility) { + this.pokemonAbilityLabelText.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonAbilityLabelText.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); + } else { + this.pokemonAbilityLabelText.setColor(getTextColor(TextStyle.WINDOW, false, this.scene.uiTheme)); + this.pokemonAbilityLabelText.setShadowColor(getTextColor(TextStyle.WINDOW, true, this.scene.uiTheme)); + } + this.pokemonNatureText.setText(getNatureName(pokemon.getNature(), true, false, false, this.scene.uiTheme)); + const dexNatures = pokemon.scene.gameData.dexData[pokemon.species.speciesId].natureAttr; + const newNature = Math.pow(2, pokemon.nature + 1); + + if (!(dexNatures & newNature)) { + this.pokemonNatureLabelText.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonNatureLabelText.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); + } else { + this.pokemonNatureLabelText.setColor(getTextColor(TextStyle.WINDOW, false, this.scene.uiTheme)); + this.pokemonNatureLabelText.setShadowColor(getTextColor(TextStyle.WINDOW, true, this.scene.uiTheme)); + } + const isFusion = pokemon.isFusion(); const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; const baseVariant = !doubleShiny ? pokemon.getVariant() : pokemon.variant; @@ -217,6 +304,17 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { : ""; this.pokemonShinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `Shiny${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, true)); this.pokemonShinyIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); + + const newShiny = BigInt(Math.pow(2, (pokemon.shiny ? 1 : 0))); + const newVariant = BigInt(Math.pow(2, pokemon.variant + 4)); + + this.pokemonShinyNewIcon.setText("(+)"); + this.pokemonShinyNewIcon.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonShinyNewIcon.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); + const newShinyOrVariant = ((newShiny & caughtAttr) === BigInt(0)) || ((newVariant & caughtAttr) === BigInt(0)); + this.pokemonShinyNewIcon.setVisible(!!newShinyOrVariant); + } else { + this.pokemonShinyNewIcon.setVisible(false); } this.pokemonFusionShinyIcon.setPosition(this.pokemonShinyIcon.x, this.pokemonShinyIcon.y); diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index d5dda05a519..e5417f83596 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -1,15 +1,15 @@ +import i18next from "i18next"; import BattleScene from "../battle-scene"; -import { gameModes } from "../game-mode"; +import { Button } from "../enums/buttons"; +import { GameMode } from "../game-mode"; +import { PokemonHeldItemModifier } from "../modifier/modifier"; import { SessionSaveData } from "../system/game-data"; +import PokemonData from "../system/pokemon-data"; +import * as Utils from "../utils"; +import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; -import PokemonData from "../system/pokemon-data"; -import { PokemonHeldItemModifier } from "../modifier/modifier"; -import MessageUiHandler from "./message-ui-handler"; -import i18next from "i18next"; -import {Button} from "../enums/buttons"; const sessionSlotCount = 5; @@ -118,7 +118,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { originalCallback(cursor); }; if (this.sessionSlots[cursor].hasData) { - ui.showText("Overwrite the data in the selected slot?", null, () => { + ui.showText(i18next.t("saveSlotSelectUiHandler:overwriteData"), null, () => { ui.setOverlayMode(Mode.CONFIRM, () => saveAndCallback(), () => { ui.revertMode(); ui.showText(null, 0); @@ -258,7 +258,7 @@ class SessionSlot extends Phaser.GameObjects.Container { const slotWindow = addWindow(this.scene, 0, 0, 304, 52); this.add(slotWindow); - this.loadingLabel = addTextObject(this.scene, 152, 26, "Loading…", TextStyle.WINDOW); + this.loadingLabel = addTextObject(this.scene, 152, 26, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW); this.loadingLabel.setOrigin(0.5, 0.5); this.add(this.loadingLabel); } @@ -266,7 +266,7 @@ class SessionSlot extends Phaser.GameObjects.Container { async setupWithData(data: SessionSaveData) { this.remove(this.loadingLabel, true); - const gameModeLabel = addTextObject(this.scene, 8, 5, `${gameModes[data.gameMode]?.getName() || "Unknown"} - Wave ${data.waveIndex}`, TextStyle.WINDOW); + const gameModeLabel = addTextObject(this.scene, 8, 5, `${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unkown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`, TextStyle.WINDOW); this.add(gameModeLabel); const timestampLabel = addTextObject(this.scene, 8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW); @@ -283,7 +283,7 @@ class SessionSlot extends Phaser.GameObjects.Container { const pokemon = p.toPokemon(this.scene); const icon = this.scene.addPokemonIcon(pokemon, 0, 0, 0, 0); - const text = addTextObject(this.scene, 32, 20, `Lv${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }); + const text = addTextObject(this.scene, 32, 20, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }); text.setShadow(0, 0, null); text.setStroke("#424242", 14); text.setOrigin(1, 0); @@ -324,7 +324,7 @@ class SessionSlot extends Phaser.GameObjects.Container { this.scene.gameData.getSession(this.slotId).then(async sessionData => { if (!sessionData) { this.hasData = false; - this.loadingLabel.setText(i18next.t("menu:empty")); + this.loadingLabel.setText(i18next.t("saveSlotSelectUiHandler:empty")); resolve(false); return; } diff --git a/src/ui/settings/settings-display-ui-handler.ts b/src/ui/settings/settings-display-ui-handler.ts index 9e61c2ba0b2..0aed0689388 100644 --- a/src/ui/settings/settings-display-ui-handler.ts +++ b/src/ui/settings/settings-display-ui-handler.ts @@ -2,7 +2,7 @@ import BattleScene from "../../battle-scene"; import { Mode } from "../ui"; "#app/inputs-controller.js"; import AbstractSettingsUiHandler from "./abstract-settings-ui-handler"; -import { Setting, SettingType } from "#app/system/settings/settings"; +import { Setting, SettingKeys, SettingType } from "#app/system/settings/settings"; export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler { /** @@ -15,6 +15,48 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler super(scene, mode); this.title = "Display"; this.settings = Setting.filter(s => s.type === SettingType.DISPLAY); + + /** + * Update to current language from default value. + * - default value is 'English' + */ + const languageIndex = this.settings.findIndex(s => s.key === SettingKeys.Language); + if (languageIndex >= 0) { + const currentLocale = localStorage.getItem("prLang"); + switch (currentLocale) { + case "en": + this.settings[languageIndex].options[0] = "English"; + break; + case "es": + this.settings[languageIndex].options[0] = "Español"; + break; + case "it": + this.settings[languageIndex].options[0] = "Italiano"; + break; + case "fr": + this.settings[languageIndex].options[0] = "Français"; + break; + case "de": + this.settings[languageIndex].options[0] = "Deutsch"; + break; + case "pt-BR": + this.settings[languageIndex].options[0] = "Português (BR)"; + break; + case "zh-CN": + this.settings[languageIndex].options[0] = "简体中文"; + break; + case "zh-TW": + this.settings[languageIndex].options[0] = "繁體中文"; + break; + case "ko": + this.settings[languageIndex].options[0] = "한국어"; + break; + default: + this.settings[languageIndex].options[0] = "English"; + break; + } + } + this.localStorageKey = "settings"; } } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index ece05574837..d318fd3f967 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1,4 +1,4 @@ -import { BattleSceneEventType, CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js"; +import { BattleSceneEventType, CandyUpgradeNotificationChangedEvent } from "../events/battle-scene"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; import { argbFromRgba } from "@material/material-color-utilities"; @@ -18,8 +18,8 @@ import { LevelMoves, pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "../ import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { Type } from "../data/type"; import { Button } from "../enums/buttons"; -import { GameModes, gameModes } from "../game-mode"; -import { TitlePhase } from "../phases"; +import { GameModes } from "../game-mode"; +import { SelectChallengePhase, TitlePhase } from "../phases"; import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterFormMoveData, StarterMoveset } from "../system/game-data"; import { Passive as PassiveAttr } from "#app/data/enums/passive"; import { Tutorial, handleTutorial } from "../tutorial"; @@ -31,7 +31,11 @@ import { StatsContainer } from "./stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import {SettingKeyboard} from "#app/system/settings/settings-keyboard"; +import {Device} from "#app/enums/devices"; +import * as Challenge from "../data/challenge"; import MoveInfoOverlay from "./move-info-overlay"; +import { getEggTierForSpecies } from "#app/data/egg.js"; export type StarterSelectCallback = (starters: Starter[]) => void; @@ -55,7 +59,7 @@ interface LanguageSetting { const languageSettings: { [key: string]: LanguageSetting } = { "en":{ starterInfoTextSize: "56px", - instructionTextSize: "42px", + instructionTextSize: "38px", }, "de":{ starterInfoTextSize: "56px", @@ -186,9 +190,24 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private pokemonCandyCountText: Phaser.GameObjects.Text; private pokemonCaughtHatchedContainer: Phaser.GameObjects.Container; private pokemonCaughtCountText: Phaser.GameObjects.Text; + private pokemonHatchedIcon : Phaser.GameObjects.Sprite; private pokemonHatchedCountText: Phaser.GameObjects.Text; private genOptionsText: Phaser.GameObjects.Text; - private instructionsText: Phaser.GameObjects.Text; + + private instructionsContainer: Phaser.GameObjects.Container; + private shinyIconElement: Phaser.GameObjects.Sprite; + private formIconElement: Phaser.GameObjects.Sprite; + private abilityIconElement: Phaser.GameObjects.Sprite; + private genderIconElement: Phaser.GameObjects.Sprite; + private natureIconElement: Phaser.GameObjects.Sprite; + private variantIconElement: Phaser.GameObjects.Sprite; + private shinyLabel: Phaser.GameObjects.Text; + private formLabel: Phaser.GameObjects.Text; + private genderLabel: Phaser.GameObjects.Text; + private abilityLabel: Phaser.GameObjects.Text; + private natureLabel: Phaser.GameObjects.Text; + private variantLabel: Phaser.GameObjects.Text; + private starterSelectMessageBox: Phaser.GameObjects.NineSlice; private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; private statsContainer: StatsContainer; @@ -244,8 +263,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private iconAnimHandler: PokemonIconAnimHandler; + //variables to keep track of the dynamically rendered list of instruction prompts for starter select + private instructionRowX = 0; + private instructionRowY = 0; + private instructionRowTextOffset = 12; + private starterSelectCallback: StarterSelectCallback; - private gameMode: GameModes; protected blockInput: boolean = false; @@ -577,10 +600,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCaughtCountText.setOrigin(0, 0); this.pokemonCaughtHatchedContainer.add(this.pokemonCaughtCountText); - const pokemonHatchedIcon = this.scene.add.sprite(1, 14, "items", "mystery_egg"); - pokemonHatchedIcon.setOrigin(0, 0); - pokemonHatchedIcon.setScale(0.75); - this.pokemonCaughtHatchedContainer.add(pokemonHatchedIcon); + this.pokemonHatchedIcon = this.scene.add.sprite(1, 14, "egg_icons"); + this.pokemonHatchedIcon.setOrigin(0.15, 0.2); + this.pokemonHatchedIcon.setScale(0.8); + this.pokemonCaughtHatchedContainer.add(this.pokemonHatchedIcon); this.pokemonHatchedCountText = addTextObject(this.scene, 24, 19, "0", TextStyle.SUMMARY_ALT); this.pokemonHatchedCountText.setOrigin(0, 0); @@ -648,8 +671,42 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // The font size should be set per language const instructionTextSize = textSettings.instructionTextSize; - this.instructionsText = addTextObject(this.scene, 4, 156, "", TextStyle.PARTY, { fontSize: instructionTextSize }); - this.starterSelectContainer.add(this.instructionsText); + this.instructionsContainer = this.scene.add.container(4, 156); + this.instructionsContainer.setVisible(true); + this.starterSelectContainer.add(this.instructionsContainer); + + // instruction rows that will be pushed into the container dynamically based on need + this.shinyIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "R.png"); + this.shinyIconElement.setScale(0.675); + this.shinyIconElement.setOrigin(0.0, 0.0); + this.shinyLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleShiny"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.formIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "F.png"); + this.formIconElement.setScale(0.675); + this.formIconElement.setOrigin(0.0, 0.0); + this.formLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleForm"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.genderIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "G.png"); + this.genderIconElement.setScale(0.675); + this.genderIconElement.setOrigin(0.0, 0.0); + this.genderLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleGender"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.abilityIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "E.png"); + this.abilityIconElement.setScale(0.675); + this.abilityIconElement.setOrigin(0.0, 0.0); + this.abilityLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleAbility"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.natureIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "N.png"); + this.natureIconElement.setScale(0.675); + this.natureIconElement.setOrigin(0.0, 0.0); + this.natureLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleNature"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.variantIconElement = this.scene.add.sprite(this.instructionRowX, this.instructionRowY, "keyboard", "V.png"); + this.variantIconElement.setScale(0.675); + this.variantIconElement.setOrigin(0.0, 0.0); + this.variantLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleVariant"), TextStyle.PARTY, { fontSize: instructionTextSize }); + + this.hideInstructions(); this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); this.starterSelectMessageBoxContainer.setVisible(false); @@ -724,14 +781,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { show(args: any[]): boolean { this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers - if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") { + if (args.length >= 1 && args[0] instanceof Function) { super.show(args); this.starterSelectCallback = args[0] as StarterSelectCallback; this.starterSelectContainer.setVisible(true); - this.gameMode = args[1]; - this.setGenMode(false); this.setCursor(0); this.setGenMode(true); @@ -957,7 +1012,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } else { this.blockInput = true; this.scene.clearPhaseQueue(); - this.scene.pushPhase(new TitlePhase(this.scene)); + if (this.scene.gameMode.isChallenge) { + this.scene.pushPhase(new SelectChallengePhase(this.scene)); + } else { + this.scene.pushPhase(new TitlePhase(this.scene)); + } this.scene.getCurrentPhase().end(); success = true; } @@ -1029,7 +1088,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } const species = this.genSpecies[this.getGenCursorWithScroll()][this.cursor]; - if (!isDupe && this.tryUpdateValue(this.scene.gameData.getSpeciesStarterValue(species.speciesId))) { + + const isValidForChallenge = new Utils.BooleanHolder(true); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge); + + if (!isDupe && isValidForChallenge.value && this.tryUpdateValue(this.scene.gameData.getSpeciesStarterValue(species.speciesId))) { const cursorObj = this.starterCursorObjs[this.starterCursors.length]; cursorObj.setVisible(true); cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y); @@ -1479,55 +1542,98 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined, false); } + updateButtonIcon(iconSetting, gamepadType, iconElement, controlLabel): void { + let iconPath; + // touch controls cannot be rebound as is, and are just emulating a keyboard event. + // Additionally, since keyboard controls can be rebound (and will be displayed when they are), we need to have special handling for the touch controls + if (gamepadType === "touch") { + gamepadType = "keyboard"; + switch (iconSetting) { + case SettingKeyboard.Button_Cycle_Shiny: + iconPath = "R.png"; + break; + case SettingKeyboard.Button_Cycle_Form: + iconPath = "F.png"; + break; + case SettingKeyboard.Button_Cycle_Gender: + iconPath = "G.png"; + break; + case SettingKeyboard.Button_Cycle_Ability: + iconPath = "E.png"; + break; + case SettingKeyboard.Button_Cycle_Nature: + iconPath = "N.png"; + break; + case SettingKeyboard.Button_Cycle_Variant: + iconPath = "V.png"; + break; + default: + break; + } + } else { + iconPath = this.scene.inputController?.getIconForLatestInputRecorded(iconSetting); + } + iconElement.setTexture(gamepadType, iconPath); + iconElement.setPosition(this.instructionRowX, this.instructionRowY); + controlLabel.setPosition(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY); + iconElement.setVisible(true); + controlLabel.setVisible(true); + this.instructionsContainer.add([iconElement, controlLabel]); + this.instructionRowY += 8; + if (this.instructionRowY >= 24) { + this.instructionRowY = 0; + this.instructionRowX += 50; + } + } + updateInstructions(): void { - const instructionLines = [ ]; - const cycleInstructionLines = []; + this.instructionRowX = 0; + this.instructionRowY = 0; + this.hideInstructions(); + this.instructionsContainer.removeAll(); + let gamepadType; + if (this.scene.inputMethod === "gamepad") { + gamepadType = this.scene.inputController.getConfig(this.scene.inputController.selectedDevice[Device.GAMEPAD]).padType; + } else { + gamepadType = this.scene.inputMethod; + } + if (this.speciesStarterDexEntry?.caughtAttr) { if (this.canCycleShiny) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleShiny")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Shiny, gamepadType, this.shinyIconElement, this.shinyLabel); } if (this.canCycleForm) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleForm")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Form, gamepadType, this.formIconElement, this.formLabel); } if (this.canCycleGender) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleGender")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Gender, gamepadType, this.genderIconElement, this.genderLabel); } if (this.canCycleAbility) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleAbility")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Ability, gamepadType, this.abilityIconElement, this.abilityLabel); } if (this.canCycleNature) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleNature")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Nature, gamepadType, this.natureIconElement, this.natureLabel); } if (this.canCycleVariant) { - cycleInstructionLines.push(i18next.t("starterSelectUiHandler:cycleVariant")); + this.updateButtonIcon(SettingKeyboard.Button_Cycle_Variant, gamepadType, this.variantIconElement, this.variantLabel); } } - - if (cycleInstructionLines.length > 2) { - cycleInstructionLines[0] += " | " + cycleInstructionLines.splice(1, 1); - if (cycleInstructionLines.length > 2) { - cycleInstructionLines[1] += " | " + cycleInstructionLines.splice(2, 1); - } - if (cycleInstructionLines.length > 2) { - cycleInstructionLines[2] += " | " + cycleInstructionLines.splice(3, 1); - } - } - - for (const cil of cycleInstructionLines) { - instructionLines.push(cil); - } - - this.instructionsText.setText(instructionLines.join("\n")); } getValueLimit(): integer { - switch (this.gameMode) { + const valueLimit = new Utils.IntegerHolder(0); + switch (this.scene.gameMode.modeId) { case GameModes.ENDLESS: case GameModes.SPLICED_ENDLESS: - return 15; + valueLimit.value = 15; + break; default: - return 10; + valueLimit.value = 10; } + + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_POINTS, valueLimit); + + return valueLimit.value; } setCursor(cursor: integer): boolean { @@ -1718,11 +1824,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonPassiveLabelText.setVisible(true); this.pokemonNatureLabelText.setVisible(true); this.pokemonCaughtCountText.setText(`${this.speciesStarterDexEntry.caughtCount}`); + if (species.speciesId === Species.MANAPHY || species.speciesId === Species.PHIONE) { + this.pokemonHatchedIcon.setFrame("manaphy"); + } else { + this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species)); + } this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`); this.pokemonCaughtHatchedContainer.setVisible(true); if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) { this.pokemonCaughtHatchedContainer.setY(16); - [ this.pokemonCandyIcon, this.pokemonCandyOverlayIcon, this.pokemonCandyDarknessOverlay, this.pokemonCandyCountText ].map(c => c.setVisible(false)); + [ + this.pokemonCandyIcon, + this.pokemonCandyOverlayIcon, + this.pokemonCandyDarknessOverlay, + this.pokemonCandyCountText, + this.pokemonHatchedIcon, + this.pokemonHatchedCountText + ].map(c => c.setVisible(false)); + } else if (species.speciesId === Species.ETERNATUS) { + this.pokemonHatchedIcon.setVisible(false); + this.pokemonHatchedCountText.setVisible(false); } else { this.pokemonCaughtHatchedContainer.setY(25); this.pokemonCandyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); @@ -1733,6 +1854,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`); this.pokemonCandyCountText.setVisible(true); this.pokemonFormText.setVisible(true); + this.pokemonHatchedIcon.setVisible(true); + this.pokemonHatchedCountText.setVisible(true); let currentFriendship = this.scene.gameData.starterData[this.lastSpecies.speciesId].friendship; if (!currentFriendship || currentFriendship === undefined) { @@ -2160,20 +2283,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const speciesSprite = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite; /** - * If remainValue greater than or equal pokemon species, the user can select. + * If remainValue greater than or equal pokemon species and the pokemon is legal for this challenge, the user can select. * so that the alpha value of pokemon sprite set 1. * * If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater. * we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too. */ - if (remainValue >= speciesStarterValue) { + const isValidForChallenge = new Utils.BooleanHolder(true); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.genSpecies[g][s], isValidForChallenge); + + const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge.value; + + if (canBeChosen) { speciesSprite.setAlpha(1); if (speciesStarterDexEntry?.caughtAttr) { this.canAddParty = true; } } else { /** - * If remainValue less than pokemon, the use can't select. + * If it can't be chosen, the user can't select. * so that the alpha value of pokemon sprite set 0.375. */ speciesSprite.setAlpha(0.375); @@ -2202,8 +2330,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ui.showText(i18next.t("starterSelectUiHandler:confirmStartTeam"), null, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => { - const startRun = (gameMode: GameModes) => { - this.scene.gameMode = gameModes[gameMode]; + const startRun = () => { this.scene.money = this.scene.gameMode.getStartingMoney(); ui.setMode(Mode.STARTER_SELECT); const thisObj = this; @@ -2222,7 +2349,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }; })); }; - startRun(this.gameMode); + startRun(); }, cancel, null, null, 19); }); @@ -2260,9 +2387,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler { super.clearText(); } + hideInstructions(): void { + this.shinyIconElement.setVisible(false); + this.shinyLabel.setVisible(false); + this.formIconElement.setVisible(false); + this.formLabel.setVisible(false); + this.genderIconElement.setVisible(false); + this.genderLabel.setVisible(false); + this.abilityIconElement.setVisible(false); + this.abilityLabel.setVisible(false); + this.natureIconElement.setVisible(false); + this.natureLabel.setVisible(false); + this.variantIconElement.setVisible(false); + this.variantLabel.setVisible(false); + } + clear(): void { super.clear(); this.cursor = -1; + this.hideInstructions(); this.starterSelectContainer.setVisible(false); this.blockInput = false; diff --git a/src/ui/stats-container.ts b/src/ui/stats-container.ts index 40879a77a1d..c19389afdbb 100644 --- a/src/ui/stats-container.ts +++ b/src/ui/stats-container.ts @@ -3,8 +3,12 @@ import BattleScene from "../battle-scene"; import { Stat, getStatName } from "../data/pokemon-stat"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; -const ivChartStatCoordMultipliers = [ [ 0, -1 ], [ 0.825, -0.5 ], [ 0.825, 0.5 ], [ -0.825, -0.5 ], [ -0.825, 0.5 ], [ 0, 1 ] ]; + const ivChartSize = 24; +const ivChartStatCoordMultipliers = [[0, -1], [0.825, -0.5], [0.825, 0.5], [-0.825, -0.5], [-0.825, 0.5], [0, 1]]; +const speedLabelOffset = -3; +const sideLabelOffset = 1; +const ivLabelOffset = [0, sideLabelOffset, -sideLabelOffset, sideLabelOffset, -sideLabelOffset, speedLabelOffset]; const ivChartStatIndexes = [0,1,2,5,4,3]; // swap special attack and speed const ivChartLabelxOffset= [0,7,8,-8,-8,0]; const ivChartLabelyOffset= [0,5,0,5,0,0]; // doing this so attack does not overlap with (+N) diff --git a/src/ui/text.ts b/src/ui/text.ts index 56e1b492dfa..715e4f02430 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -1,10 +1,11 @@ -import i18next from "i18next"; import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; import BattleScene from "../battle-scene"; import { EggTier } from "../data/enums/egg-type"; import { UiTheme } from "../enums/ui-theme"; import { ModifierTier } from "../modifier/modifier-tier"; +import Phaser from "phaser"; +import i18next from "i18next"; export enum TextStyle { MESSAGE, @@ -29,33 +30,18 @@ export enum TextStyle { SETTINGS_LOCKED, TOOLTIP_TITLE, TOOLTIP_CONTENT, - MOVE_INFO_CONTENT + MOVE_INFO_CONTENT, + MOVE_PP_FULL, + MOVE_PP_HALF_FULL, + MOVE_PP_NEAR_EMPTY, + MOVE_PP_EMPTY } -interface LanguageSetting { - summaryFontSize?: string, - battleInfoFontSize?: string, - partyFontSize?: string, - tooltipContentFontSize?: string, - moveInfoFontSize?: string, - textScale?: number -} - -const languageSettings: { [key: string]: LanguageSetting } = { - "en":{}, - "de":{}, - "es":{}, - "fr":{}, - "it":{}, - "pt_BR":{}, - "zh_CN":{}, -}; - export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text { - const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); + const [ scale, styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); const ret = scene.add.text(x, y, content, styleOptions); - ret.setScale(0.1666666667); + ret.setScale(scale); ret.setShadow(shadowXpos, shadowYpos, shadowColor); if (!(styleOptions as Phaser.Types.GameObjects.Text.TextStyle).lineSpacing) { ret.setLineSpacing(5); @@ -65,8 +51,8 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content } export function setTextStyle(obj: Phaser.GameObjects.Text, scene: Phaser.Scene, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) { - const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); - obj.setScale(0.1666666667); + const [ scale, styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); + obj.setScale(scale); obj.setShadow(shadowXpos, shadowYpos, shadowColor); if (!(styleOptions as Phaser.Types.GameObjects.Text.TextStyle).lineSpacing) { obj.setLineSpacing(5); @@ -74,11 +60,11 @@ export function setTextStyle(obj: Phaser.GameObjects.Text, scene: Phaser.Scene, } export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText { - const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); + const [ scale, styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); const ret = new BBCodeText(scene, x, y, content, styleOptions as BBCodeText.TextStyle); scene.add.existing(ret); - ret.setScale(0.1666666667); + ret.setScale(scale); ret.setShadow(shadowXpos, shadowYpos, shadowColor); if (!(styleOptions as BBCodeText.TextStyle).lineSpacing) { ret.setLineSpacing(10); @@ -88,23 +74,25 @@ export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, c } export function addTextInputObject(scene: Phaser.Scene, x: number, y: number, width: number, height: number, style: TextStyle, extraStyleOptions?: InputText.IConfig): InputText { - const [ styleOptions ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); + const [ scale, styleOptions ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions); const ret = new InputText(scene, x, y, width, height, styleOptions as InputText.IConfig); scene.add.existing(ret); - ret.setScale(0.1666666667); + ret.setScale(scale); return ret; } -function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ Phaser.Types.GameObjects.Text.TextStyle | InputText.IConfig, string, number, number ] { - const lang = i18next.resolvedLanguage; +function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ number, Phaser.Types.GameObjects.Text.TextStyle | InputText.IConfig, string, number, number ] { + const {resolvedLanguage} = i18next; let shadowXpos = 4; let shadowYpos = 5; + const scale = 0.1666666667; + const defaultFontSize = 96; let styleOptions: Phaser.Types.GameObjects.Text.TextStyle = { - fontFamily: "emerald", - fontSize: "96px", + fontFamily: "emerald, unifont", + fontSize: 96, color: getTextColor(style, false, uiTheme), padding: { bottom: 6 @@ -122,65 +110,45 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio case TextStyle.SUMMARY_GREEN: case TextStyle.WINDOW: case TextStyle.WINDOW_ALT: + case TextStyle.STATS_VALUE: shadowXpos = 3; shadowYpos = 3; break; case TextStyle.STATS_LABEL: - let fontSizeLabel = "96px"; - switch (lang) { - case "de": - fontSizeLabel = "80px"; - break; - default: - fontSizeLabel = "96px"; - break; - } - styleOptions.fontSize = fontSizeLabel; - break; - case TextStyle.STATS_VALUE: - shadowXpos = 3; - shadowYpos = 3; - let fontSizeValue = "96px"; - switch (lang) { - case "de": - fontSizeValue = "80px"; - break; - default: - fontSizeValue = "96px"; - break; - } - styleOptions.fontSize = fontSizeValue; - break; case TextStyle.MESSAGE: case TextStyle.SETTINGS_LABEL: case TextStyle.SETTINGS_LOCKED: case TextStyle.SETTINGS_SELECTED: - styleOptions.fontSize = languageSettings[lang]?.summaryFontSize || "96px"; break; case TextStyle.BATTLE_INFO: case TextStyle.MONEY: case TextStyle.TOOLTIP_TITLE: - styleOptions.fontSize = languageSettings[lang]?.battleInfoFontSize || "72px"; + styleOptions.fontSize = defaultFontSize - 24; shadowXpos = 3.5; shadowYpos = 3.5; break; case TextStyle.PARTY: case TextStyle.PARTY_RED: - styleOptions.fontSize = languageSettings[lang]?.partyFontSize || "66px"; + styleOptions.fontSize = defaultFontSize - 30; styleOptions.fontFamily = "pkmnems"; break; case TextStyle.TOOLTIP_CONTENT: - styleOptions.fontSize = languageSettings[lang]?.tooltipContentFontSize || "64px"; + styleOptions.fontSize = defaultFontSize - 32; shadowXpos = 3; shadowYpos = 3; break; case TextStyle.MOVE_INFO_CONTENT: - styleOptions.fontSize = languageSettings[lang]?.moveInfoFontSize || "56px"; + styleOptions.fontSize = defaultFontSize - 40; shadowXpos = 3; shadowYpos = 3; break; } + if (["zh"].includes(resolvedLanguage.substring(0,2))) { + shadowXpos = 0; + shadowYpos = 0; + } + const shadowColor = getTextColor(style, true, uiTheme); if (extraStyleOptions) { @@ -191,7 +159,7 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio styleOptions = Object.assign(styleOptions, extraStyleOptions); } - return [ styleOptions, shadowColor, shadowXpos, shadowYpos ]; + return [ scale, styleOptions, shadowColor, shadowXpos, shadowYpos ]; } export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string { @@ -204,11 +172,27 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui return !shadow ? "#f8f8f8" : "#6b5a73"; case TextStyle.WINDOW: case TextStyle.MOVE_INFO_CONTENT: + case TextStyle.MOVE_PP_FULL: case TextStyle.TOOLTIP_CONTENT: if (uiTheme) { return !shadow ? "#484848" : "#d0d0c8"; } return !shadow ? "#f8f8f8" : "#6b5a73"; + case TextStyle.MOVE_PP_HALF_FULL: + if (uiTheme) { + return !shadow ? "#a68e17" : "#ebd773"; + } + return !shadow ? "#ccbe00" : "#6e672c"; + case TextStyle.MOVE_PP_NEAR_EMPTY: + if (uiTheme) { + return !shadow ? "#d64b00" : "#f7b18b"; + } + return !shadow ? "#d64b00" : "#69402a"; + case TextStyle.MOVE_PP_EMPTY: + if (uiTheme) { + return !shadow ? "#e13d3d" : "#fca2a2"; + } + return !shadow ? "#e13d3d" : "#632929"; case TextStyle.WINDOW_ALT: return !shadow ? "#484848" : "#d0d0c8"; case TextStyle.BATTLE_INFO: diff --git a/src/ui/time-of-day-widget.ts b/src/ui/time-of-day-widget.ts index fd5a8b0b15e..da3503fb573 100644 --- a/src/ui/time-of-day-widget.ts +++ b/src/ui/time-of-day-widget.ts @@ -1,7 +1,7 @@ import * as Utils from "../utils"; import BattleScene from "#app/battle-scene.js"; import { TimeOfDay } from "#app/data/enums/time-of-day.js"; -import { BattleSceneEventType } from "#app/battle-scene-events.js"; +import { BattleSceneEventType } from "../events/battle-scene"; import { EaseType } from "./enums/ease-type"; /** A small self contained UI element that displays the time of day as an icon */ diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index 74015ed7245..e74853276ea 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -3,12 +3,19 @@ import { TextStyle, getTextColor } from "./text"; import { Mode } from "./ui"; import {Button} from "../enums/buttons"; +/** + * A basic abstract class to act as a holder and processor for UI elements. + */ export default abstract class UiHandler { protected scene: BattleScene; protected mode: integer; protected cursor: integer = 0; public active: boolean = false; + /** + * @param {BattleScene} scene The same scene as everything else. + * @param {Mode} mode The mode of the UI element. These should be unique. + */ constructor(scene: BattleScene, mode: Mode) { this.scene = scene; this.mode = mode; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index aaf764f501f..366be949374 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -14,6 +14,7 @@ import EvolutionSceneHandler from "./evolution-scene-handler"; import TargetSelectUiHandler from "./target-select-ui-handler"; import SettingsUiHandler from "./settings/settings-ui-handler"; import SettingsGamepadUiHandler from "./settings/settings-gamepad-ui-handler"; +import GameChallengesUiHandler from "./challenges-select-ui-handler"; import { TextStyle, addTextObject } from "./text"; import AchvBar from "./achv-bar"; import MenuUiHandler from "./menu-ui-handler"; @@ -80,7 +81,8 @@ export enum Mode { LOADING, SESSION_RELOAD, UNAVAILABLE, - OUTDATED + OUTDATED, + CHALLENGE_SELECT } const transitionModes = [ @@ -91,7 +93,8 @@ const transitionModes = [ Mode.EVOLUTION_SCENE, Mode.EGG_HATCH_SCENE, Mode.EGG_LIST, - Mode.EGG_GACHA + Mode.EGG_GACHA, + Mode.CHALLENGE_SELECT ]; const noTransitionModes = [ @@ -173,7 +176,8 @@ export default class UI extends Phaser.GameObjects.Container { new LoadingModalUiHandler(scene), new SessionReloadModalUiHandler(scene), new UnavailableModalUiHandler(scene), - new OutdatedModalUiHandler(scene) + new OutdatedModalUiHandler(scene), + new GameChallengesUiHandler(scene) ]; } diff --git a/src/utils.ts b/src/utils.ts index 7b25c4990e1..6f2c9cd0c65 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,5 @@ import i18next from "i18next"; +import { MoneyFormat } from "./enums/money-format"; export const MissingTextureKey = "__MISSING"; @@ -237,7 +238,7 @@ export function formatLargeNumber(count: integer, threshold: integer): string { // Abbreviations from 10^0 to 10^33 const AbbreviationsLargeNumber: string[] = ["", "K", "M", "B", "t", "q", "Q", "s", "S", "o", "n", "d"]; -export function formatFancyLargeNumber(number: number, rounded: number = 2): string { +export function formatFancyLargeNumber(number: number, rounded: number = 3): string { let exponent: number; if (number < 1000) { @@ -251,7 +252,14 @@ export function formatFancyLargeNumber(number: number, rounded: number = 2): str number /= Math.pow(1000, exponent); } - return `${(exponent === 0) ? number : number.toFixed(rounded)}${AbbreviationsLargeNumber[exponent]}`; + return `${(exponent === 0) || number % 1 === 0 ? number : number.toFixed(rounded)}${AbbreviationsLargeNumber[exponent]}`; +} + +export function formatMoney(format: MoneyFormat, amount: number) { + if (format === MoneyFormat.ABBREVIATED) { + return formatFancyLargeNumber(amount); + } + return amount.toLocaleString(); } export function formatStat(stat: integer, forHp: boolean = false): string { @@ -283,12 +291,12 @@ export const localServerUrl = import.meta.env.VITE_SERVER_URL ?? `http://${windo export const serverUrl = isLocal ? localServerUrl : ""; export const apiUrl = isLocal ? serverUrl : "https://api.pokerogue.net"; // used to disable api calls when isLocal is true and a server is not found -export let isLocalServerConnected = false; +export let isLocalServerConnected = true; export function setCookie(cName: string, cValue: string): void { const expiration = new Date(); expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3/*7*/); - document.cookie = `${cName}=${cValue};SameSite=Strict;path=/;expires=${expiration.toUTCString()}`; + document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Path=/;Expires=${expiration.toUTCString()}`; } export function getCookie(cName: string): string {