From c112abbcd20fbd1f0171762c4464b9601d10731d Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Fri, 30 Aug 2024 03:59:33 +0900 Subject: [PATCH 01/14] [Challenge] Inverse battle challenge (#3525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add inverse battle challenge. refactoring type.ts for inverse battle challenge * update type integer -> number * add inverse battle condition to thunder wave, conversion 2. * add inverse_battle test code, add checking gameMode in runToSummon not to overwrite gameMode to CLASSIC always * update startBattle with isClassicMode default = true * add inverse achievement * fix achv validation condition * remove unnecessary new line * update defaultWidth 160 -> 200 * update locales * fix korean translation * fix korean translation2 * Update src/locales/de/achv.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/de/challenges.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/de/challenges.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * resize challenge description 96 -> 84 * update challenge select UI size. * revert font size to 84. update de translation * Update src/locales/fr/challenges.ts Co-authored-by: Lugiad' * Update src/locales/fr/achv.ts Co-authored-by: Lugiad' * Update src/locales/es/challenges.ts Co-authored-by: Asdar * Update src/locales/fr/challenges.ts Co-authored-by: Lugiad' * Update src/locales/fr/achv.ts Co-authored-by: Lugiad' * Update src/locales/es/achv.ts Co-authored-by: Asdar * Update src/locales/fr/achv.ts Co-authored-by: Lugiad' * shrink de font size on achivement * set middle align to achv title * Update src/locales/zh_CN/achv.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_TW/achv.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_CN/challenges.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_TW/challenges.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * fix zh_TW ahiv.ts * fix import code on inverse battle test for updated phase * Update src/data/type.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * update requested changes * Update src/locales/pt_BR/achv.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/pt_BR/achv.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/pt_BR/challenges.ts Co-authored-by: José Ricardo Fleury Oliveira * [draft] update inverse battle apply function * change the way how to use applyChallenge for inverse type * resolve confilct * fix test codes * remove unnecessary multiplier variable and break codes * update getTypeDamageMultiplier argument type from `number` to `Type` * Fix inverse types tests (#1) * Fix Inverse Battle tests * Add timeout parameter to tests * update requested changes * update requested changes * update requested changes2 * update comments * Update src/test/utils/helpers/challengeModeHelper.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/test/utils/helpers/challengeModeHelper.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * fix mis pasted code * revert loadChallenge code for FreshStartChallenge * code refactoring * restore challenge.json lost translations * revert UI changes * revert unreverted newlines * Run History inclusion * requested changes from torranx * update WaterSuperEffectTypeMultiplierAttr for inverse battle matchup. * fix test code. adding flying press test code * update requested change from xavion3 * updated requested change from xavion 2 * update requested changes from xavion 3 * remove exception code which is not valid * attach partial mark to Freeze dry. requested by xavion * add missing game over phase code when we delete old phases.ts * fix test codes * merge conflict * fix achv condition * updated achv block condition. we don't want to change desc now * resolve conflict * Eternatus Moveset Tinkering * Cleaning it up --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: Asdar Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: frutescens --- public/images/items.json | 6835 +++++++++-------- public/images/items.png | Bin 56828 -> 57239 bytes src/data/challenge.ts | 65 +- src/data/move.ts | 37 +- src/data/type.ts | 318 +- src/enums/challenges.ts | 3 +- src/field/pokemon.ts | 13 +- src/locales/de/achv.json | 4 + src/locales/de/challenges.json | 7 + src/locales/en/achv-female.json | 4 + src/locales/en/achv.json | 4 + src/locales/en/challenges.json | 7 + src/locales/es/achv.json | 4 + src/locales/es/challenges.json | 7 + src/locales/fr/achv.json | 4 + src/locales/fr/challenges.json | 7 + src/locales/ja/challenges.json | 1 + src/locales/ko/achv.json | 4 + src/locales/ko/challenges.json | 7 + src/locales/pt_BR/achv.json | 4 + src/locales/pt_BR/challenges.json | 7 + src/locales/zh_CN/achv.json | 4 + src/locales/zh_CN/challenges.json | 7 + src/locales/zh_TW/achv.json | 4 + src/locales/zh_TW/challenges.json | 7 + src/system/achv.ts | 68 +- src/test/battle/inverse_battle.test.ts | 203 + src/test/utils/gameManager.ts | 3 + src/test/utils/helpers/challengeModeHelper.ts | 78 + src/ui/run-info-ui-handler.ts | 45 +- 30 files changed, 4005 insertions(+), 3756 deletions(-) create mode 100644 src/test/battle/inverse_battle.test.ts create mode 100644 src/test/utils/helpers/challengeModeHelper.ts diff --git a/public/images/items.json b/public/images/items.json index c347790b92f..bb86b46aa4d 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -4,8 +4,8 @@ "image": "items.png", "format": "RGBA8888", "size": { - "w": 425, - "h": 425 + "w": 426, + "h": 426 }, "scale": 1, "frames": [ @@ -240,6 +240,27 @@ "h": 31 } }, + { + "filename": "inverse", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 30 + }, + "frame": { + "x": 0, + "y": 241, + "w": 22, + "h": 30 + } + }, { "filename": "ribbon_gen3", "rotated": false, @@ -256,7 +277,7 @@ }, "frame": { "x": 0, - "y": 241, + "y": 271, "w": 22, "h": 29 } @@ -277,7 +298,7 @@ }, "frame": { "x": 0, - "y": 270, + "y": 300, "w": 22, "h": 29 } @@ -298,7 +319,7 @@ }, "frame": { "x": 0, - "y": 299, + "y": 329, "w": 22, "h": 29 } @@ -340,7 +361,7 @@ }, "frame": { "x": 0, - "y": 328, + "y": 358, "w": 22, "h": 28 } @@ -361,28 +382,7 @@ }, "frame": { "x": 0, - "y": 356, - "w": 22, - "h": 28 - } - }, - { - "filename": "ribbon_gen6", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 22, - "h": 28 - }, - "frame": { - "x": 0, - "y": 384, + "y": 386, "w": 22, "h": 28 } @@ -619,7 +619,7 @@ } }, { - "filename": "elixir", + "filename": "lock_capsule", "rotated": false, "trimmed": true, "sourceSize": { @@ -628,15 +628,15 @@ }, "spriteSourceSize": { "x": 7, - "y": 4, - "w": 18, - "h": 24 + "y": 5, + "w": 19, + "h": 22 }, "frame": { "x": 407, "y": 0, - "w": 18, - "h": 24 + "w": 19, + "h": 22 } }, { @@ -724,7 +724,7 @@ } }, { - "filename": "ribbon_gen8", + "filename": "ribbon_gen6", "rotated": false, "trimmed": true, "sourceSize": { @@ -744,6 +744,27 @@ "h": 28 } }, + { + "filename": "ribbon_gen8", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 2, + "w": 22, + "h": 28 + }, + "frame": { + "x": 22, + "y": 237, + "w": 22, + "h": 28 + } + }, { "filename": "black_augurite", "rotated": false, @@ -760,7 +781,7 @@ }, "frame": { "x": 22, - "y": 237, + "y": 265, "w": 22, "h": 25 } @@ -781,7 +802,7 @@ }, "frame": { "x": 22, - "y": 262, + "y": 290, "w": 23, "h": 24 } @@ -802,7 +823,7 @@ }, "frame": { "x": 22, - "y": 286, + "y": 314, "w": 24, "h": 24 } @@ -823,7 +844,7 @@ }, "frame": { "x": 22, - "y": 310, + "y": 338, "w": 24, "h": 24 } @@ -844,7 +865,7 @@ }, "frame": { "x": 22, - "y": 334, + "y": 362, "w": 24, "h": 24 } @@ -865,13 +886,13 @@ }, "frame": { "x": 22, - "y": 358, + "y": 386, "w": 24, "h": 24 } }, { - "filename": "earth_plate", + "filename": "mega_bracelet", "rotated": false, "trimmed": true, "sourceSize": { @@ -879,20 +900,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 + "x": 6, + "y": 8, + "w": 20, + "h": 16 }, "frame": { "x": 22, - "y": 382, - "w": 24, - "h": 24 + "y": 410, + "w": 20, + "h": 16 } }, { - "filename": "coupon", + "filename": "relic_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -900,37 +921,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 + "x": 7, + "y": 9, + "w": 17, + "h": 16 }, "frame": { - "x": 22, - "y": 406, - "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": 45, - "y": 406, - "w": 23, - "h": 19 + "x": 42, + "y": 410, + "w": 17, + "h": 16 } }, { @@ -955,7 +955,7 @@ } }, { - "filename": "mega_bracelet", + "filename": "abomasite", "rotated": false, "trimmed": true, "sourceSize": { @@ -963,20 +963,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 8, "y": 8, - "w": 20, + "w": 16, "h": 16 }, "frame": { "x": 28, "y": 70, - "w": 20, + "w": 16, "h": 16 } }, { - "filename": "calcium", + "filename": "absolite", "rotated": false, "trimmed": true, "sourceSize": { @@ -985,36 +985,15 @@ }, "spriteSourceSize": { "x": 8, - "y": 4, + "y": 8, "w": 16, - "h": 24 + "h": 16 }, "frame": { - "x": 39, - "y": 86, + "x": 44, + "y": 70, "w": 16, - "h": 24 - } - }, - { - "filename": "carbos", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 39, - "y": 110, - "w": 16, - "h": 24 + "h": 16 } }, { @@ -1033,11 +1012,32 @@ }, "frame": { "x": 39, - "y": 134, + "y": 86, "w": 21, "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": 39, + "y": 110, + "w": 24, + "h": 24 + } + }, { "filename": "fist_plate", "rotated": false, @@ -1054,7 +1054,7 @@ }, "frame": { "x": 39, - "y": 158, + "y": 134, "w": 24, "h": 24 } @@ -1075,7 +1075,7 @@ }, "frame": { "x": 39, - "y": 182, + "y": 158, "w": 24, "h": 24 } @@ -1095,8 +1095,8 @@ "h": 24 }, "frame": { - "x": 44, - "y": 206, + "x": 39, + "y": 182, "w": 24, "h": 24 } @@ -1117,7 +1117,7 @@ }, "frame": { "x": 44, - "y": 230, + "y": 206, "w": 24, "h": 24 } @@ -1137,8 +1137,8 @@ "h": 24 }, "frame": { - "x": 45, - "y": 254, + "x": 44, + "y": 230, "w": 24, "h": 24 } @@ -1158,8 +1158,8 @@ "h": 24 }, "frame": { - "x": 46, - "y": 278, + "x": 44, + "y": 254, "w": 24, "h": 24 } @@ -1179,8 +1179,8 @@ "h": 24 }, "frame": { - "x": 46, - "y": 302, + "x": 45, + "y": 278, "w": 24, "h": 24 } @@ -1201,7 +1201,7 @@ }, "frame": { "x": 46, - "y": 326, + "y": 302, "w": 24, "h": 24 } @@ -1222,7 +1222,7 @@ }, "frame": { "x": 46, - "y": 350, + "y": 326, "w": 24, "h": 24 } @@ -1243,137 +1243,11 @@ }, "frame": { "x": 46, - "y": 374, + "y": 350, "w": 24, "h": 24 } }, - { - "filename": "abomasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 48, - "y": 70, - "w": 16, - "h": 16 - } - }, - { - "filename": "ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 55, - "y": 86, - "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": 55, - "y": 110, - "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": 60, - "y": 134, - "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": 63, - "y": 158, - "w": 16, - "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": 63, - "y": 182, - "w": 23, - "h": 24 - } - }, { "filename": "lucky_punch_great", "rotated": false, @@ -1389,180 +1263,12 @@ "h": 24 }, "frame": { - "x": 68, - "y": 206, - "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": 68, - "y": 230, - "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": 69, - "y": 254, - "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": 70, - "y": 278, - "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": 70, - "y": 302, - "w": 24, - "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": 70, - "y": 326, - "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": 70, - "y": 350, - "w": 24, - "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": 70, + "x": 46, "y": 374, "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": 68, - "y": 398, - "w": 24, - "h": 24 - } - }, { "filename": "ability_capsule", "rotated": false, @@ -1585,7 +1291,7 @@ } }, { - "filename": "lure", + "filename": "calcium", "rotated": false, "trimmed": true, "sourceSize": { @@ -1595,39 +1301,18 @@ "spriteSourceSize": { "x": 8, "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 92, - "y": 398, - "w": 17, - "h": 24 - } - }, - { - "filename": "max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, + "w": 16, "h": 24 }, "frame": { "x": 59, "y": 27, - "w": 18, + "w": 16, "h": 24 } }, { - "filename": "scanner", + "filename": "lucky_punch_master", "rotated": false, "trimmed": true, "sourceSize": { @@ -1641,14 +1326,14 @@ "h": 24 }, "frame": { - "x": 77, + "x": 75, "y": 26, "w": 24, "h": 24 } }, { - "filename": "silk_scarf", + "filename": "lucky_punch_ultra", "rotated": false, "trimmed": true, "sourceSize": { @@ -1662,12 +1347,33 @@ "h": 24 }, "frame": { - "x": 101, + "x": 99, "y": 26, "w": 24, "h": 24 } }, + { + "filename": "revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 12, + "h": 17 + }, + "frame": { + "x": 123, + "y": 26, + "w": 12, + "h": 17 + } + }, { "filename": "big_mushroom", "rotated": false, @@ -1710,6 +1416,69 @@ "h": 23 } }, + { + "filename": "elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 60, + "y": 70, + "w": 18, + "h": 24 + } + }, + { + "filename": "coin_case", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 78, + "y": 73, + "w": 24, + "h": 23 + } + }, + { + "filename": "kings_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 102, + "y": 50, + "w": 23, + "h": 24 + } + }, { "filename": "berry_pouch", "rotated": false, @@ -1726,11 +1495,284 @@ }, "frame": { "x": 102, - "y": 50, + "y": 74, "w": 23, "h": 23 } }, + { + "filename": "aerodactylite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 60, + "y": 94, + "w": 16, + "h": 16 + } + }, + { + "filename": "carbos", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 63, + "y": 110, + "w": 16, + "h": 24 + } + }, + { + "filename": "ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 63, + "y": 134, + "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": 63, + "y": 158, + "w": 18, + "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": 63, + "y": 182, + "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": 68, + "y": 206, + "w": 22, + "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": 68, + "y": 230, + "w": 24, + "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": 68, + "y": 254, + "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": 69, + "y": 278, + "w": 24, + "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": 70, + "y": 302, + "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": 70, + "y": 326, + "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": 70, + "y": 350, + "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": 70, + "y": 374, + "w": 24, + "h": 24 + } + }, { "filename": "sky_plate", "rotated": false, @@ -1746,14 +1788,14 @@ "h": 24 }, "frame": { - "x": 125, - "y": 36, + "x": 59, + "y": 398, "w": 24, "h": 24 } }, { - "filename": "choice_specs", + "filename": "hp_up", "rotated": false, "trimmed": true, "sourceSize": { @@ -1761,41 +1803,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 125, - "y": 60, - "w": 24, - "h": 18 - } - }, - { - "filename": "max_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, + "x": 8, "y": 4, - "w": 18, + "w": 16, "h": 24 }, "frame": { - "x": 149, - "y": 36, - "w": 18, + "x": 83, + "y": 398, + "w": 16, "h": 24 } }, { - "filename": "adamant_crystal", + "filename": "reveal_glass", "rotated": false, "trimmed": true, "sourceSize": { @@ -1804,15 +1825,36 @@ }, "spriteSourceSize": { "x": 4, - "y": 6, + "y": 4, "w": 23, - "h": 21 + "h": 24 }, "frame": { - "x": 149, - "y": 60, + "x": 79, + "y": 96, "w": 23, - "h": 21 + "h": 24 + } + }, + { + "filename": "dynamax_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 23 + }, + "frame": { + "x": 102, + "y": 97, + "w": 23, + "h": 23 } }, { @@ -1830,8 +1872,8 @@ "h": 24 }, "frame": { - "x": 167, - "y": 21, + "x": 81, + "y": 120, "w": 24, "h": 24 } @@ -1851,12 +1893,54 @@ "h": 24 }, "frame": { - "x": 191, - "y": 21, + "x": 81, + "y": 144, "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": 105, + "y": 120, + "w": 21, + "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": 105, + "y": 144, + "w": 21, + "h": 24 + } + }, { "filename": "stone_plate", "rotated": false, @@ -1872,12 +1956,33 @@ "h": 24 }, "frame": { - "x": 215, - "y": 21, + "x": 87, + "y": 168, "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": 111, + "y": 168, + "w": 16, + "h": 24 + } + }, { "filename": "sun_stone", "rotated": false, @@ -1893,12 +1998,33 @@ "h": 24 }, "frame": { - "x": 239, - "y": 21, + "x": 90, + "y": 192, "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": 114, + "y": 192, + "w": 17, + "h": 24 + } + }, { "filename": "toxic_plate", "rotated": false, @@ -1914,8 +2040,8 @@ "h": 24 }, "frame": { - "x": 263, - "y": 21, + "x": 92, + "y": 216, "w": 24, "h": 24 } @@ -1935,14 +2061,14 @@ "h": 24 }, "frame": { - "x": 287, - "y": 21, + "x": 92, + "y": 240, "w": 24, "h": 24 } }, { - "filename": "silver_powder", + "filename": "max_elixir", "rotated": false, "trimmed": true, "sourceSize": { @@ -1950,41 +2076,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 11, - "w": 24, - "h": 15 - }, - "frame": { - "x": 167, - "y": 45, - "w": 24, - "h": 15 - } - }, - { - "filename": "max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, + "x": 7, "y": 4, - "w": 22, + "w": 18, "h": 24 }, "frame": { - "x": 311, - "y": 21, - "w": 22, + "x": 116, + "y": 216, + "w": 18, "h": 24 } }, { - "filename": "coin_case", + "filename": "max_ether", "rotated": false, "trimmed": true, "sourceSize": { @@ -1992,16 +2097,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 + "x": 7, + "y": 4, + "w": 18, + "h": 24 }, "frame": { - "x": 333, - "y": 20, - "w": 24, - "h": 23 + "x": 116, + "y": 240, + "w": 18, + "h": 24 } }, { @@ -2019,12 +2124,75 @@ "h": 23 }, "frame": { - "x": 357, - "y": 20, + "x": 93, + "y": 264, "w": 24, "h": 23 } }, + { + "filename": "black_belt", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 117, + "y": 264, + "w": 22, + "h": 23 + } + }, + { + "filename": "silver_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 11, + "w": 24, + "h": 15 + }, + "frame": { + "x": 93, + "y": 287, + "w": 24, + "h": 15 + } + }, + { + "filename": "griseous_core", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 94, + "y": 302, + "w": 23, + "h": 23 + } + }, { "filename": "hearthflame_mask", "rotated": false, @@ -2040,138 +2208,12 @@ "h": 23 }, "frame": { - "x": 381, - "y": 20, + "x": 94, + "y": 325, "w": 24, "h": 23 } }, - { - "filename": "red_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 20, - "h": 24 - }, - "frame": { - "x": 405, - "y": 24, - "w": 20, - "h": 24 - } - }, - { - "filename": "amulet_coin", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 172, - "y": 60, - "w": 23, - "h": 21 - } - }, - { - "filename": "candy_overlay", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 12, - "w": 16, - "h": 15 - }, - "frame": { - "x": 191, - "y": 45, - "w": 16, - "h": 15 - } - }, - { - "filename": "dragon_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 207, - "y": 45, - "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": 231, - "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": 255, - "y": 45, - "w": 24, - "h": 22 - } - }, { "filename": "leppa_berry", "rotated": false, @@ -2187,8 +2229,8 @@ "h": 23 }, "frame": { - "x": 279, - "y": 45, + "x": 94, + "y": 348, "w": 24, "h": 23 } @@ -2208,264 +2250,12 @@ "h": 23 }, "frame": { - "x": 303, - "y": 45, + "x": 94, + "y": 371, "w": 24, "h": 23 } }, - { - "filename": "revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 10, - "y": 8, - "w": 12, - "h": 17 - }, - "frame": { - "x": 195, - "y": 60, - "w": 12, - "h": 17 - } - }, - { - "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": 207, - "y": 63, - "w": 24, - "h": 20 - } - }, - { - "filename": "metal_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 231, - "y": 67, - "w": 24, - "h": 20 - } - }, - { - "filename": "peat_block", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 255, - "y": 67, - "w": 24, - "h": 22 - } - }, - { - "filename": "twisted_spoon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 279, - "y": 68, - "w": 24, - "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": 303, - "y": 68, - "w": 23, - "h": 23 - } - }, - { - "filename": "black_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 327, - "y": 45, - "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": 326, - "y": 68, - "w": 23, - "h": 23 - } - }, - { - "filename": "reveal_glass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 349, - "y": 43, - "w": 23, - "h": 24 - } - }, - { - "filename": "leek", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 372, - "y": 43, - "w": 23, - "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": 349, - "y": 67, - "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": 372, - "y": 66, - "w": 23, - "h": 23 - } - }, { "filename": "bug_tera_shard", "rotated": false, @@ -2481,14 +2271,98 @@ "h": 23 }, "frame": { - "x": 395, - "y": 48, + "x": 117, + "y": 287, "w": 22, "h": 23 } }, { - "filename": "auspicious_armor", + "filename": "red_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 20, + "h": 24 + }, + "frame": { + "x": 99, + "y": 394, + "w": 20, + "h": 24 + } + }, + { + "filename": "candy_overlay", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 12, + "w": 16, + "h": 15 + }, + "frame": { + "x": 117, + "y": 310, + "w": 16, + "h": 15 + } + }, + { + "filename": "max_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 118, + "y": 325, + "w": 17, + "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": 118, + "y": 349, + "w": 18, + "h": 24 + } + }, + { + "filename": "adamant_crystal", "rotated": false, "trimmed": true, "sourceSize": { @@ -2497,78 +2371,15 @@ }, "spriteSourceSize": { "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 395, - "y": 71, - "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 + "h": 21 }, "frame": { - "x": 372, - "y": 89, + "x": 118, + "y": 373, "w": 23, - "h": 20 - } - }, - { - "filename": "healing_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 349, - "y": 90, - "w": 23, - "h": 22 - } - }, - { - "filename": "black_glasses", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 395, - "y": 92, - "w": 23, - "h": 17 + "h": 21 } }, { @@ -2586,12 +2397,96 @@ "h": 23 }, "frame": { - "x": 73, - "y": 73, + "x": 119, + "y": 394, "w": 22, "h": 23 } }, + { + "filename": "choice_specs", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 135, + "y": 36, + "w": 24, + "h": 18 + } + }, + { + "filename": "twisted_spoon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 125, + "y": 54, + "w": 24, + "h": 23 + } + }, + { + "filename": "exp_balance", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 125, + "y": 77, + "w": 24, + "h": 22 + } + }, + { + "filename": "amulet_coin", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 125, + "y": 99, + "w": 23, + "h": 21 + } + }, { "filename": "dragon_tera_shard", "rotated": false, @@ -2607,8 +2502,8 @@ "h": 23 }, "frame": { - "x": 95, - "y": 73, + "x": 126, + "y": 120, "w": 22, "h": 23 } @@ -2628,56 +2523,14 @@ "h": 23 }, "frame": { - "x": 73, - "y": 96, + "x": 126, + "y": 143, "w": 22, "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": 95, - "y": 96, - "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": 117, - "y": 78, - "w": 22, - "h": 23 - } - }, - { - "filename": "blank_memory", + "filename": "dragon_fang", "rotated": false, "trimmed": true, "sourceSize": { @@ -2687,102 +2540,18 @@ "spriteSourceSize": { "x": 5, "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 117, - "y": 101, - "w": 22, - "h": 22 - } - }, - { - "filename": "fire_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, + "w": 21, "h": 23 }, "frame": { - "x": 139, - "y": 81, - "w": 22, + "x": 127, + "y": 166, + "w": 21, "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": 161, - "y": 81, - "w": 22, - "h": 23 - } - }, - { - "filename": "quick_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 139, - "y": 104, - "w": 24, - "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": 163, - "y": 104, - "w": 20, - "h": 20 - } - }, - { - "filename": "max_lure", + "filename": "super_lure", "rotated": false, "trimmed": true, "sourceSize": { @@ -2796,348 +2565,12 @@ "h": 24 }, "frame": { - "x": 183, - "y": 81, + "x": 131, + "y": 189, "w": 17, "h": 24 } }, - { - "filename": "rusted_sword", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 200, - "y": 83, - "w": 23, - "h": 22 - } - }, - { - "filename": "rusted_shield", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 183, - "y": 105, - "w": 24, - "h": 20 - } - }, - { - "filename": "apicot_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 207, - "y": 105, - "w": 19, - "h": 20 - } - }, - { - "filename": "relic_crown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 18 - }, - "frame": { - "x": 223, - "y": 87, - "w": 23, - "h": 18 - } - }, - { - "filename": "blue_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 226, - "y": 105, - "w": 20, - "h": 20 - } - }, - { - "filename": "flying_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 246, - "y": 89, - "w": 22, - "h": 23 - } - }, - { - "filename": "blunder_policy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 19 - }, - "frame": { - "x": 246, - "y": 112, - "w": 22, - "h": 19 - } - }, - { - "filename": "focus_sash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 268, - "y": 91, - "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": 290, - "y": 91, - "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": 312, - "y": 91, - "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": 334, - "y": 91, - "w": 15, - "h": 23 - } - }, - { - "filename": "sacred_ash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 268, - "y": 114, - "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": 292, - "y": 114, - "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": 316, - "y": 114, - "w": 24, - "h": 20 - } - }, - { - "filename": "eviolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 73, - "y": 119, - "w": 15, - "h": 15 - } - }, - { - "filename": "max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 76, - "y": 134, - "w": 18, - "h": 24 - } - }, { "filename": "max_repel", "rotated": false, @@ -3153,33 +2586,12 @@ "h": 24 }, "frame": { - "x": 79, - "y": 158, + "x": 134, + "y": 213, "w": 16, "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": 86, - "y": 182, - "w": 21, - "h": 24 - } - }, { "filename": "pp_max", "rotated": false, @@ -3195,8 +2607,8 @@ "h": 24 }, "frame": { - "x": 92, - "y": 206, + "x": 134, + "y": 237, "w": 16, "h": 24 } @@ -3216,12 +2628,180 @@ "h": 24 }, "frame": { - "x": 92, - "y": 230, + "x": 149, + "y": 54, "w": 16, "h": 24 } }, + { + "filename": "auspicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 149, + "y": 78, + "w": 23, + "h": 21 + } + }, + { + "filename": "exp_share", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 148, + "y": 99, + "w": 24, + "h": 22 + } + }, + { + "filename": "leek", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 148, + "y": 121, + "w": 23, + "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": 148, + "y": 144, + "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": 148, + "y": 167, + "w": 23, + "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": 148, + "y": 190, + "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": 150, + "y": 213, + "w": 22, + "h": 23 + } + }, + { + "filename": "fire_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 150, + "y": 236, + "w": 22, + "h": 23 + } + }, { "filename": "protein", "rotated": false, @@ -3237,8 +2817,8 @@ "h": 24 }, "frame": { - "x": 93, - "y": 254, + "x": 139, + "y": 261, "w": 16, "h": 24 } @@ -3258,56 +2838,14 @@ "h": 24 }, "frame": { - "x": 94, - "y": 278, + "x": 139, + "y": 285, "w": 16, "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": 94, - "y": 302, - "w": 21, - "h": 24 - } - }, - { - "filename": "dragon_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 94, - "y": 326, - "w": 21, - "h": 23 - } - }, - { - "filename": "ground_tera_shard", + "filename": "fire_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3321,14 +2859,14 @@ "h": 23 }, "frame": { - "x": 94, - "y": 349, + "x": 155, + "y": 259, "w": 22, "h": 23 } }, { - "filename": "ice_tera_shard", + "filename": "flying_tera_shard", "rotated": false, "trimmed": true, "sourceSize": { @@ -3342,54 +2880,12 @@ "h": 23 }, "frame": { - "x": 94, - "y": 372, + "x": 155, + "y": 282, "w": 22, "h": 23 } }, - { - "filename": "prism_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 88, - "y": 119, - "w": 15, - "h": 15 - } - }, - { - "filename": "super_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 94, - "y": 134, - "w": 17, - "h": 24 - } - }, { "filename": "super_repel", "rotated": false, @@ -3405,14 +2901,14 @@ "h": 24 }, "frame": { - "x": 95, - "y": 158, + "x": 159, + "y": 22, "w": 16, "h": 24 } }, { - "filename": "berry_pot", + "filename": "peat_block", "rotated": false, "trimmed": true, "sourceSize": { @@ -3420,20 +2916,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 4, "y": 5, - "w": 18, + "w": 24, "h": 22 }, "frame": { - "x": 340, - "y": 114, - "w": 18, + "x": 175, + "y": 21, + "w": 24, "h": 22 } }, { - "filename": "unknown", + "filename": "healing_charm", "rotated": false, "trimmed": true, "sourceSize": { @@ -3441,20 +2937,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 + "x": 5, + "y": 5, + "w": 23, + "h": 22 }, "frame": { - "x": 358, - "y": 112, - "w": 16, - "h": 24 + "x": 199, + "y": 21, + "w": 23, + "h": 22 } }, { - "filename": "never_melt_ice", + "filename": "rusted_sword", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 222, + "y": 21, + "w": 23, + "h": 22 + } + }, + { + "filename": "blank_memory", "rotated": false, "trimmed": true, "sourceSize": { @@ -3465,307 +2982,13 @@ "x": 5, "y": 5, "w": 22, - "h": 23 + "h": 22 }, "frame": { - "x": 374, - "y": 109, + "x": 245, + "y": 21, "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": 396, - "y": 109, - "w": 22, - "h": 23 - } - }, - { - "filename": "zinc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 107, - "y": 182, - "w": 16, - "h": 24 - } - }, - { - "filename": "hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 108, - "y": 206, - "w": 17, - "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": 108, - "y": 229, - "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": 109, - "y": 252, - "w": 21, - "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": 110, - "y": 275, - "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": 115, - "y": 298, - "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": 115, - "y": 321, - "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": 116, - "y": 344, - "w": 22, - "h": 23 - } - }, - { - "filename": "reaper_cloth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 116, - "y": 367, - "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": 111, - "y": 123, - "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": 111, - "y": 146, - "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": 133, - "y": 124, - "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": 155, - "y": 124, - "w": 22, - "h": 23 + "h": 22 } }, { @@ -3783,8 +3006,8 @@ "h": 22 }, "frame": { - "x": 133, - "y": 147, + "x": 267, + "y": 21, "w": 22, "h": 22 } @@ -3804,33 +3027,12 @@ "h": 22 }, "frame": { - "x": 155, - "y": 147, + "x": 289, + "y": 21, "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": 177, - "y": 125, - "w": 22, - "h": 23 - } - }, { "filename": "dark_memory", "rotated": false, @@ -3846,14 +3048,14 @@ "h": 22 }, "frame": { - "x": 199, - "y": 125, + "x": 311, + "y": 21, "w": 22, "h": 22 } }, { - "filename": "dire_hit", + "filename": "focus_sash", "rotated": false, "trimmed": true, "sourceSize": { @@ -3862,19 +3064,229 @@ }, "spriteSourceSize": { "x": 5, - "y": 5, + "y": 4, "w": 22, - "h": 22 + "h": 23 }, "frame": { - "x": 221, - "y": 125, + "x": 333, + "y": 20, "w": 22, - "h": 22 + "h": 23 } }, { - "filename": "deep_sea_tooth", + "filename": "ghost_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 355, + "y": 20, + "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": 377, + "y": 20, + "w": 22, + "h": 23 + } + }, + { + "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": 399, + "y": 22, + "w": 24, + "h": 20 + } + }, + { + "filename": "dragon_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 175, + "y": 43, + "w": 24, + "h": 18 + } + }, + { + "filename": "metal_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 199, + "y": 43, + "w": 24, + "h": 20 + } + }, + { + "filename": "quick_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 223, + "y": 43, + "w": 24, + "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": 247, + "y": 43, + "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": 271, + "y": 43, + "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": 295, + "y": 43, + "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": 319, + "y": 43, + "w": 24, + "h": 20 + } + }, + { + "filename": "binding_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -3884,77 +3296,14 @@ "spriteSourceSize": { "x": 5, "y": 6, - "w": 22, - "h": 21 + "w": 23, + "h": 20 }, "frame": { - "x": 177, - "y": 148, - "w": 22, - "h": 21 - } - }, - { - "filename": "dna_splicers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 199, - "y": 147, - "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": 221, - "y": 147, - "w": 22, - "h": 22 - } - }, - { - "filename": "electirizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 243, - "y": 131, - "w": 22, - "h": 22 + "x": 343, + "y": 43, + "w": 23, + "h": 20 } }, { @@ -3972,12 +3321,558 @@ "h": 21 }, "frame": { - "x": 265, - "y": 134, + "x": 366, + "y": 43, "w": 23, "h": 21 } }, + { + "filename": "black_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 165, + "y": 61, + "w": 23, + "h": 17 + } + }, + { + "filename": "unknown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 172, + "y": 78, + "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": 172, + "y": 102, + "w": 19, + "h": 20 + } + }, + { + "filename": "ground_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 171, + "y": 122, + "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": 171, + "y": 145, + "w": 22, + "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": 171, + "y": 168, + "w": 22, + "h": 22 + } + }, + { + "filename": "never_melt_ice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 170, + "y": 190, + "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": 172, + "y": 213, + "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": 172, + "y": 236, + "w": 21, + "h": 23 + } + }, + { + "filename": "zinc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 177, + "y": 259, + "w": 16, + "h": 24 + } + }, + { + "filename": "berry_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 18, + "h": 22 + }, + "frame": { + "x": 177, + "y": 283, + "w": 18, + "h": 22 + } + }, + { + "filename": "normal_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 188, + "y": 63, + "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": 210, + "y": 63, + "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": 232, + "y": 63, + "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": 254, + "y": 63, + "w": 22, + "h": 23 + } + }, + { + "filename": "reaper_cloth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 276, + "y": 63, + "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": 298, + "y": 63, + "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": 320, + "y": 63, + "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": 342, + "y": 63, + "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": 364, + "y": 64, + "w": 22, + "h": 22 + } + }, + { + "filename": "aggronite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 188, + "y": 86, + "w": 16, + "h": 16 + } + }, + { + "filename": "burn_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 204, + "y": 86, + "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": 227, + "y": 86, + "w": 23, + "h": 17 + } + }, + { + "filename": "coupon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 250, + "y": 86, + "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": 273, + "y": 86, + "w": 23, + "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": 296, + "y": 86, + "w": 23, + "h": 19 + } + }, { "filename": "n_lunarizer", "rotated": false, @@ -3993,8 +3888,8 @@ "h": 21 }, "frame": { - "x": 288, - "y": 134, + "x": 319, + "y": 86, "w": 23, "h": 21 } @@ -4014,14 +3909,14 @@ "h": 21 }, "frame": { - "x": 311, - "y": 134, + "x": 342, + "y": 86, "w": 23, "h": 21 } }, { - "filename": "deep_sea_scale", + "filename": "deep_sea_tooth", "rotated": false, "trimmed": true, "sourceSize": { @@ -4032,17 +3927,17 @@ "x": 5, "y": 6, "w": 22, - "h": 20 + "h": 21 }, "frame": { - "x": 243, - "y": 153, + "x": 365, + "y": 86, "w": 22, - "h": 20 + "h": 21 } }, { - "filename": "mystic_ticket", + "filename": "dawn_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -4050,16 +3945,121 @@ "h": 32 }, "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 + "x": 6, + "y": 6, + "w": 20, + "h": 21 }, "frame": { - "x": 265, - "y": 155, - "w": 23, - "h": 19 + "x": 389, + "y": 43, + "w": 20, + "h": 21 + } + }, + { + "filename": "hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 409, + "y": 42, + "w": 17, + "h": 23 + } + }, + { + "filename": "dragon_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 386, + "y": 64, + "w": 22, + "h": 22 + } + }, + { + "filename": "sachet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 18, + "h": 23 + }, + "frame": { + "x": 408, + "y": 65, + "w": 18, + "h": 23 + } + }, + { + "filename": "dusk_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 387, + "y": 86, + "w": 21, + "h": 21 + } + }, + { + "filename": "razor_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 18, + "h": 20 + }, + "frame": { + "x": 408, + "y": 88, + "w": 18, + "h": 20 } }, { @@ -4077,14 +4077,14 @@ "h": 19 }, "frame": { - "x": 288, - "y": 155, + "x": 191, + "y": 103, "w": 23, "h": 19 } }, { - "filename": "reviver_seed", + "filename": "sharp_beak", "rotated": false, "trimmed": true, "sourceSize": { @@ -4093,15 +4093,99 @@ }, "spriteSourceSize": { "x": 5, - "y": 8, - "w": 23, - "h": 20 + "y": 5, + "w": 21, + "h": 23 }, "frame": { - "x": 311, - "y": 155, - "w": 23, - "h": 20 + "x": 193, + "y": 122, + "w": 21, + "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": 214, + "y": 103, + "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": 193, + "y": 145, + "w": 21, + "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": 214, + "y": 126, + "w": 22, + "h": 23 + } + }, + { + "filename": "electirizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 193, + "y": 168, + "w": 22, + "h": 22 } }, { @@ -4119,12 +4203,33 @@ "h": 22 }, "frame": { - "x": 334, - "y": 136, + "x": 192, + "y": 190, "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": 214, + "y": 149, + "w": 22, + "h": 19 + } + }, { "filename": "enigma_berry", "rotated": false, @@ -4140,33 +4245,12 @@ "h": 22 }, "frame": { - "x": 356, - "y": 136, + "x": 215, + "y": 168, "w": 22, "h": 22 } }, - { - "filename": "burn_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 334, - "y": 158, - "w": 23, - "h": 17 - } - }, { "filename": "fairy_memory", "rotated": false, @@ -4182,8 +4266,8 @@ "h": 22 }, "frame": { - "x": 378, - "y": 132, + "x": 214, + "y": 190, "w": 22, "h": 22 } @@ -4203,54 +4287,12 @@ "h": 22 }, "frame": { - "x": 400, - "y": 132, + "x": 193, + "y": 212, "w": 22, "h": 22 } }, - { - "filename": "chill_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 357, - "y": 158, - "w": 23, - "h": 17 - } - }, - { - "filename": "wellspring_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 380, - "y": 154, - "w": 23, - "h": 21 - } - }, { "filename": "fire_memory", "rotated": false, @@ -4266,8 +4308,8 @@ "h": 22 }, "frame": { - "x": 403, - "y": 154, + "x": 193, + "y": 234, "w": 22, "h": 22 } @@ -4287,8 +4329,8 @@ "h": 22 }, "frame": { - "x": 123, - "y": 169, + "x": 193, + "y": 256, "w": 22, "h": 22 } @@ -4308,8 +4350,8 @@ "h": 22 }, "frame": { - "x": 145, - "y": 169, + "x": 215, + "y": 212, "w": 22, "h": 22 } @@ -4329,8 +4371,8 @@ "h": 22 }, "frame": { - "x": 167, - "y": 169, + "x": 215, + "y": 234, "w": 22, "h": 22 } @@ -4350,8 +4392,8 @@ "h": 22 }, "frame": { - "x": 189, - "y": 169, + "x": 215, + "y": 256, "w": 22, "h": 22 } @@ -4371,75 +4413,12 @@ "h": 22 }, "frame": { - "x": 211, - "y": 169, + "x": 195, + "y": 278, "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": 233, - "y": 173, - "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": 256, - "y": 174, - "w": 22, - "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": 278, - "y": 174, - "w": 22, - "h": 20 - } - }, { "filename": "guard_spec", "rotated": false, @@ -4455,8 +4434,8 @@ "h": 22 }, "frame": { - "x": 300, - "y": 175, + "x": 217, + "y": 278, "w": 22, "h": 22 } @@ -4476,8 +4455,8 @@ "h": 22 }, "frame": { - "x": 322, - "y": 175, + "x": 236, + "y": 105, "w": 22, "h": 22 } @@ -4497,8 +4476,8 @@ "h": 22 }, "frame": { - "x": 344, - "y": 175, + "x": 236, + "y": 127, "w": 22, "h": 22 } @@ -4518,33 +4497,12 @@ "h": 22 }, "frame": { - "x": 366, - "y": 175, + "x": 258, + "y": 105, "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": 388, - "y": 175, - "w": 15, - "h": 22 - } - }, { "filename": "mini_black_hole", "rotated": false, @@ -4560,8 +4518,8 @@ "h": 22 }, "frame": { - "x": 403, - "y": 176, + "x": 280, + "y": 105, "w": 22, "h": 22 } @@ -4581,8 +4539,8 @@ "h": 22 }, "frame": { - "x": 125, - "y": 191, + "x": 258, + "y": 127, "w": 22, "h": 22 } @@ -4602,12 +4560,33 @@ "h": 22 }, "frame": { - "x": 147, - "y": 191, + "x": 280, + "y": 127, "w": 22, "h": 22 } }, + { + "filename": "dubious_disc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 236, + "y": 149, + "w": 22, + "h": 19 + } + }, { "filename": "psychic_memory", "rotated": false, @@ -4623,8 +4602,8 @@ "h": 22 }, "frame": { - "x": 169, - "y": 191, + "x": 237, + "y": 168, "w": 22, "h": 22 } @@ -4644,12 +4623,33 @@ "h": 22 }, "frame": { - "x": 191, - "y": 191, + "x": 236, + "y": 190, "w": 22, "h": 22 } }, + { + "filename": "mystic_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 23 + }, + "frame": { + "x": 237, + "y": 212, + "w": 20, + "h": 23 + } + }, { "filename": "hard_meteorite", "rotated": false, @@ -4665,8 +4665,8 @@ "h": 22 }, "frame": { - "x": 213, - "y": 191, + "x": 237, + "y": 235, "w": 20, "h": 22 } @@ -4686,12 +4686,75 @@ "h": 21 }, "frame": { - "x": 233, - "y": 193, + "x": 237, + "y": 257, "w": 22, "h": 21 } }, + { + "filename": "potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 302, + "y": 105, + "w": 17, + "h": 23 + } + }, + { + "filename": "wellspring_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 319, + "y": 107, + "w": 23, + "h": 21 + } + }, + { + "filename": "reviver_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 8, + "w": 23, + "h": 20 + }, + "frame": { + "x": 302, + "y": 128, + "w": 23, + "h": 20 + } + }, { "filename": "scroll_of_darkness", "rotated": false, @@ -4707,117 +4770,12 @@ "h": 22 }, "frame": { - "x": 255, - "y": 193, + "x": 342, + "y": 107, "w": 22, "h": 22 } }, - { - "filename": "douse_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 277, - "y": 194, - "w": 23, - "h": 17 - } - }, - { - "filename": "relic_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 9, - "w": 17, - "h": 16 - }, - "frame": { - "x": 125, - "y": 213, - "w": 17, - "h": 16 - } - }, - { - "filename": "shock_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 142, - "y": 213, - "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": 165, - "y": 213, - "w": 23, - "h": 17 - } - }, - { - "filename": "malicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 188, - "y": 213, - "w": 22, - "h": 20 - } - }, { "filename": "scroll_of_waters", "rotated": false, @@ -4833,8 +4791,8 @@ "h": 22 }, "frame": { - "x": 210, - "y": 213, + "x": 364, + "y": 107, "w": 22, "h": 22 } @@ -4854,12 +4812,75 @@ "h": 22 }, "frame": { - "x": 232, - "y": 214, + "x": 386, + "y": 107, "w": 22, "h": 22 } }, + { + "filename": "oval_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 19 + }, + "frame": { + "x": 408, + "y": 108, + "w": 18, + "h": 19 + } + }, + { + "filename": "sitrus_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 239, + "y": 278, + "w": 20, + "h": 22 + } + }, + { + "filename": "upgrade", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 258, + "y": 149, + "w": 22, + "h": 19 + } + }, { "filename": "starf_berry", "rotated": false, @@ -4875,8 +4896,8 @@ "h": 22 }, "frame": { - "x": 254, - "y": 215, + "x": 259, + "y": 168, "w": 22, "h": 22 } @@ -4896,8 +4917,8 @@ "h": 22 }, "frame": { - "x": 300, - "y": 197, + "x": 258, + "y": 190, "w": 22, "h": 22 } @@ -4917,8 +4938,8 @@ "h": 22 }, "frame": { - "x": 322, - "y": 197, + "x": 257, + "y": 212, "w": 22, "h": 22 } @@ -4938,12 +4959,33 @@ "h": 22 }, "frame": { - "x": 344, - "y": 197, + "x": 257, + "y": 234, "w": 22, "h": 22 } }, + { + "filename": "metal_alloy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 21, + "h": 19 + }, + "frame": { + "x": 280, + "y": 149, + "w": 21, + "h": 19 + } + }, { "filename": "tm_bug", "rotated": false, @@ -4959,8 +5001,8 @@ "h": 22 }, "frame": { - "x": 366, - "y": 197, + "x": 281, + "y": 168, "w": 22, "h": 22 } @@ -4980,54 +5022,12 @@ "h": 22 }, "frame": { - "x": 129, - "y": 230, + "x": 280, + "y": 190, "w": 22, "h": 22 } }, - { - "filename": "sharp_beak", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 130, - "y": 252, - "w": 21, - "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": 130, - "y": 275, - "w": 21, - "h": 23 - } - }, { "filename": "tm_dragon", "rotated": false, @@ -5043,8 +5043,8 @@ "h": 22 }, "frame": { - "x": 151, - "y": 230, + "x": 279, + "y": 212, "w": 22, "h": 22 } @@ -5064,8 +5064,8 @@ "h": 22 }, "frame": { - "x": 151, - "y": 252, + "x": 279, + "y": 234, "w": 22, "h": 22 } @@ -5085,138 +5085,12 @@ "h": 22 }, "frame": { - "x": 151, - "y": 274, + "x": 259, + "y": 256, "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": 137, - "y": 298, - "w": 17, - "h": 23 - } - }, - { - "filename": "sachet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 18, - "h": 23 - }, - "frame": { - "x": 137, - "y": 321, - "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": 138, - "y": 344, - "w": 17, - "h": 23 - } - }, - { - "filename": "lock_capsule", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 154, - "y": 296, - "w": 19, - "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": 138, - "y": 367, - "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": 155, - "y": 318, - "w": 20, - "h": 22 - } - }, { "filename": "tm_fighting", "rotated": false, @@ -5232,8 +5106,8 @@ "h": 22 }, "frame": { - "x": 155, - "y": 340, + "x": 259, + "y": 278, "w": 22, "h": 22 } @@ -5253,75 +5127,12 @@ "h": 22 }, "frame": { - "x": 157, - "y": 362, + "x": 281, + "y": 256, "w": 22, "h": 22 } }, - { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 173, - "y": 230, - "w": 15, - "h": 11 - } - }, - { - "filename": "metronome", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 173, - "y": 241, - "w": 17, - "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": 173, - "y": 263, - "w": 17, - "h": 22 - } - }, { "filename": "tm_flying", "rotated": false, @@ -5337,14 +5148,224 @@ "h": 22 }, "frame": { - "x": 173, - "y": 285, + "x": 281, + "y": 278, "w": 22, "h": 22 } }, { - "filename": "dawn_stone", + "filename": "baton", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 408, + "y": 127, + "w": 18, + "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": 325, + "y": 128, + "w": 17, + "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": 342, + "y": 129, + "w": 23, + "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": 365, + "y": 129, + "w": 22, + "h": 20 + } + }, + { + "filename": "poison_barb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 387, + "y": 129, + "w": 21, + "h": 21 + } + }, + { + "filename": "candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 11, + "w": 18, + "h": 18 + }, + "frame": { + "x": 408, + "y": 145, + "w": 18, + "h": 18 + } + }, + { + "filename": "douse_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 195, + "y": 300, + "w": 23, + "h": 17 + } + }, + { + "filename": "relic_crown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 18 + }, + "frame": { + "x": 218, + "y": 300, + "w": 23, + "h": 18 + } + }, + { + "filename": "fairy_feather", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 20 + }, + "frame": { + "x": 241, + "y": 300, + "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": 263, + "y": 300, + "w": 22, + "h": 20 + } + }, + { + "filename": "big_nugget", "rotated": false, "trimmed": true, "sourceSize": { @@ -5355,13 +5376,76 @@ "x": 6, "y": 6, "w": 20, - "h": 21 + "h": 20 }, "frame": { - "x": 190, - "y": 233, + "x": 285, + "y": 300, "w": 20, - "h": 21 + "h": 20 + } + }, + { + "filename": "shock_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 155, + "y": 305, + "w": 23, + "h": 17 + } + }, + { + "filename": "lucky_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 178, + "y": 305, + "w": 17, + "h": 20 + } + }, + { + "filename": "wise_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 195, + "y": 317, + "w": 23, + "h": 17 } }, { @@ -5379,8 +5463,8 @@ "h": 21 }, "frame": { - "x": 210, - "y": 235, + "x": 218, + "y": 318, "w": 22, "h": 21 } @@ -5400,33 +5484,12 @@ "h": 21 }, "frame": { - "x": 232, - "y": 236, + "x": 240, + "y": 320, "w": 22, "h": 21 } }, - { - "filename": "gb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 190, - "y": 254, - "w": 20, - "h": 20 - } - }, { "filename": "tart_apple", "rotated": false, @@ -5442,14 +5505,14 @@ "h": 21 }, "frame": { - "x": 254, - "y": 237, + "x": 262, + "y": 320, "w": 22, "h": 21 } }, { - "filename": "tera_orb", + "filename": "shiny_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -5459,14 +5522,35 @@ "spriteSourceSize": { "x": 5, "y": 6, - "w": 22, - "h": 20 + "w": 21, + "h": 21 }, "frame": { - "x": 210, - "y": 256, - "w": 22, - "h": 20 + "x": 284, + "y": 320, + "w": 21, + "h": 21 + } + }, + { + "filename": "alakazite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 139, + "y": 309, + "w": 16, + "h": 16 } }, { @@ -5484,12 +5568,54 @@ "h": 22 }, "frame": { - "x": 232, - "y": 257, + "x": 135, + "y": 325, "w": 22, "h": 22 } }, + { + "filename": "zoom_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 157, + "y": 322, + "w": 21, + "h": 21 + } + }, + { + "filename": "metronome", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 178, + "y": 325, + "w": 17, + "h": 22 + } + }, { "filename": "tm_grass", "rotated": false, @@ -5505,12 +5631,54 @@ "h": 22 }, "frame": { - "x": 254, - "y": 258, + "x": 136, + "y": 347, "w": 22, "h": 22 } }, + { + "filename": "blue_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 158, + "y": 343, + "w": 20, + "h": 20 + } + }, + { + "filename": "super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 141, + "y": 369, + "w": 17, + "h": 23 + } + }, { "filename": "tm_ground", "rotated": false, @@ -5526,12 +5694,54 @@ "h": 22 }, "frame": { - "x": 175, - "y": 307, + "x": 158, + "y": 363, "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": 141, + "y": 392, + "w": 19, + "h": 22 + } + }, + { + "filename": "tera_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 195, + "y": 334, + "w": 22, + "h": 20 + } + }, { "filename": "tm_ice", "rotated": false, @@ -5547,8 +5757,8 @@ "h": 22 }, "frame": { - "x": 177, - "y": 329, + "x": 217, + "y": 339, "w": 22, "h": 22 } @@ -5568,8 +5778,8 @@ "h": 22 }, "frame": { - "x": 179, - "y": 351, + "x": 239, + "y": 341, "w": 22, "h": 22 } @@ -5589,8 +5799,8 @@ "h": 22 }, "frame": { - "x": 179, - "y": 373, + "x": 261, + "y": 341, "w": 22, "h": 22 } @@ -5610,14 +5820,14 @@ "h": 22 }, "frame": { - "x": 157, - "y": 384, + "x": 283, + "y": 341, "w": 22, "h": 22 } }, { - "filename": "upgrade", + "filename": "tm_rock", "rotated": false, "trimmed": true, "sourceSize": { @@ -5626,36 +5836,15 @@ }, "spriteSourceSize": { "x": 5, - "y": 7, + "y": 5, "w": 22, - "h": 19 + "h": 22 }, "frame": { - "x": 109, - "y": 406, + "x": 160, + "y": 385, "w": 22, - "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": 131, - "y": 406, - "w": 21, - "h": 19 + "h": 22 } }, { @@ -5673,8 +5862,8 @@ "h": 19 }, "frame": { - "x": 152, - "y": 406, + "x": 160, + "y": 407, "w": 20, "h": 19 } @@ -5694,14 +5883,14 @@ "h": 19 }, "frame": { - "x": 172, - "y": 406, + "x": 180, + "y": 407, "w": 20, "h": 19 } }, { - "filename": "absolite", + "filename": "altarianite", "rotated": false, "trimmed": true, "sourceSize": { @@ -5715,14 +5904,14 @@ "h": 16 }, "frame": { - "x": 116, - "y": 390, + "x": 178, + "y": 347, "w": 16, "h": 16 } }, { - "filename": "aerodactylite", + "filename": "leftovers", "rotated": false, "trimmed": true, "sourceSize": { @@ -5731,35 +5920,14 @@ }, "spriteSourceSize": { "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 132, - "y": 390, - "w": 16, - "h": 16 - } - }, - { - "filename": "tm_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, "y": 5, - "w": 22, + "w": 15, "h": 22 }, "frame": { - "x": 388, - "y": 198, - "w": 22, + "x": 180, + "y": 363, + "w": 15, "h": 22 } }, @@ -5778,12 +5946,33 @@ "h": 22 }, "frame": { - "x": 277, - "y": 211, + "x": 182, + "y": 385, "w": 22, "h": 22 } }, + { + "filename": "razor_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 200, + "y": 407, + "w": 20, + "h": 19 + } + }, { "filename": "tm_water", "rotated": false, @@ -5799,8 +5988,8 @@ "h": 22 }, "frame": { - "x": 276, - "y": 233, + "x": 195, + "y": 354, "w": 22, "h": 22 } @@ -5820,8 +6009,8 @@ "h": 22 }, "frame": { - "x": 276, - "y": 255, + "x": 217, + "y": 361, "w": 22, "h": 22 } @@ -5841,8 +6030,8 @@ "h": 22 }, "frame": { - "x": 299, - "y": 219, + "x": 239, + "y": 363, "w": 22, "h": 22 } @@ -5862,8 +6051,8 @@ "h": 22 }, "frame": { - "x": 321, - "y": 219, + "x": 261, + "y": 363, "w": 22, "h": 22 } @@ -5883,12 +6072,54 @@ "h": 22 }, "frame": { - "x": 343, - "y": 219, + "x": 283, + "y": 363, "w": 22, "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": 204, + "y": 385, + "w": 17, + "h": 22 + } + }, + { + "filename": "white_herb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 220, + "y": 407, + "w": 20, + "h": 19 + } + }, { "filename": "x_defense", "rotated": false, @@ -5904,8 +6135,8 @@ "h": 22 }, "frame": { - "x": 365, - "y": 219, + "x": 221, + "y": 385, "w": 22, "h": 22 } @@ -5925,12 +6156,33 @@ "h": 22 }, "frame": { - "x": 298, - "y": 241, + "x": 243, + "y": 385, "w": 22, "h": 22 } }, + { + "filename": "miracle_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 240, + "y": 407, + "w": 19, + "h": 19 + } + }, { "filename": "x_sp_def", "rotated": false, @@ -5946,8 +6198,8 @@ "h": 22 }, "frame": { - "x": 320, - "y": 241, + "x": 265, + "y": 385, "w": 22, "h": 22 } @@ -5967,117 +6219,12 @@ "h": 22 }, "frame": { - "x": 342, - "y": 241, + "x": 287, + "y": 385, "w": 22, "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": 364, - "y": 241, - "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": 387, - "y": 220, - "w": 21, - "h": 21 - } - }, - { - "filename": "golden_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 408, - "y": 220, - "w": 17, - "h": 20 - } - }, - { - "filename": "shiny_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 385, - "y": 241, - "w": 21, - "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": 406, - "y": 241, - "w": 19, - "h": 21 - } - }, { "filename": "masterpiece_teacup", "rotated": false, @@ -6093,8 +6240,8 @@ "h": 18 }, "frame": { - "x": 298, - "y": 263, + "x": 259, + "y": 407, "w": 21, "h": 18 } @@ -6114,14 +6261,14 @@ "h": 18 }, "frame": { - "x": 319, - "y": 263, + "x": 280, + "y": 407, "w": 21, "h": 18 } }, { - "filename": "unremarkable_teacup", + "filename": "dark_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -6129,20 +6276,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 7, "y": 7, - "w": 21, + "w": 18, "h": 18 }, "frame": { - "x": 340, - "y": 263, - "w": 21, + "x": 301, + "y": 407, + "w": 18, "h": 18 } }, { - "filename": "zoom_lens", + "filename": "relic_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -6150,20 +6297,41 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 + "x": 9, + "y": 11, + "w": 15, + "h": 11 }, "frame": { - "x": 276, - "y": 277, - "w": 21, - "h": 21 + "x": 0, + "y": 414, + "w": 15, + "h": 11 } }, { - "filename": "everstone", + "filename": "full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 4, + "w": 15, + "h": 23 + }, + "frame": { + "x": 301, + "y": 212, + "w": 15, + "h": 23 + } + }, + { + "filename": "quick_claw", "rotated": false, "trimmed": true, "sourceSize": { @@ -6172,15 +6340,78 @@ }, "spriteSourceSize": { "x": 6, - "y": 8, - "w": 20, - "h": 17 + "y": 6, + "w": 19, + "h": 21 }, "frame": { - "x": 297, - "y": 281, + "x": 301, + "y": 235, + "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": 303, + "y": 256, + "w": 19, + "h": 21 + } + }, + { + "filename": "candy_jar", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 303, + "y": 277, + "w": 19, + "h": 20 + } + }, + { + "filename": "gb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, "w": 20, - "h": 17 + "h": 20 + }, + "frame": { + "x": 305, + "y": 297, + "w": 20, + "h": 20 } }, { @@ -6198,8 +6429,8 @@ "h": 20 }, "frame": { - "x": 317, - "y": 281, + "x": 305, + "y": 317, "w": 20, "h": 20 } @@ -6219,54 +6450,12 @@ "h": 20 }, "frame": { - "x": 337, - "y": 281, + "x": 305, + "y": 337, "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": 357, - "y": 281, - "w": 19, - "h": 20 - } - }, - { - "filename": "baton", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 361, - "y": 263, - "w": 18, - "h": 18 - } - }, { "filename": "pb", "rotated": false, @@ -6282,12 +6471,33 @@ "h": 20 }, "frame": { - "x": 379, - "y": 262, + "x": 305, + "y": 357, "w": 20, "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": 309, + "y": 377, + "w": 19, + "h": 20 + } + }, { "filename": "pb_gold", "rotated": false, @@ -6303,33 +6513,12 @@ "h": 20 }, "frame": { - "x": 399, - "y": 262, + "x": 302, + "y": 148, "w": 20, "h": 20 } }, - { - "filename": "razor_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 376, - "y": 282, - "w": 20, - "h": 19 - } - }, { "filename": "rb", "rotated": false, @@ -6345,33 +6534,12 @@ "h": 20 }, "frame": { - "x": 396, - "y": 282, + "x": 322, + "y": 148, "w": 20, "h": 20 } }, - { - "filename": "spell_tag", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 19, - "h": 21 - }, - "frame": { - "x": 192, - "y": 395, - "w": 19, - "h": 21 - } - }, { "filename": "smooth_meteorite", "rotated": false, @@ -6387,8 +6555,8 @@ "h": 20 }, "frame": { - "x": 211, - "y": 276, + "x": 303, + "y": 168, "w": 20, "h": 20 } @@ -6408,8 +6576,8 @@ "h": 20 }, "frame": { - "x": 231, - "y": 279, + "x": 342, + "y": 149, "w": 20, "h": 20 } @@ -6429,14 +6597,14 @@ "h": 20 }, "frame": { - "x": 251, - "y": 280, + "x": 362, + "y": 149, "w": 20, "h": 20 } }, { - "filename": "mystery_egg", + "filename": "flame_orb", "rotated": false, "trimmed": true, "sourceSize": { @@ -6444,20 +6612,20 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, + "x": 7, + "y": 7, + "w": 18, "h": 18 }, "frame": { - "x": 195, - "y": 276, - "w": 16, + "x": 323, + "y": 168, + "w": 18, "h": 18 } }, { - "filename": "white_herb", + "filename": "unremarkable_teacup", "rotated": false, "trimmed": true, "sourceSize": { @@ -6465,16 +6633,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 6, + "x": 5, "y": 7, - "w": 20, - "h": 19 + "w": 21, + "h": 18 }, "frame": { - "x": 211, - "y": 296, - "w": 20, - "h": 19 + "x": 341, + "y": 169, + "w": 21, + "h": 18 } }, { @@ -6492,8 +6660,8 @@ "h": 18 }, "frame": { - "x": 231, - "y": 299, + "x": 362, + "y": 169, "w": 20, "h": 18 } @@ -6513,54 +6681,12 @@ "h": 18 }, "frame": { - "x": 251, - "y": 300, + "x": 382, + "y": 150, "w": 20, "h": 18 } }, - { - "filename": "hard_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 271, - "y": 298, - "w": 19, - "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": 290, - "y": 298, - "w": 19, - "h": 19 - } - }, { "filename": "wl_awakening", "rotated": false, @@ -6576,8 +6702,8 @@ "h": 18 }, "frame": { - "x": 309, - "y": 301, + "x": 382, + "y": 168, "w": 20, "h": 18 } @@ -6597,12 +6723,33 @@ "h": 18 }, "frame": { - "x": 329, - "y": 301, + "x": 402, + "y": 163, "w": 20, "h": 18 } }, + { + "filename": "everstone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 17 + }, + "frame": { + "x": 402, + "y": 181, + "w": 20, + "h": 17 + } + }, { "filename": "wl_custom_spliced", "rotated": false, @@ -6618,8 +6765,8 @@ "h": 18 }, "frame": { - "x": 349, - "y": 301, + "x": 382, + "y": 186, "w": 20, "h": 18 } @@ -6639,8 +6786,8 @@ "h": 18 }, "frame": { - "x": 369, - "y": 301, + "x": 402, + "y": 198, "w": 20, "h": 18 } @@ -6660,14 +6807,14 @@ "h": 18 }, "frame": { - "x": 389, - "y": 302, + "x": 303, + "y": 188, "w": 20, "h": 18 } }, { - "filename": "aggronite", + "filename": "light_ball", "rotated": false, "trimmed": true, "sourceSize": { @@ -6675,37 +6822,16 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 + "x": 7, + "y": 7, + "w": 18, + "h": 18 }, "frame": { - "x": 409, - "y": 302, - "w": 16, - "h": 16 - } - }, - { - "filename": "alakazite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 409, - "y": 318, - "w": 16, - "h": 16 + "x": 323, + "y": 186, + "w": 18, + "h": 18 } }, { @@ -6723,8 +6849,8 @@ "h": 18 }, "frame": { - "x": 211, - "y": 315, + "x": 341, + "y": 187, "w": 20, "h": 18 } @@ -6744,12 +6870,33 @@ "h": 18 }, "frame": { - "x": 231, - "y": 317, + "x": 361, + "y": 187, "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": 323, + "y": 204, + "w": 18, + "h": 18 + } + }, { "filename": "wl_full_restore", "rotated": false, @@ -6765,8 +6912,8 @@ "h": 18 }, "frame": { - "x": 251, - "y": 318, + "x": 341, + "y": 205, "w": 20, "h": 18 } @@ -6786,33 +6933,12 @@ "h": 18 }, "frame": { - "x": 271, - "y": 318, + "x": 361, + "y": 205, "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": 291, - "y": 317, - "w": 18, - "h": 19 - } - }, { "filename": "wl_hyper_potion", "rotated": false, @@ -6828,8 +6954,8 @@ "h": 18 }, "frame": { - "x": 309, - "y": 319, + "x": 381, + "y": 204, "w": 20, "h": 18 } @@ -6849,8 +6975,8 @@ "h": 18 }, "frame": { - "x": 329, - "y": 319, + "x": 401, + "y": 216, "w": 20, "h": 18 } @@ -6870,8 +6996,8 @@ "h": 18 }, "frame": { - "x": 349, - "y": 319, + "x": 381, + "y": 222, "w": 20, "h": 18 } @@ -6891,8 +7017,8 @@ "h": 18 }, "frame": { - "x": 369, - "y": 319, + "x": 401, + "y": 234, "w": 20, "h": 18 } @@ -6912,33 +7038,12 @@ "h": 18 }, "frame": { - "x": 389, - "y": 320, + "x": 320, + "y": 222, "w": 20, "h": 18 } }, - { - "filename": "altarianite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 409, - "y": 334, - "w": 16, - "h": 16 - } - }, { "filename": "wl_max_ether", "rotated": false, @@ -6954,54 +7059,12 @@ "h": 18 }, "frame": { - "x": 199, - "y": 333, + "x": 340, + "y": 223, "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": 201, - "y": 351, - "w": 18, - "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": 201, - "y": 371, - "w": 17, - "h": 20 - } - }, { "filename": "wl_max_potion", "rotated": false, @@ -7017,12 +7080,96 @@ "h": 18 }, "frame": { - "x": 219, - "y": 335, + "x": 360, + "y": 223, "w": 20, "h": 18 } }, + { + "filename": "ampharosite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 320, + "y": 240, + "w": 16, + "h": 16 + } + }, + { + "filename": "mystery_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 18 + }, + "frame": { + "x": 322, + "y": 256, + "w": 16, + "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": 322, + "y": 274, + "w": 18, + "h": 18 + } + }, + { + "filename": "eviolite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 336, + "y": 241, + "w": 15, + "h": 15 + } + }, { "filename": "wl_max_revive", "rotated": false, @@ -7038,8 +7185,8 @@ "h": 18 }, "frame": { - "x": 219, - "y": 353, + "x": 351, + "y": 241, "w": 20, "h": 18 } @@ -7059,8 +7206,8 @@ "h": 18 }, "frame": { - "x": 218, - "y": 371, + "x": 325, + "y": 292, "w": 20, "h": 18 } @@ -7080,8 +7227,8 @@ "h": 18 }, "frame": { - "x": 239, - "y": 336, + "x": 325, + "y": 310, "w": 20, "h": 18 } @@ -7101,8 +7248,8 @@ "h": 18 }, "frame": { - "x": 259, - "y": 336, + "x": 325, + "y": 328, "w": 20, "h": 18 } @@ -7122,8 +7269,8 @@ "h": 18 }, "frame": { - "x": 279, - "y": 336, + "x": 325, + "y": 346, "w": 20, "h": 18 } @@ -7143,159 +7290,12 @@ "h": 18 }, "frame": { - "x": 239, - "y": 354, + "x": 371, + "y": 241, "w": 20, "h": 18 } }, - { - "filename": "candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 11, - "w": 18, - "h": 18 - }, - "frame": { - "x": 259, - "y": 354, - "w": 18, - "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": 277, - "y": 354, - "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": 238, - "y": 372, - "w": 18, - "h": 18 - } - }, - { - "filename": "light_ball", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 256, - "y": 372, - "w": 18, - "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": 274, - "y": 372, - "w": 18, - "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": 299, - "y": 337, - "w": 18, - "h": 18 - } - }, - { - "filename": "ampharosite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 317, - "y": 337, - "w": 16, - "h": 16 - } - }, { "filename": "audinite", "rotated": false, @@ -7311,8 +7311,8 @@ "h": 16 }, "frame": { - "x": 333, - "y": 337, + "x": 328, + "y": 364, "w": 16, "h": 16 } @@ -7332,12 +7332,33 @@ "h": 16 }, "frame": { - "x": 349, - "y": 337, + "x": 328, + "y": 380, "w": 16, "h": 16 } }, + { + "filename": "prism_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 338, + "y": 259, + "w": 15, + "h": 15 + } + }, { "filename": "beedrillite", "rotated": false, @@ -7353,8 +7374,8 @@ "h": 16 }, "frame": { - "x": 365, - "y": 337, + "x": 353, + "y": 259, "w": 16, "h": 16 } @@ -7374,8 +7395,8 @@ "h": 16 }, "frame": { - "x": 295, - "y": 355, + "x": 369, + "y": 259, "w": 16, "h": 16 } @@ -7395,8 +7416,8 @@ "h": 16 }, "frame": { - "x": 381, - "y": 338, + "x": 385, + "y": 259, "w": 16, "h": 16 } @@ -7416,8 +7437,8 @@ "h": 16 }, "frame": { - "x": 311, - "y": 355, + "x": 401, + "y": 252, "w": 16, "h": 16 } @@ -7437,8 +7458,8 @@ "h": 16 }, "frame": { - "x": 327, - "y": 353, + "x": 401, + "y": 268, "w": 16, "h": 16 } @@ -7458,8 +7479,8 @@ "h": 16 }, "frame": { - "x": 343, - "y": 353, + "x": 340, + "y": 275, "w": 16, "h": 16 } @@ -7479,8 +7500,8 @@ "h": 16 }, "frame": { - "x": 359, - "y": 353, + "x": 356, + "y": 275, "w": 16, "h": 16 } @@ -7500,8 +7521,8 @@ "h": 16 }, "frame": { - "x": 375, - "y": 354, + "x": 372, + "y": 275, "w": 16, "h": 16 } @@ -7521,8 +7542,8 @@ "h": 16 }, "frame": { - "x": 391, - "y": 354, + "x": 345, + "y": 291, "w": 16, "h": 16 } @@ -7542,8 +7563,8 @@ "h": 16 }, "frame": { - "x": 407, - "y": 350, + "x": 345, + "y": 307, "w": 16, "h": 16 } @@ -7563,8 +7584,8 @@ "h": 16 }, "frame": { - "x": 407, - "y": 366, + "x": 361, + "y": 291, "w": 16, "h": 16 } @@ -7584,8 +7605,8 @@ "h": 16 }, "frame": { - "x": 211, - "y": 391, + "x": 345, + "y": 323, "w": 16, "h": 16 } @@ -7605,8 +7626,8 @@ "h": 16 }, "frame": { - "x": 211, - "y": 407, + "x": 361, + "y": 307, "w": 16, "h": 16 } @@ -7626,8 +7647,8 @@ "h": 16 }, "frame": { - "x": 227, - "y": 390, + "x": 345, + "y": 339, "w": 16, "h": 16 } @@ -7647,8 +7668,8 @@ "h": 16 }, "frame": { - "x": 227, - "y": 406, + "x": 361, + "y": 323, "w": 16, "h": 16 } @@ -7668,8 +7689,8 @@ "h": 16 }, "frame": { - "x": 243, - "y": 390, + "x": 361, + "y": 339, "w": 16, "h": 16 } @@ -7689,8 +7710,8 @@ "h": 16 }, "frame": { - "x": 243, - "y": 406, + "x": 377, + "y": 291, "w": 16, "h": 16 } @@ -7710,8 +7731,8 @@ "h": 16 }, "frame": { - "x": 259, - "y": 390, + "x": 377, + "y": 307, "w": 16, "h": 16 } @@ -7731,8 +7752,8 @@ "h": 16 }, "frame": { - "x": 259, - "y": 406, + "x": 377, + "y": 323, "w": 16, "h": 16 } @@ -7752,8 +7773,8 @@ "h": 16 }, "frame": { - "x": 275, - "y": 390, + "x": 377, + "y": 339, "w": 16, "h": 16 } @@ -7773,8 +7794,8 @@ "h": 16 }, "frame": { - "x": 275, - "y": 406, + "x": 345, + "y": 355, "w": 16, "h": 16 } @@ -7794,8 +7815,8 @@ "h": 16 }, "frame": { - "x": 292, - "y": 372, + "x": 361, + "y": 355, "w": 16, "h": 16 } @@ -7815,8 +7836,8 @@ "h": 16 }, "frame": { - "x": 308, - "y": 371, + "x": 377, + "y": 355, "w": 16, "h": 16 } @@ -7836,7 +7857,7 @@ "h": 16 }, "frame": { - "x": 324, + "x": 344, "y": 371, "w": 16, "h": 16 @@ -7857,8 +7878,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 369, + "x": 360, + "y": 371, "w": 16, "h": 16 } @@ -7878,8 +7899,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 369, + "x": 376, + "y": 371, "w": 16, "h": 16 } @@ -7899,8 +7920,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 370, + "x": 344, + "y": 387, "w": 16, "h": 16 } @@ -7920,8 +7941,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 370, + "x": 360, + "y": 387, "w": 16, "h": 16 } @@ -7941,8 +7962,8 @@ "h": 16 }, "frame": { - "x": 292, - "y": 388, + "x": 376, + "y": 387, "w": 16, "h": 16 } @@ -7962,8 +7983,8 @@ "h": 16 }, "frame": { - "x": 308, - "y": 387, + "x": 328, + "y": 396, "w": 16, "h": 16 } @@ -7983,8 +8004,8 @@ "h": 16 }, "frame": { - "x": 324, - "y": 387, + "x": 344, + "y": 403, "w": 16, "h": 16 } @@ -8004,8 +8025,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 385, + "x": 360, + "y": 403, "w": 16, "h": 16 } @@ -8025,8 +8046,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 385, + "x": 376, + "y": 403, "w": 16, "h": 16 } @@ -8046,8 +8067,8 @@ "h": 16 }, "frame": { - "x": 291, - "y": 404, + "x": 393, + "y": 284, "w": 16, "h": 16 } @@ -8067,8 +8088,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 386, + "x": 393, + "y": 300, "w": 16, "h": 16 } @@ -8088,8 +8109,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 386, + "x": 393, + "y": 316, "w": 16, "h": 16 } @@ -8109,8 +8130,8 @@ "h": 16 }, "frame": { - "x": 404, - "y": 382, + "x": 393, + "y": 332, "w": 16, "h": 16 } @@ -8130,8 +8151,8 @@ "h": 16 }, "frame": { - "x": 404, - "y": 398, + "x": 393, + "y": 348, "w": 16, "h": 16 } @@ -8151,8 +8172,8 @@ "h": 16 }, "frame": { - "x": 340, - "y": 401, + "x": 409, + "y": 284, "w": 16, "h": 16 } @@ -8172,8 +8193,8 @@ "h": 16 }, "frame": { - "x": 356, - "y": 401, + "x": 409, + "y": 300, "w": 16, "h": 16 } @@ -8193,8 +8214,8 @@ "h": 16 }, "frame": { - "x": 372, - "y": 402, + "x": 409, + "y": 316, "w": 16, "h": 16 } @@ -8214,8 +8235,8 @@ "h": 16 }, "frame": { - "x": 388, - "y": 402, + "x": 409, + "y": 332, "w": 16, "h": 16 } @@ -8226,6 +8247,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:4669e332ee400e355936594c14e7221c:1a1f5a801c94e8eb8589e13bc50105a1:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:6dd58685cd89890a4361a424b59bfe65:ff9159978f3a103ee1d656fb76e37457:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 9de02d9e0e95643ae8f183cbaf08f9e55acbbe6c..23c87cf3204bcb5b3b69eaa1775a9ce81d0952c7 100644 GIT binary patch literal 57239 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 IM6N<$f@McVP5=M^ literal 56828 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 nRA*pg-6VRbq!a^DJKgGXoru- 1) { + effectiveness.value = 0.5; + return true; + } + + return false; + } +} + /** * Lowers the amount of starter points available. */ @@ -785,6 +828,14 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType * @returns True if any challenge was successfully applied. */ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.FIXED_BATTLES, waveIndex: Number, battleConfig: FixedBattleConfig): boolean; +/** + * Apply all challenges that modify type effectiveness. + * @param gameMode {@linkcode GameMode} The current gameMode + * @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS + * @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. + * @returns True if any challenge was successfully applied. + */ +export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: Utils.NumberHolder): boolean; /** * Apply all challenges that modify what level AI are. * @param gameMode {@link GameMode} The current gameMode @@ -866,6 +917,9 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType case ChallengeType.FIXED_BATTLES: ret ||= c.applyFixedBattle(args[0], args[1]); break; + case ChallengeType.TYPE_EFFECTIVENESS: + ret ||= c.applyTypeEffectiveness(args[0]); + break; case ChallengeType.AI_LEVEL: ret ||= c.applyLevelChange(args[0], args[1], args[2], args[3]); break; @@ -907,6 +961,8 @@ export function copyChallenge(source: Challenge | any): Challenge { return LowerStarterPointsChallenge.loadChallenge(source); case Challenges.FRESH_START: return FreshStartChallenge.loadChallenge(source); + case Challenges.INVERSE_BATTLE: + return InverseBattleChallenge.loadChallenge(source); } throw new Error("Unknown challenge copied"); } @@ -918,5 +974,6 @@ export function initChallenges() { new SingleGenerationChallenge(), new SingleTypeChallenge(), new FreshStartChallenge(), + new InverseBattleChallenge(), ); } diff --git a/src/data/move.ts b/src/data/move.ts index c8043282b00..d50dc7e2074 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4,7 +4,7 @@ import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTr import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects } from "./status-effect"; -import { getTypeResistances, Type } from "./type"; +import { getTypeDamageMultiplier, Type } from "./type"; import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; @@ -37,6 +37,9 @@ import { StatChangePhase } from "#app/phases/stat-change-phase"; import { SwitchPhase } from "#app/phases/switch-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { SpeciesFormChangeRevertWeatherFormTrigger } from "./pokemon-forms"; +import { NumberHolder } from "#app/utils"; +import { GameMode } from "#app/game-mode"; +import { applyChallenges, ChallengeType } from "./challenge"; export enum MoveCategory { PHYSICAL, @@ -4180,8 +4183,12 @@ export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultipli apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const multiplier = args[0] as Utils.NumberHolder; if (target.isOfType(Type.WATER)) { - multiplier.value *= 4; // Increased twice because initial reduction against water - return true; + const effectivenessAgainstWater = new Utils.NumberHolder(getTypeDamageMultiplier(move.type, Type.WATER)); + applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstWater); + if (effectivenessAgainstWater.value !== 0) { + multiplier.value *= 2 / effectivenessAgainstWater.value; + return true; + } } return false; @@ -6203,7 +6210,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { return false; } const userTypes = user.getTypes(); - const validTypes = getTypeResistances(moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types + const validTypes = this.getTypeResistances(user.scene.gameMode, moveData.type).filter(t => !userTypes.includes(t)); // valid types are ones that are not already the user's types if (!validTypes.length) { return false; } @@ -6215,6 +6222,25 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { return true; } + /** + * Retrieve the types resisting a given type. Used by Conversion 2 + * @returns An array populated with Types, or an empty array if no resistances exist (Unknown or Stellar type) + */ + getTypeResistances(gameMode: GameMode, type: number): Type[] { + const typeResistances: Type[] = []; + + for (let i = 0; i < Object.keys(Type).length; i++) { + const multiplier = new NumberHolder(1); + multiplier.value = getTypeDamageMultiplier(type, i); + applyChallenges(gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier); + if (multiplier.value < 1) { + typeResistances.push(i); + } + } + + return typeResistances; + } + getCondition(): MoveConditionFunc { return (user, target, move) => { const moveHistory = target.getLastXMoves(); @@ -7940,7 +7966,8 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_OTHERS), new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6) .attr(StatusEffectAttr, StatusEffect.FREEZE) - .attr(WaterSuperEffectTypeMultiplierAttr), + .attr(WaterSuperEffectTypeMultiplierAttr) + .partial(), // This currently just multiplies the move's power instead of changing its effectiveness. It also doesn't account for abilities that modify type effectiveness such as tera shell. new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6) .soundBased() .target(MoveTarget.ALL_NEAR_ENEMIES), diff --git a/src/data/type.ts b/src/data/type.ts index 7a9f7f3605e..47bea8dd72b 100644 --- a/src/data/type.ts +++ b/src/data/type.ts @@ -23,7 +23,7 @@ export enum Type { export type TypeDamageMultiplier = 0 | 0.125 | 0.25 | 0.5 | 1 | 2 | 4 | 8; -export function getTypeDamageMultiplier(attackType: integer, defType: integer): TypeDamageMultiplier { +export function getTypeDamageMultiplier(attackType: Type, defType: Type): TypeDamageMultiplier { if (attackType === Type.UNKNOWN || defType === Type.UNKNOWN) { return 1; } @@ -33,26 +33,10 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): switch (attackType) { case Type.FIGHTING: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.ROCK: - case Type.BUG: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.ICE: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.GHOST: - default: return 0; + default: + return 1; } case Type.FIGHTING: switch (attackType) { @@ -60,25 +44,12 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.PSYCHIC: case Type.FAIRY: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.POISON: - case Type.GROUND: - case Type.GHOST: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.ICE: - case Type.DRAGON: - return 1; case Type.ROCK: case Type.BUG: case Type.DARK: return 0.5; default: - return 0; + return 1; } case Type.FLYING: switch (attackType) { @@ -86,43 +57,20 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.ELECTRIC: case Type.ICE: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.POISON: - case Type.GHOST: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.FIGHTING: case Type.BUG: case Type.GRASS: return 0.5; case Type.GROUND: - default: return 0; + default: + return 1; } case Type.POISON: switch (attackType) { case Type.GROUND: case Type.PSYCHIC: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.ROCK: - case Type.GHOST: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.ELECTRIC: - case Type.ICE: - case Type.DRAGON: - case Type.DARK: - return 1; case Type.FIGHTING: case Type.POISON: case Type.BUG: @@ -130,7 +78,7 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.FAIRY: return 0.5; default: - return 0; + return 1; } case Type.GROUND: switch (attackType) { @@ -138,25 +86,13 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.GRASS: case Type.ICE: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.FLYING: - case Type.GROUND: - case Type.BUG: - case Type.GHOST: - case Type.STEEL: - case Type.FIRE: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.POISON: case Type.ROCK: return 0.5; case Type.ELECTRIC: - default: return 0; + default: + return 1; } case Type.ROCK: switch (attackType) { @@ -166,23 +102,13 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.WATER: case Type.GRASS: return 2; - case Type.ROCK: - case Type.BUG: - case Type.GHOST: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.ICE: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.NORMAL: case Type.FLYING: case Type.POISON: case Type.FIRE: return 0.5; default: - return 0; + return 1; } case Type.BUG: switch (attackType) { @@ -190,51 +116,26 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.ROCK: case Type.FIRE: return 2; - case Type.NORMAL: - case Type.POISON: - case Type.BUG: - case Type.GHOST: - case Type.STEEL: - case Type.WATER: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.ICE: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.FIGHTING: case Type.GROUND: case Type.GRASS: return 0.5; default: - return 0; + return 1; } case Type.GHOST: switch (attackType) { case Type.GHOST: case Type.DARK: return 2; - case Type.FLYING: - case Type.GROUND: - case Type.ROCK: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.ICE: - case Type.DRAGON: - case Type.FAIRY: - return 1; case Type.POISON: case Type.BUG: return 0.5; case Type.NORMAL: case Type.FIGHTING: - default: return 0; + default: + return 1; } case Type.STEEL: switch (attackType) { @@ -242,11 +143,6 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.GROUND: case Type.FIRE: return 2; - case Type.GHOST: - case Type.WATER: - case Type.ELECTRIC: - case Type.DARK: - return 1; case Type.NORMAL: case Type.FLYING: case Type.ROCK: @@ -259,8 +155,9 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.FAIRY: return 0.5; case Type.POISON: - default: return 0; + default: + return 1; } case Type.FIRE: switch (attackType) { @@ -268,16 +165,6 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.ROCK: case Type.WATER: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.FLYING: - case Type.POISON: - case Type.GHOST: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - return 1; case Type.BUG: case Type.STEEL: case Type.FIRE: @@ -286,33 +173,20 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.FAIRY: return 0.5; default: - return 0; + return 1; } case Type.WATER: switch (attackType) { case Type.GRASS: case Type.ELECTRIC: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.ROCK: - case Type.BUG: - case Type.GHOST: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.STEEL: case Type.FIRE: case Type.WATER: case Type.ICE: return 0.5; default: - return 0; + return 1; } case Type.GRASS: switch (attackType) { @@ -322,49 +196,24 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.FIRE: case Type.ICE: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.ROCK: - case Type.GHOST: - case Type.STEEL: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.GROUND: case Type.WATER: case Type.GRASS: case Type.ELECTRIC: return 0.5; default: - return 0; + return 1; } case Type.ELECTRIC: switch (attackType) { case Type.GROUND: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.POISON: - case Type.ROCK: - case Type.BUG: - case Type.GHOST: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.PSYCHIC: - case Type.ICE: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.FLYING: case Type.STEEL: case Type.ELECTRIC: return 0.5; default: - return 0; + return 1; } case Type.PSYCHIC: switch (attackType) { @@ -372,25 +221,11 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.GHOST: case Type.DARK: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.ROCK: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.ICE: - case Type.DRAGON: - case Type.FAIRY: - return 1; case Type.FIGHTING: case Type.PSYCHIC: return 0.5; default: - return 0; + return 1; } case Type.ICE: switch (attackType) { @@ -399,24 +234,10 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.STEEL: case Type.FIRE: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.BUG: - case Type.GHOST: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.DRAGON: - case Type.DARK: - case Type.FAIRY: - return 1; case Type.ICE: return 0.5; default: - return 0; + return 1; } case Type.DRAGON: switch (attackType) { @@ -424,25 +245,13 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.DRAGON: case Type.FAIRY: return 2; - case Type.NORMAL: - case Type.FIGHTING: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.ROCK: - case Type.BUG: - case Type.GHOST: - case Type.STEEL: - case Type.PSYCHIC: - case Type.DARK: - return 1; case Type.FIRE: case Type.WATER: case Type.GRASS: case Type.ELECTRIC: return 0.5; default: - return 0; + return 1; } case Type.DARK: switch (attackType) { @@ -450,106 +259,33 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.BUG: case Type.FAIRY: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.POISON: - case Type.GROUND: - case Type.ROCK: - case Type.STEEL: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.ICE: - case Type.DRAGON: - return 1; case Type.GHOST: case Type.DARK: return 0.5; case Type.PSYCHIC: - default: return 0; + default: + return 1; } case Type.FAIRY: switch (attackType) { case Type.POISON: case Type.STEEL: return 2; - case Type.NORMAL: - case Type.FLYING: - case Type.GROUND: - case Type.ROCK: - case Type.GHOST: - case Type.FIRE: - case Type.WATER: - case Type.GRASS: - case Type.ELECTRIC: - case Type.PSYCHIC: - case Type.ICE: - case Type.FAIRY: - return 1; case Type.FIGHTING: case Type.BUG: case Type.DARK: return 0.5; case Type.DRAGON: - default: return 0; + default: + return 1; } case Type.STELLAR: return 1; } - return 0; -} - -/** - * Retrieve the types resisting a given type - * @returns An array populated with Types, or an empty array if no resistances exist (Unknown or Stellar type) - */ -export function getTypeResistances(type: number): Type[] { - switch (type) { - case Type.NORMAL: - return [Type.ROCK, Type.STEEL, Type.GHOST]; - case Type.FIGHTING: - return [Type.FLYING, Type.POISON, Type.BUG, Type.PSYCHIC, Type.FAIRY, Type.GHOST]; - case Type.FLYING: - return [Type.ROCK, Type.ELECTRIC, Type.STEEL]; - case Type.POISON: - return [Type.POISON, Type.GROUND, Type.ROCK, Type.GHOST, Type.STEEL]; - case Type.GROUND: - return [Type.BUG, Type.GRASS, Type.FLYING]; - case Type.ROCK: - return [Type.FIGHTING, Type.GROUND, Type.STEEL]; - case Type.BUG: - return [Type.FIGHTING, Type.FLYING, Type.POISON, Type.GHOST, Type.STEEL, Type.FIRE, Type.FAIRY]; - case Type.GHOST: - return [Type.DARK, Type.NORMAL]; - case Type.STEEL: - return [Type.STEEL, Type.FIRE, Type.WATER, Type.ELECTRIC]; - case Type.FIRE: - return [Type.ROCK, Type.FIRE, Type.WATER, Type.DRAGON]; - case Type.WATER: - return [Type.WATER, Type.GRASS, Type.DRAGON]; - case Type.GRASS: - return [Type.FLYING, Type.POISON, Type.BUG, Type.STEEL, Type.FIRE, Type.GRASS, Type.DRAGON]; - case Type.ELECTRIC: - return [Type.GRASS, Type.ELECTRIC, Type.DRAGON, Type.GROUND]; - case Type.PSYCHIC: - return [Type.STEEL, Type.PSYCHIC]; - case Type.ICE: - return [Type.STEEL, Type.FIRE, Type.WATER, Type.ICE]; - case Type.DRAGON: - return [Type.STEEL, Type.FAIRY]; - case Type.DARK: - return [Type.FIGHTING, Type.DARK, Type.FAIRY]; - case Type.FAIRY: - return [Type.POISON, Type.STEEL, Type.FIRE]; - case Type.UNKNOWN: - case Type.STELLAR: - default: - return []; - } + return 1; } /** diff --git a/src/enums/challenges.ts b/src/enums/challenges.ts index 690e1cdc32d..c4dc7460dfe 100644 --- a/src/enums/challenges.ts +++ b/src/enums/challenges.ts @@ -3,5 +3,6 @@ export enum Challenges { SINGLE_TYPE, LOWER_MAX_STARTER_COST, LOWER_STARTER_POINTS, - FRESH_START + FRESH_START, + INVERSE_BATTLE, } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8a3a6b280cb..58764ff1046 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -49,6 +49,7 @@ import { BerryType } from "#enums/berry-type"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Challenges } from "#enums/challenges"; import { getPokemonNameWithAffix } from "#app/messages.js"; import { DamagePhase } from "#app/phases/damage-phase.js"; import { FaintPhase } from "#app/phases/faint-phase.js"; @@ -1315,12 +1316,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return 1; } } - - return getTypeDamageMultiplier(moveType, defType); + const multiplier = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, defType)); + applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier); + return multiplier.value; }).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier; + const typeMultiplierAgainstFlying = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, Type.FLYING)); + applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, typeMultiplierAgainstFlying); // Handle strong winds lowering effectiveness of types super effective against pure flying - if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) { + if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && typeMultiplierAgainstFlying.value === 2) { multiplier /= 2; if (!simulated) { this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage")); @@ -3852,6 +3856,9 @@ export class EnemyPokemon extends Pokemon { new PokemonMove(Moves.FLAMETHROWER), new PokemonMove(Moves.COSMIC_POWER) ]; + if (this.scene.gameMode.hasChallenge(Challenges.INVERSE_BATTLE)) { + this.moveset[2] = new PokemonMove(Moves.THUNDERBOLT); + } break; default: super.generateAndPopulateMoveset(); diff --git a/src/locales/de/achv.json b/src/locales/de/achv.json index 0649bcf3169..d2e56089720 100644 --- a/src/locales/de/achv.json +++ b/src/locales/de/achv.json @@ -269,5 +269,9 @@ "FRESH_START": { "name": "Hussa, noch einmal von vorn!", "description": "Schließe die 'Neuanfang' Herausforderung ab" + }, + "INVERSE_BATTLE": { + "name": "Spieglein, Spieglein an der Wand", + "description": "Schließe die 'Umkehrkampf' Herausforderung ab" } } \ No newline at end of file diff --git a/src/locales/de/challenges.json b/src/locales/de/challenges.json index 1b41a707a81..17c33353bc6 100644 --- a/src/locales/de/challenges.json +++ b/src/locales/de/challenges.json @@ -25,5 +25,12 @@ "desc": "Du kannst nur die ursprünglichen Starter verwenden, genau so, als hättest du gerade erst mit Pokérogue begonnen.", "value.0": "Aus", "value.1": "An" + }, + "inverseBattle": { + "name": "Umkehrkampf", + "shortName": "Umkehrkampf", + "desc": "Die Typen-Effektivität wird umgekehrt, und kein Typ ist gegen einen anderen Typ immun.\nDeaktiviert die Erfolge anderer Herausforderungen.", + "value.0": "Aus", + "value.1": "An" } } \ No newline at end of file diff --git a/src/locales/en/achv-female.json b/src/locales/en/achv-female.json index ec695c3ed2a..edcd8c53fb7 100644 --- a/src/locales/en/achv-female.json +++ b/src/locales/en/achv-female.json @@ -260,5 +260,9 @@ "FRESH_START": { "name": "First Try!", "description": "Complete the Fresh Start challenge." + }, + "INVERSE_BATTLE": { + "name": "Mirror rorriM", + "description": "Complete the Inverse Battle challenge.\n.egnellahc elttaB esrevnI eht etelpmoC" } } \ No newline at end of file diff --git a/src/locales/en/achv.json b/src/locales/en/achv.json index 185b42d181a..0ed746c77b3 100644 --- a/src/locales/en/achv.json +++ b/src/locales/en/achv.json @@ -279,5 +279,9 @@ "FRESH_START": { "name": "First Try!", "description": "Complete the Fresh Start challenge." + }, + "INVERSE_BATTLE": { + "name": "Mirror rorriM", + "description": "Complete the Inverse Battle challenge.\n.egnellahc elttaB esrevnI eht etelpmoC" } } \ No newline at end of file diff --git a/src/locales/en/challenges.json b/src/locales/en/challenges.json index c89fa7a21bf..f189266cea2 100644 --- a/src/locales/en/challenges.json +++ b/src/locales/en/challenges.json @@ -25,5 +25,12 @@ "desc": "You can only use the original starters, and only as if you had just started PokéRogue.", "value.0": "Off", "value.1": "On" + }, + "inverseBattle": { + "name": "Inverse Battle", + "shortName": "Inverse", + "desc": "Type matchups are reversed and no type is immune to any other type.\nDisables other challenges' achievements.", + "value.0": "Off", + "value.1": "On" } } \ No newline at end of file diff --git a/src/locales/es/achv.json b/src/locales/es/achv.json index c3a22c566d0..c94b8858233 100644 --- a/src/locales/es/achv.json +++ b/src/locales/es/achv.json @@ -170,5 +170,9 @@ "CLASSIC_VICTORY": { "name": "Imbatible", "description": "Completa el juego en modo clásico." + }, + "INVERSE_BATTLE": { + "name": "Espejo ojepsE", + "description": "Completa el reto de Combate Inverso.\n.osrevnI etabmoC ed oter le atelpmoC" } } \ No newline at end of file diff --git a/src/locales/es/challenges.json b/src/locales/es/challenges.json index a855f3dbc2b..6a7db8c10c3 100644 --- a/src/locales/es/challenges.json +++ b/src/locales/es/challenges.json @@ -18,5 +18,12 @@ "name": "Monotipo", "desc": "Solo puedes usar Pokémon with the {{type}} type.", "desc_default": "Solo puedes usar Pokémon del tipo elegido." + }, + "inverseBattle": { + "name": "Combate Inverso", + "shortName": "Inverso", + "desc": "La efectividad de los tipos es invertida. No hay inmunidades entre tipos.\nEste reto deshabilita logros de otros retos.", + "value.0": "Desactivado", + "value.1": "Activado" } } \ No newline at end of file diff --git a/src/locales/fr/achv.json b/src/locales/fr/achv.json index f83fa3079f2..60655ae22cf 100644 --- a/src/locales/fr/achv.json +++ b/src/locales/fr/achv.json @@ -274,5 +274,9 @@ "FRESH_START": { "name": "Du premier coup !", "description": "Terminer un challenge « Nouveau départ »." + }, + "INVERSE_BATTLE": { + "name": "La teuté à verlan", + "description": "Terminer un challenge en Combat Inversé.\nMineter un lenjcha en Ba-con Versin." } } diff --git a/src/locales/fr/challenges.json b/src/locales/fr/challenges.json index 50a8e34f298..a83ec2e0be4 100644 --- a/src/locales/fr/challenges.json +++ b/src/locales/fr/challenges.json @@ -25,5 +25,12 @@ "desc": "Vous ne pouvez choisir que les starters de base du jeu, comme si vous le recommenciez.", "value.0": "Non", "value.1": "Oui" + }, + "inverseBattle": { + "name": "Combat Inversé", + "shortName": "Inversé", + "desc": "Les affinités de la table des types sont inversées et plus aucun type n’a d’immunité.\nDésactive les succès des autres challenges.", + "value.0": "Non", + "value.1": "Oui" } } \ No newline at end of file diff --git a/src/locales/ja/challenges.json b/src/locales/ja/challenges.json index 29f6ca835fe..54225ebf766 100644 --- a/src/locales/ja/challenges.json +++ b/src/locales/ja/challenges.json @@ -22,6 +22,7 @@ }, "freshStart": { "name": "出直し", + "shortName": "出直し", "desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の 最初のパートナーしか 使えません", "value.0": "オフ", "value.1": "オン" diff --git a/src/locales/ko/achv.json b/src/locales/ko/achv.json index 73753dd9b5a..8546dff949c 100644 --- a/src/locales/ko/achv.json +++ b/src/locales/ko/achv.json @@ -260,5 +260,9 @@ "FRESH_START": { "name": "첫트!", "description": "새 출발 챌린지 모드 클리어." + }, + "INVERSE_BATTLE": { + "name": "상성 전문가(였던 것)", + "description": "거꾸로 배틀 챌린지 모드 클리어." } } \ No newline at end of file diff --git a/src/locales/ko/challenges.json b/src/locales/ko/challenges.json index 433b0990e87..7efdfef3570 100644 --- a/src/locales/ko/challenges.json +++ b/src/locales/ko/challenges.json @@ -25,5 +25,12 @@ "desc": "포켓로그를 처음 시작했던 때처럼 강화가 전혀 되지 않은 오리지널 스타팅 포켓몬만 고를 수 있습니다.", "value.0": "해제", "value.1": "설정" + }, + "inverseBattle": { + "name": "거꾸로 배틀", + "shortName": "거꾸로", + "desc": "타입 상성이 반대로 바뀌고 면역 타입은 약점 타입이 됩니다.\n설정 시 다른 챌린지 업적은 달성할 수 없습니다.", + "value.0": "해제", + "value.1": "설정" } } \ No newline at end of file diff --git a/src/locales/pt_BR/achv.json b/src/locales/pt_BR/achv.json index aee3dd48cc5..acdec1ae306 100644 --- a/src/locales/pt_BR/achv.json +++ b/src/locales/pt_BR/achv.json @@ -264,5 +264,9 @@ "FRESH_START": { "name": "De Primeira!", "description": "Complete o desafio de novo começo." + }, + "INVERSE_BATTLE": { + "name": "A torre da derrotA", + "description": "Complete o desafio da Batalha Inversa.\n.asrevnI ahlataB ad oifased o etelpmoC" } } \ No newline at end of file diff --git a/src/locales/pt_BR/challenges.json b/src/locales/pt_BR/challenges.json index 43a40e29b56..6b20a92f4f6 100644 --- a/src/locales/pt_BR/challenges.json +++ b/src/locales/pt_BR/challenges.json @@ -25,5 +25,12 @@ "desc": "Você só pode usar os iniciais originais, como se tivesse acabado de começar o PokéRogue.", "value.0": "Desligado", "value.1": "Ligado" + }, + "inverseBattle": { + "name": "Batalha Inversa", + "shortName": "Inversa", + "desc": "Fraquezas e resistências de tipos são invertidas e nenhum tipo é imune a outro tipo.\nDesativa as conquistas de outros desafios.", + "value.0": "Desligado", + "value.1": "Ligado" } } \ No newline at end of file diff --git a/src/locales/zh_CN/achv.json b/src/locales/zh_CN/achv.json index 103a9bb41b5..8de0c48a2c3 100644 --- a/src/locales/zh_CN/achv.json +++ b/src/locales/zh_CN/achv.json @@ -268,5 +268,9 @@ "FRESH_START": { "name": "初次尝试!", "description": "完成初次尝试挑战" + }, + "INVERSE_BATTLE": { + "name": "镜子子镜", + "description": "完成逆转之战挑战\n战挑战之转逆成完" } } diff --git a/src/locales/zh_CN/challenges.json b/src/locales/zh_CN/challenges.json index 0b454d759fb..9351ec96285 100644 --- a/src/locales/zh_CN/challenges.json +++ b/src/locales/zh_CN/challenges.json @@ -25,5 +25,12 @@ "desc": "你只能使用御三家,就像是你第一次玩宝可梦肉鸽一样。", "value.0": "关闭", "value.1": "开启" + }, + "inverseBattle": { + "name": "逆转之战", + "shortName": "逆转之战", + "desc": "属性相克关系被反转,且没有任何属性对其他属性免疫。\n禁用其他挑战的成就。", + "value.0": "关闭", + "value.1": "开启" } } \ No newline at end of file diff --git a/src/locales/zh_TW/achv.json b/src/locales/zh_TW/achv.json index dcd6f26ae82..6587394cf41 100644 --- a/src/locales/zh_TW/achv.json +++ b/src/locales/zh_TW/achv.json @@ -252,5 +252,9 @@ }, "MONO_FAIRY": { "name": "林克,醒醒!" + }, + "INVERSE_BATTLE": { + "name": "鏡子子鏡", + "description": "完成逆轉之戰挑戰\n戰挑戰之轉逆成完" } } \ No newline at end of file diff --git a/src/locales/zh_TW/challenges.json b/src/locales/zh_TW/challenges.json index c6c4f90e65e..a1fc6b8f50f 100644 --- a/src/locales/zh_TW/challenges.json +++ b/src/locales/zh_TW/challenges.json @@ -19,5 +19,12 @@ "name": "單屬性", "desc": "你只能使用{{type}}\n屬性的寶可夢", "desc_default": "你只能使用所選\n屬性的寶可夢" + }, + "inverseBattle": { + "name": "逆轉之戰", + "shortName": "逆轉之戰", + "desc": "屬性相克關系被反轉,且沒有任何屬性對其他屬性免疫。\n禁用其他挑戰的成就。", + "value.0": "關閉", + "value.1": "開啓" } } \ No newline at end of file diff --git a/src/system/achv.ts b/src/system/achv.ts index 0f9bc5ac6de..5436cce24ab 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -5,8 +5,9 @@ import { pokemonEvolutions } from "#app/data/pokemon-evolutions"; import i18next from "i18next"; import * as Utils from "../utils"; import { PlayerGender } from "#enums/player-gender"; -import { Challenge, FreshStartChallenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge.js"; -import { ConditionFn } from "#app/@types/common.js"; +import { Challenge, FreshStartChallenge, InverseBattleChallenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge"; +import { Challenges } from "#app/enums/challenges"; +import { ConditionFn } from "#app/@types/common"; export enum AchvTier { COMMON, @@ -137,8 +138,8 @@ 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))); + constructor(localizationKey: string, name: string, description: string, iconImage: string, score: integer, challengeFunc: (challenge: Challenge, scene: BattleScene) => boolean) { + super(localizationKey, name, description, iconImage, score, (_scene: BattleScene, args: any[]) => challengeFunc(args[0] as Challenge, _scene)); } } @@ -275,6 +276,8 @@ export function getAchievementDescription(localizationKey: string): string { return i18next.t("achv:MonoType.description", { context: genderStr, "type": i18next.t(`pokemonInfo:Type.${localizationKey.slice(5)}`) }); case "FRESH_START": return i18next.t("achv:FRESH_START.description", { context: genderStr }); + case "INVERSE_BATTLE": + return i18next.t("achv:INVERSE_BATTLE.description", { context: genderStr }); default: return ""; } @@ -323,34 +326,35 @@ export const achvs = { PERFECT_IVS: new Achv("PERFECT_IVS", "", "PERFECT_IVS.description", "blunder_policy", 100), CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY", "", "CLASSIC_VICTORY.description", "relic_crown", 150), UNEVOLVED_CLASSIC_VICTORY: new Achv("UNEVOLVED_CLASSIC_VICTORY", "", "UNEVOLVED_CLASSIC_VICTORY.description", "eviolite", 175, c => c.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)), - MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE", "", "MONO_GEN_ONE.description", "ribbon_gen1", 100, c => c instanceof SingleGenerationChallenge && c.value === 1), - MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO", "", "MONO_GEN_TWO.description", "ribbon_gen2", 100, c => c instanceof SingleGenerationChallenge && c.value === 2), - MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE", "", "MONO_GEN_THREE.description", "ribbon_gen3", 100, c => c instanceof SingleGenerationChallenge && c.value === 3), - MONO_GEN_FOUR_VICTORY: new ChallengeAchv("MONO_GEN_FOUR", "", "MONO_GEN_FOUR.description", "ribbon_gen4", 100, c => c instanceof SingleGenerationChallenge && c.value === 4), - MONO_GEN_FIVE_VICTORY: new ChallengeAchv("MONO_GEN_FIVE", "", "MONO_GEN_FIVE.description", "ribbon_gen5", 100, c => c instanceof SingleGenerationChallenge && c.value === 5), - MONO_GEN_SIX_VICTORY: new ChallengeAchv("MONO_GEN_SIX", "", "MONO_GEN_SIX.description", "ribbon_gen6", 100, c => c instanceof SingleGenerationChallenge && c.value === 6), - MONO_GEN_SEVEN_VICTORY: new ChallengeAchv("MONO_GEN_SEVEN", "", "MONO_GEN_SEVEN.description", "ribbon_gen7", 100, c => c instanceof SingleGenerationChallenge && c.value === 7), - MONO_GEN_EIGHT_VICTORY: new ChallengeAchv("MONO_GEN_EIGHT", "", "MONO_GEN_EIGHT.description", "ribbon_gen8", 100, c => c instanceof SingleGenerationChallenge && c.value === 8), - MONO_GEN_NINE_VICTORY: new ChallengeAchv("MONO_GEN_NINE", "", "MONO_GEN_NINE.description", "ribbon_gen9", 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), - FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, c => c instanceof FreshStartChallenge && c.value === 1), + MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE", "", "MONO_GEN_ONE.description", "ribbon_gen1", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 1 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO", "", "MONO_GEN_TWO.description", "ribbon_gen2", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 2 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE", "", "MONO_GEN_THREE.description", "ribbon_gen3", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 3 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_FOUR_VICTORY: new ChallengeAchv("MONO_GEN_FOUR", "", "MONO_GEN_FOUR.description", "ribbon_gen4", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 4 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_FIVE_VICTORY: new ChallengeAchv("MONO_GEN_FIVE", "", "MONO_GEN_FIVE.description", "ribbon_gen5", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 5 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_SIX_VICTORY: new ChallengeAchv("MONO_GEN_SIX", "", "MONO_GEN_SIX.description", "ribbon_gen6", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 6 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_SEVEN_VICTORY: new ChallengeAchv("MONO_GEN_SEVEN", "", "MONO_GEN_SEVEN.description", "ribbon_gen7", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 7 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_EIGHT_VICTORY: new ChallengeAchv("MONO_GEN_EIGHT", "", "MONO_GEN_EIGHT.description", "ribbon_gen8", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 8 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GEN_NINE_VICTORY: new ChallengeAchv("MONO_GEN_NINE", "", "MONO_GEN_NINE.description", "ribbon_gen9", 100, (c, scene) => c instanceof SingleGenerationChallenge && c.value === 9 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_NORMAL: new ChallengeAchv("MONO_NORMAL", "", "MONO_NORMAL.description", "silk_scarf", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 1 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_FIGHTING: new ChallengeAchv("MONO_FIGHTING", "", "MONO_FIGHTING.description", "black_belt", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 2 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_FLYING: new ChallengeAchv("MONO_FLYING", "", "MONO_FLYING.description", "sharp_beak", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 3 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_POISON: new ChallengeAchv("MONO_POISON", "", "MONO_POISON.description", "poison_barb", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 4 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GROUND: new ChallengeAchv("MONO_GROUND", "", "MONO_GROUND.description", "soft_sand", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 5 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_ROCK: new ChallengeAchv("MONO_ROCK", "", "MONO_ROCK.description", "hard_stone", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 6 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_BUG: new ChallengeAchv("MONO_BUG", "", "MONO_BUG.description", "silver_powder", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 7 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GHOST: new ChallengeAchv("MONO_GHOST", "", "MONO_GHOST.description", "spell_tag", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 8 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_STEEL: new ChallengeAchv("MONO_STEEL", "", "MONO_STEEL.description", "metal_coat", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 9 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_FIRE: new ChallengeAchv("MONO_FIRE", "", "MONO_FIRE.description", "charcoal", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 10 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_WATER: new ChallengeAchv("MONO_WATER", "", "MONO_WATER.description", "mystic_water", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 11 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_GRASS: new ChallengeAchv("MONO_GRASS", "", "MONO_GRASS.description", "miracle_seed", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 12 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_ELECTRIC: new ChallengeAchv("MONO_ELECTRIC", "", "MONO_ELECTRIC.description", "magnet", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 13 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_PSYCHIC: new ChallengeAchv("MONO_PSYCHIC", "", "MONO_PSYCHIC.description", "twisted_spoon", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 14 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_ICE: new ChallengeAchv("MONO_ICE", "", "MONO_ICE.description", "never_melt_ice", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 15 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_DRAGON: new ChallengeAchv("MONO_DRAGON", "", "MONO_DRAGON.description", "dragon_fang", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 16 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_DARK: new ChallengeAchv("MONO_DARK", "", "MONO_DARK.description", "black_glasses", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 17 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + MONO_FAIRY: new ChallengeAchv("MONO_FAIRY", "", "MONO_FAIRY.description", "fairy_feather", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 18 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, (c, scene) => c instanceof FreshStartChallenge && c.value > 0 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), + INVERSE_BATTLE: new ChallengeAchv("INVERSE_BATTLE", "", "INVERSE_BATTLE.description", "inverse", 100, c => c instanceof InverseBattleChallenge && c.value > 0), }; export function initAchievements() { diff --git a/src/test/battle/inverse_battle.test.ts b/src/test/battle/inverse_battle.test.ts new file mode 100644 index 00000000000..be8b04155eb --- /dev/null +++ b/src/test/battle/inverse_battle.test.ts @@ -0,0 +1,203 @@ +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { Type } from "#app/data/type"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; +import { Challenges } from "#enums/challenges"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +const TIMEOUT = 20 * 1000; + +describe("Inverse Battle", () => { + 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.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); + + game.override + .battleType("single") + .starterSpecies(Species.FEEBAS) + .ability(Abilities.BALL_FETCH) + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH); + }); + + it("1. immune types are 2x effective - Thunderbolt against Ground Type", async () => { + game.override.enemySpecies(Species.SANDSHREW); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(2); + }, TIMEOUT); + + it("2. 2x effective types are 0.5x effective - Thunderbolt against Flying Type", async () => { + game.override.enemySpecies(Species.PIDGEY); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(0.5); + }, TIMEOUT); + + it("3. 0.5x effective types are 2x effective - Thunderbolt against Electric Type", async () => { + game.override.enemySpecies(Species.CHIKORITA); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.getMoveEffectiveness(player, allMoves[Moves.THUNDERBOLT])).toBe(2); + }, TIMEOUT); + + it("4. Stealth Rock follows the inverse matchups - Stealth Rock against Charizard deals 1/32 of max HP", async () => { + game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0); + game.override + .enemySpecies(Species.CHARIZARD) + .enemyLevel(100); + + await game.challengeMode.startBattle(); + + const charizard = game.scene.getEnemyPokemon()!; + + const maxHp = charizard.getMaxHp(); + const damage_prediction = Math.max(Math.round(charizard.getMaxHp() / 32), 1); + console.log("Damage calcuation before round: " + charizard.getMaxHp() / 32); + const currentHp = charizard.hp; + const expectedHP = maxHp - damage_prediction; + + console.log("Charizard's max HP: " + maxHp, "Damage: " + damage_prediction, "Current HP: " + currentHp, "Expected HP: " + expectedHP); + expect(currentHp).toBeGreaterThan(maxHp * 31 / 32 - 1); + }, TIMEOUT); + + it("5. Freeze Dry is 2x effective against Water Type like other Ice type Move - Freeze Dry against Squirtle", async () => { + game.override.enemySpecies(Species.SQUIRTLE); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.getMoveEffectiveness(player, allMoves[Moves.FREEZE_DRY])).toBe(2); + }, TIMEOUT); + + it("6. Water Absorb should heal against water moves - Water Absorb against Water gun", async () => { + game.override + .moveset([Moves.WATER_GUN]) + .enemyAbility(Abilities.WATER_ABSORB); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + enemy.hp = enemy.getMaxHp() - 1; + game.move.select(Moves.WATER_GUN); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + + await game.phaseInterceptor.to(MoveEndPhase); + + expect(enemy.hp).toBe(enemy.getMaxHp()); + }, TIMEOUT); + + it("7. Fire type does not get burned - Will-O-Wisp against Charmander", async () => { + game.override + .moveset([Moves.WILL_O_WISP]) + .enemySpecies(Species.CHARMANDER); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.WILL_O_WISP); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.move.forceHit(); + + await game.phaseInterceptor.to(MoveEndPhase); + + expect(enemy.status?.effect).not.toBe(StatusEffect.BURN); + }, TIMEOUT); + + it("8. Electric type does not get paralyzed - Nuzzle against Pikachu", async () => { + game.override + .moveset([Moves.NUZZLE]) + .enemySpecies(Species.PIKACHU) + .enemyLevel(50); + + await game.challengeMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.NUZZLE); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + + await game.phaseInterceptor.to(MoveEndPhase); + + expect(enemy.status?.effect).not.toBe(StatusEffect.PARALYSIS); + }, TIMEOUT); + + + it("10. Anticipation should trigger on 2x effective moves - Anticipation against Thunderbolt", async () => { + game.override + .moveset([Moves.THUNDERBOLT]) + .enemySpecies(Species.SANDSHREW) + .enemyAbility(Abilities.ANTICIPATION); + + await game.challengeMode.startBattle(); + + expect(game.scene.getEnemyPokemon()?.summonData.abilitiesApplied[0]).toBe(Abilities.ANTICIPATION); + }, TIMEOUT); + + it("11. Conversion 2 should change the type to the resistive type - Conversion 2 against Dragonite", async () => { + game.override + .moveset([Moves.CONVERSION_2]) + .enemyMoveset([Moves.DRAGON_CLAW, Moves.DRAGON_CLAW, Moves.DRAGON_CLAW, Moves.DRAGON_CLAW]); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.CONVERSION_2); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + await game.phaseInterceptor.to(TurnEndPhase); + + expect(player.getTypes()[0]).toBe(Type.DRAGON); + }, TIMEOUT); + + it("12. Flying Press should be 0.25x effective against Grass + Dark Type - Flying Press against Meowscarada", async () => { + game.override + .moveset([Moves.FLYING_PRESS]) + .enemySpecies(Species.MEOWSCARADA); + + await game.challengeMode.startBattle(); + + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.getMoveEffectiveness(player, allMoves[Moves.FLYING_PRESS])).toBe(0.25); + }, TIMEOUT); +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 6ade758fd6f..60d07065090 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -40,6 +40,7 @@ import fs from "fs"; import { vi } from "vitest"; import { ClassicModeHelper } from "./helpers/classicModeHelper"; import { DailyModeHelper } from "./helpers/dailyModeHelper"; +import { ChallengeModeHelper } from "./helpers/challengeModeHelper"; import { MoveHelper } from "./helpers/moveHelper"; import { OverridesHelper } from "./helpers/overridesHelper"; import { SettingsHelper } from "./helpers/settingsHelper"; @@ -57,6 +58,7 @@ export default class GameManager { public readonly move: MoveHelper; public readonly classicMode: ClassicModeHelper; public readonly dailyMode: DailyModeHelper; + public readonly challengeMode: ChallengeModeHelper; public readonly settings: SettingsHelper; /** @@ -77,6 +79,7 @@ export default class GameManager { this.move = new MoveHelper(this); this.classicMode = new ClassicModeHelper(this); this.dailyMode = new DailyModeHelper(this); + this.challengeMode = new ChallengeModeHelper(this); this.settings = new SettingsHelper(this); } diff --git a/src/test/utils/helpers/challengeModeHelper.ts b/src/test/utils/helpers/challengeModeHelper.ts new file mode 100644 index 00000000000..184f11f505c --- /dev/null +++ b/src/test/utils/helpers/challengeModeHelper.ts @@ -0,0 +1,78 @@ +import { BattleStyle } from "#app/enums/battle-style"; +import { Species } from "#app/enums/species"; +import overrides from "#app/overrides"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { Mode } from "#app/ui/ui"; +import { generateStarter } from "../gameManagerUtils"; +import { GameManagerHelper } from "./gameManagerHelper"; +import { Challenge } from "#app/data/challenge"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { Challenges } from "#enums/challenges"; +import { copyChallenge } from "data/challenge"; + +/** + * Helper to handle Challenge mode specifics + */ +export class ChallengeModeHelper extends GameManagerHelper { + + challenges: Challenge[] = []; + + /** + * Adds a challenge to the challenge mode helper. + * @param id - The challenge id. + * @param value - The challenge value. + * @param severity - The challenge severity. + */ + addChallenge(id: Challenges, value: number, severity: number) { + const challenge = copyChallenge({ id, value, severity }); + this.challenges.push(challenge); + } + + /** + * Runs the Challenge game to the summon phase. + * @param gameMode - Optional game mode to set. + * @returns A promise that resolves when the summon phase is reached. + */ + async runToSummon(species?: Species[]) { + await this.game.runToTitle(); + + this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.game.scene.gameMode.challenges = this.challenges; + const starters = generateStarter(this.game.scene, species); + const selectStarterPhase = new SelectStarterPhase(this.game.scene); + this.game.scene.pushPhase(new EncounterPhase(this.game.scene, false)); + selectStarterPhase.initBattle(starters); + }); + + await this.game.phaseInterceptor.run(EncounterPhase); + if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { + this.game.removeEnemyHeldItems(); + } + } + + /** + * 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. + */ + async startBattle(species?: Species[]) { + await this.runToSummon(species); + + if (this.game.scene.battleStyle === BattleStyle.SWITCH) { + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + } + + await this.game.phaseInterceptor.to(CommandPhase); + console.log("==================[New Turn]=================="); + } +} diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts index ff4ed919e75..25210277edc 100644 --- a/src/ui/run-info-ui-handler.ts +++ b/src/ui/run-info-ui-handler.ts @@ -374,23 +374,14 @@ export default class RunInfoUiHandler extends UiHandler { case GameModes.CHALLENGE: modeText.appendText(`${i18next.t("gameMode:challenge")}`, false); modeText.appendText(`\t\t${i18next.t("runHistory:challengeRules")}: `); - const runChallenges = this.runInfo.challenges; - const rules: string[] = []; - for (let i = 0; i < runChallenges.length; i++) { - if (runChallenges[i].id === Challenges.SINGLE_GENERATION && runChallenges[i].value !== 0) { - rules.push(i18next.t(`runHistory:challengeMonoGen${runChallenges[i].value}`)); - } else if (runChallenges[i].id === Challenges.SINGLE_TYPE && runChallenges[i].value !== 0) { - rules.push(i18next.t(`pokemonInfo:Type.${Type[runChallenges[i].value-1]}` as const)); - } else if (runChallenges[i].id === Challenges.FRESH_START && runChallenges[i].value !== 0) { - rules.push(i18next.t("challenges:freshStart.name")); - } - } + const rules: string[] = this.challengeParser(); if (rules) { for (let i = 0; i < rules.length; i++) { + const newline = i > 0 && i%2 === 0; if (i > 0) { - modeText.appendText(" + ", false); + modeText.appendText(" + ", newline); } - modeText.appendText(rules[i], false); + modeText.appendText(rules[i], newline); } } break; @@ -466,6 +457,34 @@ export default class RunInfoUiHandler extends UiHandler { this.runContainer.add(this.runInfoContainer); } + /** + * This function parses the Challenges section of the Run Entry and returns a list of active challenge. + * @return string[] of active challenge names + */ + private challengeParser(): string[] { + const rules: string[] = []; + for (let i = 0; i < this.runInfo.challenges.length; i++) { + if (this.runInfo.challenges[i].value !== 0) { + switch (this.runInfo.challenges[i].id) { + case Challenges.SINGLE_GENERATION: + rules.push(i18next.t(`runHistory:challengeMonoGen${this.runInfo.challenges[i].value}`)); + break; + case Challenges.SINGLE_TYPE: + rules.push(i18next.t(`pokemonInfo:Type.${Type[this.runInfo.challenges[i].value-1]}` as const)); + break; + case Challenges.FRESH_START: + rules.push(i18next.t("challenges:freshStart.name")); + break; + case Challenges.INVERSE_BATTLE: + // + rules.push(i18next.t("challenges:inverseBattle.shortName").split("").reverse().join("")); + break; + } + } + } + return rules; + } + /** * Parses and displays the run's player party. * Default Information: Icon, Level, Nature, Ability, Passive, Shiny Status, Fusion Status, Stats, and Moves. From db9434ac11b2735ca31d32f755be84ed838f0e42 Mon Sep 17 00:00:00 2001 From: damocleas Date: Thu, 29 Aug 2024 15:29:06 -0400 Subject: [PATCH 02/14] [Balance] Biome Changes / Minor Passive Changes / Minor Egg Move Changes / Beta GMax form adjustments (#3852) * [Balance] Previous Egg/Passive/Eternatus Update Adjustments * Update pokemon-species.ts * Updated Eternatus, src/field/pokemon.ts * Update egg-moves.ts for Drowzee and Darkrai * Update biomes.ts * Update biomes.ts to screw over Dojo! * Update pokemon-species.ts gmax adjustments --- src/data/biomes.ts | 26 +++++++++++++------------- src/data/egg-moves.ts | 6 +++--- src/data/pokemon-species.ts | 12 ++++++------ src/field/pokemon.ts | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index ed579112249..2cdb29a94ec 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -35,36 +35,36 @@ interface BiomeDepths { export const biomeLinks: BiomeLinks = { [Biome.TOWN]: Biome.PLAINS, [Biome.PLAINS]: [ Biome.GRASS, Biome.METROPOLIS, Biome.LAKE ], - [Biome.GRASS]: Biome.TALL_GRASS, + [Biome.GRASS]: [ Biome.TALL_GRASS, [ Biome.CONSTRUCTION_SITE, 2 ] ], [Biome.TALL_GRASS]: [ Biome.FOREST, Biome.CAVE ], [Biome.SLUM]: Biome.CONSTRUCTION_SITE, [Biome.FOREST]: [ Biome.JUNGLE, Biome.MEADOW ], [Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ], [Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ], - [Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 4 ] ], + [Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 3 ] ], [Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP, Biome.CONSTRUCTION_SITE ], - [Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 4 ] ], - [Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 3 ] ], + [Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ], + [Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.DOJO, 2] [ Biome.WASTELAND, 2 ] ], [Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ], [Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE ], - [Biome.DESERT]: Biome.RUINS, + [Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ], [Biome.ICE_CAVE]: Biome.SNOWY_FOREST, - [Biome.MEADOW]: [ Biome.PLAINS, [ Biome.FAIRY_CAVE, 2 ] ], + [Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ], [Biome.POWER_PLANT]: Biome.FACTORY, - [Biome.VOLCANO]: [ Biome.BEACH, [ Biome.ICE_CAVE, 4 ] ], + [Biome.VOLCANO]: [ Biome.BEACH, [ Biome.ICE_CAVE, 3 ] ], [Biome.GRAVEYARD]: Biome.ABYSS, - [Biome.DOJO]: [ Biome.PLAINS, [ Biome.TEMPLE, 3 ] ], - [Biome.FACTORY]: [ Biome.PLAINS, [ Biome.LABORATORY, 4 ] ], + [Biome.DOJO]: [ Biome.PLAINS, [ Biome.JUNGLE, 2], [ Biome.TEMPLE, 2 ] ], + [Biome.FACTORY]: [ Biome.TALL_GRASS, [ Biome.LABORATORY, 3 ] ], [Biome.RUINS]: [ Biome.FOREST ], [Biome.WASTELAND]: Biome.BADLANDS, [Biome.ABYSS]: [ Biome.CAVE, [ Biome.SPACE, 3 ], [ Biome.WASTELAND, 3 ] ], [Biome.SPACE]: Biome.RUINS, - [Biome.CONSTRUCTION_SITE]: [ Biome.DOJO, Biome.POWER_PLANT ], + [Biome.CONSTRUCTION_SITE]: [ Biome.POWER_PLANT, [ Biome.DOJO, 2 ] ], [Biome.JUNGLE]: [ Biome.TEMPLE ], - [Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 3 ] ], - [Biome.TEMPLE]: [ Biome.SWAMP, [ Biome.RUINS, 3 ] ], + [Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 2 ] ], + [Biome.TEMPLE]: [ Biome.DESERT, [ Biome.SWAMP, 2 ], [ Biome.RUINS, 2 ] ], [Biome.METROPOLIS]: Biome.SLUM, - [Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.LAKE, Biome.MOUNTAIN ], + [Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.MOUNTAIN, [ Biome.LAKE, 2 ] ], [Biome.ISLAND]: Biome.SEA, [Biome.LABORATORY]: Biome.CONSTRUCTION_SITE }; diff --git a/src/data/egg-moves.ts b/src/data/egg-moves.ts index f88ac2c71b2..b516238c46e 100644 --- a/src/data/egg-moves.ts +++ b/src/data/egg-moves.ts @@ -43,7 +43,7 @@ export const speciesEggMoves = { [Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ], [Species.GASTLY]: [ Moves.SLUDGE_BOMB, Moves.AURA_SPHERE, Moves.NASTY_PLOT, Moves.ASTRAL_BARRAGE ], [Species.ONIX]: [ Moves.SHORE_UP, Moves.BODY_PRESS, Moves.HEAVY_SLAM, Moves.DIAMOND_STORM ], - [Species.DROWZEE]: [ Moves.BADDY_BAD, Moves.STRENGTH_SAP, Moves.LUMINA_CRASH, Moves.SPORE ], + [Species.DROWZEE]: [ Moves.BADDY_BAD, Moves.STRENGTH_SAP, Moves.LUMINA_CRASH, Moves.DARK_VOID ], [Species.KRABBY]: [ Moves.FIRE_LASH, Moves.PLAY_ROUGH, Moves.IVY_CUDGEL, Moves.SHELL_SMASH ], [Species.VOLTORB]: [ Moves.NASTY_PLOT, Moves.OVERHEAT, Moves.FROST_BREATH, Moves.ELECTRO_DRIFT ], [Species.EXEGGCUTE]: [ Moves.FICKLE_BEAM, Moves.APPLE_ACID, Moves.TRICK_ROOM, Moves.LUMINA_CRASH ], @@ -125,7 +125,7 @@ export const speciesEggMoves = { [Species.SUICUNE]: [ Moves.RECOVER, Moves.NASTY_PLOT, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ], [Species.LARVITAR]: [ Moves.DRAGON_DANCE, Moves.MOUNTAIN_GALE, Moves.SHORE_UP, Moves.DIAMOND_STORM ], [Species.LUGIA]: [ Moves.NASTY_PLOT, Moves.LUMINA_CRASH, Moves.AURA_SPHERE, Moves.OBLIVION_WING ], - [Species.HO_OH]: [ Moves.FLOATY_FALL, Moves.SOLAR_BLADE, Moves.REVIVAL_BLESSING, Moves.BOLT_BEAK ], + [Species.HO_OH]: [ Moves.FLOATY_FALL, Moves.PRECIPICE_BLADES, Moves.REVIVAL_BLESSING, Moves.BOLT_BEAK ], [Species.CELEBI]: [ Moves.PHOTON_GEYSER, Moves.MATCHA_GOTCHA, Moves.REVIVAL_BLESSING, Moves.QUIVER_DANCE ], [Species.TREECKO]: [ Moves.NASTY_PLOT, Moves.APPLE_ACID, Moves.SECRET_SWORD, Moves.DRAGON_ENERGY ], [Species.TORCHIC]: [ Moves.HIGH_JUMP_KICK, Moves.SUPERCELL_SLAM, Moves.KNOCK_OFF, Moves.V_CREATE ], @@ -249,7 +249,7 @@ export const speciesEggMoves = { [Species.CRESSELIA]: [ Moves.COSMIC_POWER, Moves.SECRET_SWORD, Moves.SIZZLY_SLIDE, Moves.LUMINA_CRASH ], [Species.PHIONE]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ], [Species.MANAPHY]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ], - [Species.DARKRAI]: [ Moves.FIERY_WRATH, Moves.MOONBLAST, Moves.SEARING_SHOT, Moves.SPORE ], + [Species.DARKRAI]: [ Moves.FIERY_WRATH, Moves.MOONBLAST, Moves.FIERY_DANCE, Moves.MAKE_IT_RAIN ], [Species.SHAYMIN]: [ Moves.MATCHA_GOTCHA, Moves.FIERY_DANCE, Moves.AEROBLAST, Moves.QUIVER_DANCE ], [Species.ARCEUS]: [ Moves.NO_RETREAT, Moves.COLLISION_COURSE, Moves.ASTRAL_BARRAGE, Moves.MULTI_ATTACK ], [Species.VICTINI]: [ Moves.BLUE_FLARE, Moves.BOLT_STRIKE, Moves.LUSTER_PURGE, Moves.VICTORY_DANCE ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 832f7112748..db601935bfc 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1132,7 +1132,7 @@ export function initSpecies() { ), new PokemonSpecies(Species.SNORLAX, 1, false, false, false, "Sleeping Pokémon", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, GrowthRate.SLOW, 87.5, false, true, new PokemonForm("Normal", "", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, Type.GRASS, 35, 460, Abilities.THICK_FAT, Abilities.THICK_FAT, Abilities.THICK_FAT, 640, 200, 135, 85, 80, 125, 15, 25, 50, 189), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, null, 35, 460, Abilities.THICK_FAT, Abilities.THICK_FAT, Abilities.THICK_FAT, 640, 200, 135, 85, 80, 125, 15, 25, 50, 189), ), new PokemonSpecies(Species.ARTICUNO, 1, true, false, false, "Freeze Pokémon", Type.ICE, Type.FLYING, 1.7, 55.4, Abilities.PRESSURE, Abilities.NONE, Abilities.SNOW_CLOAK, 580, 90, 85, 100, 95, 125, 85, 3, 35, 290, GrowthRate.SLOW, null, false), new PokemonSpecies(Species.ZAPDOS, 1, true, false, false, "Electric Pokémon", Type.ELECTRIC, Type.FLYING, 1.6, 52.6, Abilities.PRESSURE, Abilities.NONE, Abilities.STATIC, 580, 90, 90, 85, 125, 90, 100, 3, 35, 290, GrowthRate.SLOW, null, false), @@ -2252,19 +2252,19 @@ export function initSpecies() { new PokemonSpecies(Species.THWACKEY, 8, false, false, false, "Beat Pokémon", Type.GRASS, null, 0.7, 14, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 420, 70, 85, 70, 55, 60, 80, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.RILLABOOM, 8, false, false, false, "Drummer Pokémon", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true, new PokemonForm("Normal", "", Type.GRASS, null, 2.1, 90, Abilities.OVERGROW, Abilities.NONE, Abilities.GRASSY_SURGE, 530, 100, 125, 90, 60, 70, 85, 45, 50, 265, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.GRASS, null, 28, 90, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, 630, 125, 150, 115, 65, 95, 80, 45, 50, 265), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.GRASS, null, 28, 90, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, Abilities.GRASSY_SURGE, 630, 125, 150, 105, 85, 85, 80, 45, 50, 265), ), new PokemonSpecies(Species.SCORBUNNY, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.3, 4.5, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 310, 50, 71, 40, 40, 40, 69, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.RABOOT, 8, false, false, false, "Rabbit Pokémon", Type.FIRE, null, 0.6, 9, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 420, 65, 86, 60, 55, 60, 94, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.CINDERACE, 8, false, false, false, "Striker Pokémon", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true, new PokemonForm("Normal", "", Type.FIRE, null, 1.4, 33, Abilities.BLAZE, Abilities.NONE, Abilities.LIBERO, 530, 80, 116, 75, 65, 75, 119, 45, 50, 265, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FIRE, null, 27, 33, Abilities.LIBERO, Abilities.LIBERO, Abilities.LIBERO, 630, 90, 151, 85, 85, 85, 134, 45, 50, 265), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.FIRE, null, 27, 33, Abilities.LIBERO, Abilities.LIBERO, Abilities.LIBERO, 630, 100, 146, 80, 90, 80, 134, 45, 50, 265), ), new PokemonSpecies(Species.SOBBLE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.3, 4, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 310, 50, 40, 40, 70, 40, 70, 45, 50, 62, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.DRIZZILE, 8, false, false, false, "Water Lizard Pokémon", Type.WATER, null, 0.7, 11.5, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 420, 65, 60, 55, 95, 55, 90, 45, 50, 147, GrowthRate.MEDIUM_SLOW, 87.5, false), new PokemonSpecies(Species.INTELEON, 8, false, false, false, "Secret Agent Pokémon", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, GrowthRate.MEDIUM_SLOW, 87.5, false, true, new PokemonForm("Normal", "", Type.WATER, null, 1.9, 45.2, Abilities.TORRENT, Abilities.NONE, Abilities.SNIPER, 530, 70, 85, 65, 125, 65, 120, 45, 50, 265, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.WATER, null, 40, 45.2, Abilities.SNIPER, Abilities.SNIPER, Abilities.SNIPER, 630, 90, 90, 85, 150, 85, 130, 45, 50, 265), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.WATER, null, 40, 45.2, Abilities.SNIPER, Abilities.SNIPER, Abilities.SNIPER, 630, 95, 97, 77, 147, 77, 137, 45, 50, 265), ), new PokemonSpecies(Species.SKWOVET, 8, false, false, false, "Cheeky Pokémon", Type.NORMAL, null, 0.3, 2.5, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 275, 70, 55, 55, 35, 35, 25, 255, 50, 55, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.GREEDENT, 8, false, false, false, "Greedy Pokémon", Type.NORMAL, null, 0.6, 6, Abilities.CHEEK_POUCH, Abilities.NONE, Abilities.GLUTTONY, 460, 120, 95, 95, 55, 75, 20, 90, 50, 161, GrowthRate.MEDIUM_FAST, 50, false), @@ -3470,7 +3470,7 @@ export const starterPassiveAbilities = { [Species.SUICUNE]: Abilities.UNAWARE, [Species.LARVITAR]: Abilities.SAND_RUSH, [Species.LUGIA]: Abilities.DELTA_STREAM, - [Species.HO_OH]: Abilities.DROUGHT, + [Species.HO_OH]: Abilities.MAGIC_GUARD, [Species.CELEBI]: Abilities.GRASSY_SURGE, [Species.TREECKO]: Abilities.TINTED_LENS, [Species.TORCHIC]: Abilities.RECKLESS, @@ -3591,7 +3591,7 @@ export const starterPassiveAbilities = { [Species.HEATRAN]: Abilities.EARTH_EATER, [Species.REGIGIGAS]: Abilities.MINDS_EYE, [Species.GIRATINA]: Abilities.SHADOW_SHIELD, - [Species.CRESSELIA]: Abilities.UNAWARE, + [Species.CRESSELIA]: Abilities.SHADOW_SHIELD, [Species.PHIONE]: Abilities.SIMPLE, [Species.MANAPHY]: Abilities.PRIMORDIAL_SEA, [Species.DARKRAI]: Abilities.UNNERVE, diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 58764ff1046..6df486aab39 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3846,7 +3846,7 @@ export class EnemyPokemon extends Pokemon { this.moveset = (formIndex !== undefined ? formIndex : this.formIndex) ? [ new PokemonMove(Moves.DYNAMAX_CANNON), - new PokemonMove(Moves.SLUDGE_BOMB), + new PokemonMove(Moves.CROSS_POISON), new PokemonMove(Moves.FLAMETHROWER), new PokemonMove(Moves.RECOVER, 0, -4) ] From 9833b1da7e67d3041c98bd273add09704e2ce580 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:10:38 -0700 Subject: [PATCH 03/14] [Balance] Randomized Biome after End Biome (#3888) * Biome.END goes somewhere random * this way island is included too * no towns or plains * Enums are dumb --------- Co-authored-by: frutescens --- src/data/biomes.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 2cdb29a94ec..3879053b066 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -7663,6 +7663,12 @@ export function initBiomes() { biomeDepths[Biome.TOWN] = [ 0, 1 ]; const traverseBiome = (biome: Biome, depth: integer) => { + if (biome === Biome.END) { + const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key))); + biomeList.pop(); // Removes Biome.END from the list + const randIndex = Utils.randInt(biomeList.length, 2); // Will never be Biome.TOWN or Biome.PLAINS + biome = Biome[biomeList[randIndex]]; + } const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome]) ? biomeLinks[biome] as (Biome | [ Biome, integer ])[] : [ biomeLinks[biome] as Biome ]; From b2cd21bcb18f4c0929a3d0b2e3e872388a47a7e7 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:13:10 -0400 Subject: [PATCH 04/14] Fix evolution items not working on mons without forms (#3902) --- src/modifier/modifier-type.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 938f73a1e08..3afeb79ff2b 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -791,10 +791,10 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge super("", EvolutionItem[evolutionItem].toLowerCase(), (_type, args) => new Modifiers.EvolutionItemModifier(this, (args[0] as PlayerPokemon).id), (pokemon: PlayerPokemon) => { if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem - && (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === pokemon.getFormKey())).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) { + && (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === null || e.preFormKey === pokemon.getFormKey())).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) { return null; } else if (pokemon.isFusion() && pokemon.fusionSpecies && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem - && (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === pokemon.getFusionFormKey())).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) { + && (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === null || e.preFormKey === pokemon.getFusionFormKey())).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) { return null; } From e4da48f51a279c174a2273258ed4dfc35f450134 Mon Sep 17 00:00:00 2001 From: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:47:37 +0200 Subject: [PATCH 05/14] [Bug] Starter select default attributes fixes (#3870) * Test changes to starter ui stuff for edge case stuff to fix * Minor bug fixes * [starter-ui] cleanup outdated fix * use existing method to get the default form from the caught attributes * clear the existing StarterPreferences of potential invalid values * remember the last variant used even when disabling shiny form * fix variant and shiny checks for edge case with variant flags but no shiny flag * more fixes for invalid starter prefs and default settings --------- Co-authored-by: Opaque02 <66582645+Opaque02@users.noreply.github.com> Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> --- src/system/game-data.ts | 2 + src/ui/starter-select-ui-handler.ts | 362 ++++++++++++++-------------- 2 files changed, 180 insertions(+), 184 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index d10d6288696..f8d13286ca4 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -243,6 +243,8 @@ export class StarterPrefs { if (pStr !== StarterPrefers_private_latest) { // something changed, store the update localStorage.setItem(`starterPrefs_${loggedInUser?.username}`, pStr); + // update the latest prefs + StarterPrefers_private_latest = pStr; } } } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index f9b40dd96e6..267a62104e3 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -915,7 +915,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.allSpecies.forEach((species, s) => { const icon = this.starterContainers[s].icon; const dexEntry = this.scene.gameData.dexData[species.speciesId]; - this.starterPreferences[species.speciesId] = this.starterPreferences[species.speciesId] ?? {}; + + // Initialize the StarterAttributes for this species + this.starterPreferences[species.speciesId] = this.initStarterPrefs(species); if (dexEntry.caughtAttr) { icon.clearTint(); @@ -942,6 +944,93 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return false; } + /** + * Get the starter attributes for the given PokemonSpecies, after sanitizing them. + * If somehow a preference is set for a form, variant, gender, ability or nature + * that wasn't actually unlocked or is invalid it will be cleared here + * + * @param species The species to get Starter Preferences for + * @returns StarterAttributes for the species + */ + initStarterPrefs(species: PokemonSpecies): StarterAttributes { + const starterAttributes = this.starterPreferences[species.speciesId]; + const dexEntry = this.scene.gameData.dexData[species.speciesId]; + const starterData = this.scene.gameData.starterData[species.speciesId]; + + // no preferences or Pokemon wasn't caught, return empty attribute + if (!starterAttributes || !dexEntry.caughtAttr) { + return {}; + } + + const caughtAttr = dexEntry.caughtAttr; + + const hasShiny = caughtAttr & DexAttr.SHINY; + const hasNonShiny = caughtAttr & DexAttr.NON_SHINY; + if (starterAttributes.shiny && !hasShiny) { + // shiny form wasn't unlocked, purging shiny and variant setting + delete starterAttributes.shiny; + delete starterAttributes.variant; + } else if (starterAttributes.shiny === false && !hasNonShiny) { + // non shiny form wasn't unlocked, purging shiny setting + delete starterAttributes.shiny; + } + + if (starterAttributes.variant !== undefined && !isNaN(starterAttributes.variant)) { + const unlockedVariants = [ + hasNonShiny, + hasShiny && caughtAttr & DexAttr.DEFAULT_VARIANT, + hasShiny && caughtAttr & DexAttr.VARIANT_2, + hasShiny && caughtAttr & DexAttr.VARIANT_3 + ]; + if (!unlockedVariants[starterAttributes.variant + 1]) { // add 1 as -1 = non-shiny + // requested variant wasn't unlocked, purging setting + delete starterAttributes.variant; + } + } + + if (starterAttributes.female !== undefined) { + if (!(starterAttributes.female ? caughtAttr & DexAttr.FEMALE : caughtAttr & DexAttr.MALE)) { + // requested gender wasn't unlocked, purging setting + delete starterAttributes.female; + } + } + + if (starterAttributes.ability !== undefined) { + const speciesHasSingleAbility = species.ability2 === species.ability1; + const abilityAttr = starterData.abilityAttr; + const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1; + const hasAbility2 = abilityAttr & AbilityAttr.ABILITY_2; + const hasHiddenAbility = abilityAttr & AbilityAttr.ABILITY_HIDDEN; + // Due to a past bug it is possible that some Pokemon with a single ability have the ability2 flag + // In this case, we only count ability2 as valid if ability1 was not unlocked, otherwise we ignore it + const unlockedAbilities = [ + hasAbility1, + speciesHasSingleAbility ? hasAbility2 && !hasAbility1 : hasAbility2, + hasHiddenAbility + ]; + if (!unlockedAbilities[starterAttributes.ability]) { + // requested ability wasn't unlocked, purging setting + delete starterAttributes.ability; + } + } + + const selectedForm = starterAttributes.form; + if (selectedForm !== undefined && (!species.forms[selectedForm]?.isStarterSelectable || !(caughtAttr & this.scene.gameData.getFormAttr(selectedForm)))) { + // requested form wasn't unlocked/isn't a starter form, purging setting + delete starterAttributes.form; + } + + if (starterAttributes.nature !== undefined) { + const unlockedNatures = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr); + if (unlockedNatures.indexOf(starterAttributes.nature as unknown as Nature) < 0) { + // requested nature wasn't unlocked, purging setting + delete starterAttributes.nature; + } + } + + return starterAttributes; + } + /** * Set the selections for all filters to their default starting value */ @@ -1749,9 +1838,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { switch (button) { case Button.CYCLE_SHINY: if (this.canCycleShiny) { - const newVariant = props.variant; + const newVariant = starterAttributes.variant ? starterAttributes.variant as Variant : props.variant; starterAttributes.shiny = starterAttributes.shiny ? !starterAttributes.shiny : true; - this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, props.shiny ? 0 : undefined, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, props.shiny ? 0 : newVariant, undefined, undefined); if (starterAttributes.shiny) { this.scene.playSound("se/sparkle"); // Set the variant label to the shiny tint @@ -1760,10 +1849,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonShinyIcon.setTint(tint); this.pokemonShinyIcon.setVisible(true); } else { - // starterAttributes.variant = 0; - if (starterAttributes?.variant) { - delete starterAttributes.variant; - } this.pokemonShinyIcon.setVisible(false); success = true; } @@ -2276,43 +2361,39 @@ export default class StarterSelectUiHandler extends MessageUiHandler { container.cost = this.scene.gameData.getSpeciesStarterValue(container.species.speciesId); // First, ensure you have the caught attributes for the species else default to bigint 0 - const isCaught = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0); - - // Define the variables based on whether their respective variants have been caught - const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); - const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); - const isVariantCaught = !!(isCaught & DexAttr.SHINY); - const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught; - const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0; - const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked; - const isCostReduced = this.scene.gameData.starterData[container.species.speciesId].valueReduction > 0; - const isCostReductionUnlockable = this.isValueReductionAvailable(container.species.speciesId); - const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false; - - const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0; - const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0; - const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined; - const isHA = this.scene.gameData.starterData[container.species.speciesId].abilityAttr & AbilityAttr.ABILITY_HIDDEN; - const isEggPurchasable = this.isSameSpeciesEggAvailable(container.species.speciesId); + const caughtAttr = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0); + const starterData = this.scene.gameData.starterData[container.species.speciesId]; + // Gen filter const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation); + // Type filter const fitsType = this.filterBar.getVals(DropDownColumn.TYPES).some(type => container.species.isOfType((type as number) - 1)); + // Caught / Shiny filter + const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY); + const isShinyCaught = !!(caughtAttr & DexAttr.SHINY); + const isVariant1Caught = isShinyCaught && !!(caughtAttr & DexAttr.DEFAULT_VARIANT); + const isVariant2Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_2); + const isVariant3Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_3); + const isUncaught = !isNonShinyCaught && !isVariant1Caught && !isVariant2Caught && !isVariant3Caught; const fitsCaught = this.filterBar.getVals(DropDownColumn.CAUGHT).some(caught => { if (caught === "SHINY3") { return isVariant3Caught; } else if (caught === "SHINY2") { return isVariant2Caught && !isVariant3Caught; } else if (caught === "SHINY") { - return isVariantCaught && !isVariant2Caught && !isVariant3Caught; + return isVariant1Caught && !isVariant2Caught && !isVariant3Caught; } else if (caught === "NORMAL") { - return isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught; + return isNonShinyCaught && !isVariant1Caught && !isVariant2Caught && !isVariant3Caught; } else if (caught === "UNCAUGHT") { return isUncaught; } }); + // Passive Filter + const isPassiveUnlocked = starterData.passiveAttr > 0; + const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked; const fitsPassive = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => { if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.ON) { return isPassiveUnlocked; @@ -2325,6 +2406,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); + // Cost Reduction Filter + const isCostReduced = starterData.valueReduction > 0; + const isCostReductionUnlockable = this.isValueReductionAvailable(container.species.speciesId); const fitsCostReduction = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => { if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.ON) { return isCostReduced; @@ -2337,6 +2421,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); + // Favorite Filter + const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false; const fitsFavorite = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (misc.val === "FAVORITE" && misc.state === DropDownState.ON) { return isFavorite; @@ -2349,28 +2435,34 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); + // Ribbon / Classic Win Filter + const hasWon = starterData.classicWinCount > 0; + const hasNotWon = starterData.classicWinCount === 0; + const isUndefined = starterData.classicWinCount === undefined; const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { - if (container.species.speciesId < 10) { - } if (misc.val === "WIN" && misc.state === DropDownState.ON) { - return isWin; + return hasWon; } else if (misc.val === "WIN" && misc.state === DropDownState.EXCLUDE) { - return isNotWin || isUndefined; + return hasNotWon || isUndefined; } else if (misc.val === "WIN" && misc.state === DropDownState.OFF) { return true; } }); + // HA Filter + const hasHA = starterData.abilityAttr & AbilityAttr.ABILITY_HIDDEN; const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) { - return isHA; + return hasHA; } else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.EXCLUDE) { - return !isHA; + return !hasHA; } else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.OFF) { return true; } }); + // Egg Purchasable Filter + const isEggPurchasable = this.isSameSpeciesEggAvailable(container.species.speciesId); const fitsEgg = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (misc.val === "EGG" && misc.state === DropDownState.ON) { return isEggPurchasable; @@ -2381,6 +2473,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); + // Pokerus Filter const fitsPokerus = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (misc.val === "POKERUS" && misc.state === DropDownState.ON) { return this.pokerusSpecies.includes(container.species); @@ -2579,56 +2672,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0; const starterAttributes : StarterAttributes | null = species ? {...this.starterPreferences[species.speciesId]} : null; - // validate starterAttributes - if (starterAttributes) { - // this may cause changes so we created a copy of the attributes before - if (starterAttributes.variant && !isNaN(starterAttributes.variant)) { - if (![ - this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY, // TODO: is that bang correct? - this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT, // TODO: is that bang correct? - this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2, // TODO: is that bang correct? - this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3 // TODO: is that bang correct? - ][starterAttributes.variant+1]) { // add 1 as -1 = non-shiny - // requested variant wasn't unlocked, purging setting - delete starterAttributes.variant; - } - } - - if (typeof starterAttributes.female !== "boolean" || !(starterAttributes.female ? - this.speciesStarterDexEntry!.caughtAttr & DexAttr.FEMALE : // TODO: is this bang correct? - this.speciesStarterDexEntry!.caughtAttr & DexAttr.MALE // TODO: is this bang correct? - )) { - // requested gender wasn't unlocked, purging setting - delete starterAttributes.female; - } - - const abilityAttr = this.scene.gameData.starterData[species!.speciesId].abilityAttr; // TODO: is this bang correct? - if (![ - abilityAttr & AbilityAttr.ABILITY_1, - species!.ability2 ? (abilityAttr & AbilityAttr.ABILITY_2) : abilityAttr & AbilityAttr.ABILITY_HIDDEN, // TODO: is this bang correct? - species!.ability2 && abilityAttr & AbilityAttr.ABILITY_HIDDEN // TODO: is this bang correct? - ][starterAttributes.ability!]) { // TODO: is this bang correct? - // requested ability wasn't unlocked, purging setting - delete starterAttributes.ability; - } - - if (!(species?.forms[starterAttributes.form!]?.isStarterSelectable && this.speciesStarterDexEntry!.caughtAttr & this.scene.gameData.getFormAttr(starterAttributes.form!))) { // TODO: are those bangs correct? - // requested form wasn't unlocked/isn't a starter form, purging setting - delete starterAttributes.form; - } - - if (this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr).indexOf(starterAttributes.nature as unknown as Nature) < 0) { - // requested nature wasn't unlocked, purging setting - delete starterAttributes.nature; - } - } if (starterAttributes?.nature) { // load default nature from stater save data, if set this.natureCursor = starterAttributes.nature; } if (starterAttributes?.ability && !isNaN(starterAttributes.ability)) { - // load default nature from stater save data, if set + // load default ability from stater save data, if set this.abilityCursor = starterAttributes.ability; } @@ -2675,7 +2725,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonLuckText.setText(luck.toString()); this.pokemonLuckText.setTint(getVariantTint(Math.min(luck - 1, 2) as Variant)); this.pokemonLuckLabelText.setVisible(this.pokemonLuckText.visible); - this.pokemonShinyIcon.setVisible(this.starterPreferences[species.speciesId]?.shiny ?? false); //Growth translate let growthReadable = Utils.toReadableString(GrowthRate[species.growthRate]); @@ -2699,12 +2748,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species)); } this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`); + const defaultDexAttr = this.getCurrentDexProps(species.speciesId); const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); const variant = defaultProps.variant; const tint = getVariantTint(variant); this.pokemonShinyIcon.setFrame(getVariantIcon(variant)); this.pokemonShinyIcon.setTint(tint); + this.pokemonShinyIcon.setVisible(defaultProps.shiny); this.pokemonCaughtHatchedContainer.setVisible(true); if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) { this.pokemonCaughtHatchedContainer.setY(16); @@ -2894,21 +2945,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const dexEntry = this.scene.gameData.dexData[species.speciesId]; const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr; - const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); - const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); - const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); - const isDefaultVariantCaught = !!(isCaught & DexAttr.DEFAULT_VARIANT); - const isVariantCaught = !!(isCaught & DexAttr.SHINY); - const isMaleCaught = !!(isCaught & DexAttr.MALE); - const isFemaleCaught = !!(isCaught & DexAttr.FEMALE); - - const starterAttributes = this.starterPreferences[species.speciesId]; - - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); - const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); - const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); + const caughtAttr = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); if (!dexEntry.caughtAttr) { + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); + const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); + const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); + if (shiny === undefined || shiny !== props.shiny) { shiny = props.shiny; } @@ -2927,83 +2970,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (natureIndex === undefined || natureIndex !== defaultNature) { natureIndex = defaultNature; } - } else { - // compare current shiny, formIndex, female, variant, abilityIndex, natureIndex with the caught ones - // if the current ones are not caught, we need to find the next caught ones - if (shiny) { - if (!(isVariantCaught || isVariant2Caught || isVariant3Caught)) { - shiny = false; - starterAttributes.shiny = false; - variant = 0; - starterAttributes.variant = 0; - } else { - shiny = true; - starterAttributes.shiny = true; - if (variant === 0 && !isDefaultVariantCaught) { - if (isVariant2Caught) { - variant = 1; - starterAttributes.variant = 1; - } else if (isVariant3Caught) { - variant = 2; - starterAttributes.variant = 2; - } else { - variant = 0; - starterAttributes.variant = 0; - } - } else if (variant === 1 && !isVariant2Caught) { - if (isVariantCaught) { - variant = 0; - starterAttributes.variant = 0; - } else if (isVariant3Caught) { - variant = 2; - starterAttributes.variant = 2; - } else { - variant = 0; - starterAttributes.variant = 0; - } - } else if (variant === 2 && !isVariant3Caught) { - if (isVariantCaught) { - variant = 0; - starterAttributes.variant = 0; - } else if (isVariant2Caught) { - variant = 1; - starterAttributes.variant = 1; - } else { - variant = 0; - starterAttributes.variant = 0; - } - } - } - } - if (female) { - if (!isFemaleCaught) { - female = false; - starterAttributes.female = false; - } - } else { - if (!isMaleCaught) { - female = true; - starterAttributes.female = true; - } - } - - if (species.forms) { - const formCount = species.forms.length; - let newFormIndex = formIndex??0; - if (species.forms[newFormIndex]) { - const isValidForm = species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex); - if (!isValidForm) { - do { - newFormIndex = (newFormIndex + 1) % formCount; - if (species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) { - break; - } - } while (newFormIndex !== props.formIndex); - formIndex = newFormIndex; - starterAttributes.form = formIndex; - } - } - } } this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default? @@ -3045,8 +3011,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler { currentFilteredContainer.checkIconId(female, formIndex, shiny, variant); } - this.canCycleShiny = isVariantCaught || isVariant2Caught || isVariant3Caught; + const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY); + const isShinyCaught = !!(caughtAttr & DexAttr.SHINY); + const isVariant1Caught = isShinyCaught && !!(caughtAttr & DexAttr.DEFAULT_VARIANT); + const isVariant2Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_2); + const isVariant3Caught = isShinyCaught && !!(caughtAttr & DexAttr.VARIANT_3); + + this.canCycleShiny = isNonShinyCaught && isShinyCaught; + this.canCycleVariant = !!shiny && [ isVariant1Caught, isVariant2Caught, isVariant3Caught].filter(v => v).length > 1; + + const isMaleCaught = !!(caughtAttr & DexAttr.MALE); + const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE); this.canCycleGender = isMaleCaught && isFemaleCaught; + const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1; let hasAbility2 = abilityAttr & AbilityAttr.ABILITY_2; const hasHiddenAbility = abilityAttr & AbilityAttr.ABILITY_HIDDEN; @@ -3061,10 +3038,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } this.canCycleAbility = [ hasAbility1, hasAbility2, hasHiddenAbility ].filter(a => a).length > 1; + this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey)) .map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1; this.canCycleNature = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1; - this.canCycleVariant = !!shiny && [ dexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT, dexEntry.caughtAttr & DexAttr.VARIANT_2, dexEntry.caughtAttr & DexAttr.VARIANT_3].filter(v => v).length > 1; + } if (dexEntry.caughtAttr && species.malePercent !== null) { @@ -3442,39 +3420,55 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return canStart; } - /* this creates a temporary dex attr props that we use to check whether a pokemon is valid for a challenge. - * when checking for certain challenges (i.e. mono type), we need to check for form changes AND evolutions - * However, since some pokemon can evolve based on their intial gender/form, we need a way to look for that - * This temporary dex attr will therefore ONLY look at gender and form, since there's no cases of shinies/variants - * having different evolutions to their non shiny/variant part, and so those can be ignored - * Since the current form and gender is stored in the starter preferences, this is where we get the values from - */ + /** + * Creates a temporary dex attr props that will be used to check whether a pokemon is valid for a challenge + * and to display the correct shiny, variant, and form based on the StarterPreferences + * + * @param speciesId the id of the species to get props for + * @returns the dex props + */ getCurrentDexProps(speciesId: number): bigint { let props = 0n; + const caughtAttr = this.scene.gameData.dexData[speciesId].caughtAttr; - if (this.starterPreferences[speciesId]?.female) { // this checks the gender of the pokemon + /* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props + * It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props + * If neither of these pass, we add DexAttr.MALE to our temp props + */ + if (this.starterPreferences[speciesId]?.female || ((caughtAttr & DexAttr.FEMALE) > 0n && (caughtAttr & DexAttr.MALE) === 0n)) { props += DexAttr.FEMALE; } else { props += DexAttr.MALE; } - if (this.starterPreferences[speciesId]?.shiny) { + /* This part is very similar to above, but instead of for gender, it checks for shiny within starter preferences. + * If they're not there, it checks the caughtAttr for shiny only (i.e. SHINY === true && NON_SHINY === false) + */ + if (this.starterPreferences[speciesId]?.shiny || ((caughtAttr & DexAttr.SHINY) > 0n && (caughtAttr & DexAttr.NON_SHINY) === 0n)) { props += DexAttr.SHINY; if (this.starterPreferences[speciesId]?.variant) { props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT; } else { - props += DexAttr.DEFAULT_VARIANT; + /* This calculates the correct variant if there's no starter preferences for it. + * This gets the lowest tier variant that you've caught (in line with other mechanics) and adds it to the temp props + */ + if ((caughtAttr & DexAttr.DEFAULT_VARIANT) > 0) { + props += DexAttr.DEFAULT_VARIANT; + } + if ((caughtAttr & DexAttr.VARIANT_2) > 0) { + props += DexAttr.VARIANT_2; + } else if ((caughtAttr & DexAttr.VARIANT_3) > 0) { + props += DexAttr.VARIANT_3; + } } } else { props += DexAttr.NON_SHINY; - if (this.starterPreferences[speciesId]?.variant) { - delete this.starterPreferences[speciesId].variant; - } props += DexAttr.DEFAULT_VARIANT; // we add the default variant here because non shiny versions are listed as default variant } if (this.starterPreferences[speciesId]?.form) { // this checks for the form of the pokemon props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.form)) * DexAttr.DEFAULT_FORM; } else { - props += DexAttr.DEFAULT_FORM; + // Get the first unlocked form + props += this.scene.gameData.getFormAttr(this.scene.gameData.getFormIndex(caughtAttr)); } return props; From 8bf44a20472652ce1a828f4e940fb607d053dfca Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Thu, 29 Aug 2024 23:59:19 +0100 Subject: [PATCH 06/14] Fix error handling and revert mode in AdminUiHandler --- src/ui/admin-ui-handler.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ui/admin-ui-handler.ts b/src/ui/admin-ui-handler.ts index 371604c00a2..049e5b01cdf 100644 --- a/src/ui/admin-ui-handler.ts +++ b/src/ui/admin-ui-handler.ts @@ -64,12 +64,13 @@ export default class AdminUiHandler extends FormModalUiHandler { Utils.apiPost("admin/account/discord-link", `username=${encodeURIComponent(this.inputs[0].text)}&discordId=${encodeURIComponent(this.inputs[1].text)}`, "application/x-www-form-urlencoded", true) .then(response => { if (!response.ok) { - return response.text(); + console.error(response); } - return response.json(); + this.scene.ui.revertMode(); }) - .then(response => { - this.scene.ui.setMode(Mode.ADMIN, config); + .catch((err) => { + console.error(err); + this.scene.ui.revertMode(); }); return false; }; From 3b9b0c4091bf2e291f045255b650e8cccb9c8539 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:05:09 -0400 Subject: [PATCH 07/14] Blitzy's implementation of evil teams in trainer-config.ts (#3884) --- src/data/trainer-config.ts | 4074 ++++++++++++++++++------------------ 1 file changed, 2037 insertions(+), 2037 deletions(-) diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index d48e384d30e..a6cf4247f27 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1,2037 +1,2037 @@ -import BattleScene, {startingWave} from "../battle-scene"; -import {ModifierTypeFunc, modifierTypes} from "../modifier/modifier-type"; -import {EnemyPokemon} from "../field/pokemon"; -import * as Utils from "../utils"; -import {PokeballType} from "./pokeball"; -import {pokemonEvolutions, pokemonPrevolutions} from "./pokemon-evolutions"; -import PokemonSpecies, {getPokemonSpecies, PokemonSpeciesFilter} from "./pokemon-species"; -import {tmSpecies} from "./tms"; -import {Type} from "./type"; -import {doubleBattleDialogue} from "./dialogue"; -import {PersistentModifier} from "../modifier/modifier"; -import {TrainerVariant} from "../field/trainer"; -import {getIsInitialized, initI18n} from "#app/plugins/i18n"; -import i18next from "i18next"; -import {Moves} from "#enums/moves"; -import {PartyMemberStrength} from "#enums/party-member-strength"; -import {Species} from "#enums/species"; -import {TrainerType} from "#enums/trainer-type"; -import {Gender} from "./gender"; - -export enum TrainerPoolTier { - COMMON, - UNCOMMON, - RARE, - SUPER_RARE, - ULTRA_RARE -} - -export interface TrainerTierPools { - [key: integer]: Species[] -} - -export enum TrainerSlot { - NONE, - TRAINER, - TRAINER_PARTNER -} - -export class TrainerPartyTemplate { - public size: integer; - public strength: PartyMemberStrength; - public sameSpecies: boolean; - public balanced: boolean; - - constructor(size: integer, strength: PartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { - this.size = size; - this.strength = strength; - this.sameSpecies = !!sameSpecies; - this.balanced = !!balanced; - } - - getStrength(index: integer): PartyMemberStrength { - return this.strength; - } - - isSameSpecies(index: integer): boolean { - return this.sameSpecies; - } - - isBalanced(index: integer): boolean { - return this.balanced; - } -} - -export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { - public templates: TrainerPartyTemplate[]; - - constructor(...templates: TrainerPartyTemplate[]) { - super(templates.reduce((total: integer, template: TrainerPartyTemplate) => { - total += template.size; - return total; - }, 0), PartyMemberStrength.AVERAGE); - this.templates = templates; - } - - getStrength(index: integer): PartyMemberStrength { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.getStrength(index - t); - } - t += template.size; - } - - return super.getStrength(index); - } - - isSameSpecies(index: integer): boolean { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.isSameSpecies(index - t); - } - t += template.size; - } - - return super.isSameSpecies(index); - } - - isBalanced(index: integer): boolean { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.isBalanced(index - t); - } - t += template.size; - } - - return super.isBalanced(index); - } -} - -export const trainerPartyTemplates = { - ONE_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - ONE_AVG: new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), - ONE_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - ONE_STRONG: new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), - ONE_STRONGER: new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), - TWO_WEAKER: new TrainerPartyTemplate(2, PartyMemberStrength.WEAKER), - TWO_WEAK: new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), - TWO_WEAK_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), - TWO_WEAK_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), - TWO_WEAK_SAME_TWO_WEAK_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true)), - TWO_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - TWO_AVG: new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), - TWO_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - TWO_AVG_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), - TWO_AVG_SAME_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - TWO_AVG_SAME_TWO_AVG_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true)), - TWO_STRONG: new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), - THREE_WEAK: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK), - THREE_WEAK_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, true), - THREE_AVG: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), - THREE_AVG_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, true), - THREE_WEAK_BALANCED: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, false, true), - FOUR_WEAKER: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER), - FOUR_WEAKER_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER, true), - FOUR_WEAK: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK), - FOUR_WEAK_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, true), - FOUR_WEAK_BALANCED: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, false, true), - FIVE_WEAKER: new TrainerPartyTemplate(5, PartyMemberStrength.WEAKER), - FIVE_WEAK: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK), - FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK, false, true), - SIX_WEAKER: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER), - SIX_WEAKER_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true), - SIX_WEAK_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, true), - SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, false, true), - - GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - GYM_LEADER_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - GYM_LEADER_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - GYM_LEADER_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - GYM_LEADER_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - - ELITE_FOUR: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - - CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), new TrainerPartyTemplate(5, PartyMemberStrength.STRONG, false, true)), - - RIVAL: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), - RIVAL_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), - RIVAL_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), - RIVAL_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), - RIVAL_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), - RIVAL_6: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)) -}; - -type PartyTemplateFunc = (scene: BattleScene) => TrainerPartyTemplate; -type PartyMemberFunc = (scene: BattleScene, level: integer, strength: PartyMemberStrength) => EnemyPokemon; -type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; - -export interface PartyMemberFuncs { - [key: integer]: PartyMemberFunc -} - -export class TrainerConfig { - public trainerType: TrainerType; - public trainerTypeDouble: TrainerType; - public name: string; - public nameFemale: string; - public nameDouble: string; - public title: string; - public titleDouble: string; - public hasGenders: boolean = false; - public hasDouble: boolean = false; - public hasCharSprite: boolean = false; - public doubleOnly: boolean = false; - public moneyMultiplier: number = 1; - public isBoss: boolean = false; - public hasStaticParty: boolean = false; - public useSameSeedForAllMembers: boolean = false; - public mixedBattleBgm: string; - public battleBgm: string; - public encounterBgm: string; - public femaleEncounterBgm: string; - public doubleEncounterBgm: string; - public victoryBgm: string; - public genModifiersFunc: GenModifiersFunc; - public modifierRewardFuncs: ModifierTypeFunc[] = []; - public partyTemplates: TrainerPartyTemplate[]; - public partyTemplateFunc: PartyTemplateFunc; - public partyMemberFuncs: PartyMemberFuncs = {}; - public speciesPools: TrainerTierPools; - public speciesFilter: PokemonSpeciesFilter; - public specialtyTypes: Type[] = []; - public hasVoucher: boolean = false; - - public encounterMessages: string[] = []; - public victoryMessages: string[] = []; - public defeatMessages: string[] = []; - - public femaleEncounterMessages: string[]; - public femaleVictoryMessages: string[]; - public femaleDefeatMessages: string[]; - - public doubleEncounterMessages: string[]; - public doubleVictoryMessages: string[]; - public doubleDefeatMessages: string[]; - - constructor(trainerType: TrainerType, allowLegendaries?: boolean) { - 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(); - } - - getKey(): string { - return TrainerType[this.getDerivedType()].toString().toLowerCase(); - } - - getSpriteKey(female?: boolean, isDouble: boolean = false): string { - let ret = this.getKey(); - if (this.hasGenders) { - ret += `_${female ? "f" : "m"}`; - } - // If a special double trainer class was set, set it as the sprite key - if (this.trainerTypeDouble && female && isDouble) { - // Get the derived type for the double trainer since the sprite key is based on the derived type - ret = TrainerType[this.getDerivedType(this.trainerTypeDouble)].toString().toLowerCase(); - } - return ret; - } - - setName(name: string): TrainerConfig { - if (name === "Finn") { - // Give the rival a localized name - // First check if i18n is initialized - if (!getIsInitialized()) { - initI18n(); - } - // This is only the male name, because the female name is handled in a different function (setHasGenders) - if (name === "Finn") { - name = i18next.t("trainerNames:rival"); - } - } - this.name = name; - return this; - } - - /** - * Sets if a boss trainer will have a voucher or not. - * @param hasVoucher - If the boss trainer will have a voucher. - */ - setHasVoucher(hasVoucher: boolean): void { - this.hasVoucher = hasVoucher; - } - - setTitle(title: string): TrainerConfig { - // First check if i18n is initialized - if (!getIsInitialized()) { - initI18n(); - } - - // Make the title lowercase and replace spaces with underscores - title = title.toLowerCase().replace(/\s/g, "_"); - - // Get the title from the i18n file - this.title = i18next.t(`titles:${title}`); - - - return this; - } - - - /** - * Returns the derived trainer type for a given trainer type. - * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) - * @returns {TrainerType} - The derived trainer type. - */ - getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType { - let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType; - switch (trainerType) { - case TrainerType.RIVAL_2: - case TrainerType.RIVAL_3: - case TrainerType.RIVAL_4: - case TrainerType.RIVAL_5: - case TrainerType.RIVAL_6: - trainerType = TrainerType.RIVAL; - break; - case TrainerType.LANCE_CHAMPION: - trainerType = TrainerType.LANCE; - break; - 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.LUSAMINE_2: - trainerType = TrainerType.LUSAMINE; - break; - case TrainerType.GUZMA_2: - trainerType = TrainerType.GUZMA; - break; - case TrainerType.ROSE_2: - trainerType = TrainerType.ROSE; - break; - case TrainerType.MARNIE_ELITE: - trainerType = TrainerType.MARNIE; - break; - case TrainerType.NESSA_ELITE: - trainerType = TrainerType.NESSA; - break; - case TrainerType.BEA_ELITE: - trainerType = TrainerType.BEA; - break; - case TrainerType.ALLISTER_ELITE: - trainerType = TrainerType.ALLISTER; - break; - case TrainerType.RAIHAN_ELITE: - trainerType = TrainerType.RAIHAN; - break; - } - - return trainerType; - } - - /** - * Sets the configuration for trainers with genders, including the female name and encounter background music (BGM). - * @param {string} [nameFemale] - The name of the female trainer. If 'Ivy', a localized name will be assigned. - * @param {TrainerType | string} [femaleEncounterBgm] - The encounter BGM for the female trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ - setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig { - // If the female name is 'Ivy' (the rival), assign a localized name. - if (nameFemale === "Ivy") { - // Check if the internationalization (i18n) system is initialized. - if (!getIsInitialized()) { - // Initialize the i18n system if it is not already initialized. - initI18n(); - } - // Set the localized name for the female rival. - this.nameFemale = i18next.t("trainerNames:rival_female"); - } else { - // Otherwise, assign the provided female name. - this.nameFemale = nameFemale!; // TODO: is this bang correct? - } - - // Indicate that this trainer configuration includes genders. - this.hasGenders = true; - - // If a female encounter BGM is provided. - if (femaleEncounterBgm) { - // If the BGM is a TrainerType (number), convert it to a string, replace underscores with spaces, and convert to lowercase. - // Otherwise, assign the provided string as the BGM. - this.femaleEncounterBgm = typeof femaleEncounterBgm === "number" - ? TrainerType[femaleEncounterBgm].toString().replace(/_/g, " ").toLowerCase() - : femaleEncounterBgm; - } - - // Return the updated TrainerConfig instance. - return this; - } - - /** - * Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM. - * @param nameDouble - The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles). - * @param doubleEncounterBgm - The encounter BGM for the double trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ - setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig { - this.hasDouble = true; - this.nameDouble = nameDouble; - if (doubleEncounterBgm) { - this.doubleEncounterBgm = typeof doubleEncounterBgm === "number" ? TrainerType[doubleEncounterBgm].toString().replace(/\_/g, " ").toLowerCase() : doubleEncounterBgm; - } - return this; - } - - /** - * Sets the trainer type for double battles. - * @param trainerTypeDouble - The TrainerType of the partner in a double battle. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ - setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig { - this.trainerTypeDouble = trainerTypeDouble; - this.setDoubleMessages(this.nameDouble); - return this; - } - - /** - * Sets the encounter and victory messages for double trainers. - * @param nameDouble - The name of the pair (e.g. "red_blue_double"). - */ - setDoubleMessages(nameDouble: string) { - // Check if there is double battle dialogue for this trainer - if (doubleBattleDialogue[nameDouble]) { - // Set encounter and victory messages for double trainers - this.doubleEncounterMessages = doubleBattleDialogue[nameDouble].encounter; - this.doubleVictoryMessages = doubleBattleDialogue[nameDouble].victory; - this.doubleDefeatMessages = doubleBattleDialogue[nameDouble].defeat; - } - } - - /** - * Sets the title for double trainers - * @param titleDouble - the key for the title in the i18n file. (e.g., "champion_double"). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ - setDoubleTitle(titleDouble: string): TrainerConfig { - // First check if i18n is initialized - if (!getIsInitialized()) { - initI18n(); - } - - // Make the title lowercase and replace spaces with underscores - titleDouble = titleDouble.toLowerCase().replace(/\s/g, "_"); - - // Get the title from the i18n file - this.titleDouble = i18next.t(`titles:${titleDouble}`); - - return this; - } - - setHasCharSprite(): TrainerConfig { - this.hasCharSprite = true; - return this; - } - - setDoubleOnly(): TrainerConfig { - this.doubleOnly = true; - return this; - } - - setMoneyMultiplier(moneyMultiplier: number): TrainerConfig { - this.moneyMultiplier = moneyMultiplier; - return this; - } - - setBoss(): TrainerConfig { - this.isBoss = true; - return this; - } - - setStaticParty(): TrainerConfig { - this.hasStaticParty = true; - return this; - } - - setUseSameSeedForAllMembers(): TrainerConfig { - this.useSameSeedForAllMembers = true; - return this; - } - - setMixedBattleBgm(mixedBattleBgm: string): TrainerConfig { - this.mixedBattleBgm = mixedBattleBgm; - return this; - } - - setBattleBgm(battleBgm: string): TrainerConfig { - this.battleBgm = battleBgm; - return this; - } - - setEncounterBgm(encounterBgm: TrainerType | string): TrainerConfig { - this.encounterBgm = typeof encounterBgm === "number" ? TrainerType[encounterBgm].toString().toLowerCase() : encounterBgm; - return this; - } - - setVictoryBgm(victoryBgm: string): TrainerConfig { - this.victoryBgm = victoryBgm; - return this; - } - - setPartyTemplates(...partyTemplates: TrainerPartyTemplate[]): TrainerConfig { - this.partyTemplates = partyTemplates; - return this; - } - - setPartyTemplateFunc(partyTemplateFunc: PartyTemplateFunc): TrainerConfig { - this.partyTemplateFunc = partyTemplateFunc; - return this; - } - - setPartyMemberFunc(slotIndex: integer, partyMemberFunc: PartyMemberFunc): TrainerConfig { - this.partyMemberFuncs[slotIndex] = partyMemberFunc; - return this; - } - - setSpeciesPools(speciesPools: TrainerTierPools | Species[]): TrainerConfig { - this.speciesPools = (Array.isArray(speciesPools) ? {[TrainerPoolTier.COMMON]: speciesPools} : speciesPools) as unknown as TrainerTierPools; - return this; - } - - setSpeciesFilter(speciesFilter: PokemonSpeciesFilter, allowLegendaries?: boolean): TrainerConfig { - const baseFilter = this.speciesFilter; - this.speciesFilter = allowLegendaries ? speciesFilter : species => speciesFilter(species) && baseFilter(species); - return this; - } - - setSpecialtyTypes(...specialtyTypes: Type[]): TrainerConfig { - this.specialtyTypes = specialtyTypes; - return this; - } - - setGenModifiersFunc(genModifiersFunc: GenModifiersFunc): TrainerConfig { - this.genModifiersFunc = genModifiersFunc; - return this; - } - - setModifierRewardFuncs(...modifierTypeFuncs: (() => ModifierTypeFunc)[]): TrainerConfig { - this.modifierRewardFuncs = modifierTypeFuncs.map(func => () => { - const modifierTypeFunc = func(); - const modifierType = modifierTypeFunc(); - modifierType.withIdFromFunc(modifierTypeFunc); - return modifierType; - }); - return this; - } - - /** - * Returns the pool of species for an evil team admin - * @param team - The evil team the admin belongs to. - * @returns {TrainerTierPools} - */ - speciesPoolPerEvilTeamAdmin(team): TrainerTierPools { - team = team.toLowerCase(); - switch (team) { - case "rocket": { - return { - [TrainerPoolTier.COMMON]: [Species.RATTATA, Species.KOFFING, Species.EKANS, Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], - [TrainerPoolTier.UNCOMMON]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], - [TrainerPoolTier.RARE]: [Species.DRATINI, Species.LARVITAR] - }; - } - case "magma": { - return { - [TrainerPoolTier.COMMON]: [Species.NUMEL, Species.POOCHYENA, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR], - [TrainerPoolTier.UNCOMMON]: [Species.TRAPINCH, Species.HEATMOR], - [TrainerPoolTier.RARE]: [Species.CAPSAKID, Species.CHARCADET] - }; - } - case "aqua": { - return { - [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.CORPHISH, Species.ZIGZAGOON, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], - [TrainerPoolTier.UNCOMMON]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], - [TrainerPoolTier.RARE]: [Species.DONDOZO] - }; - } - case "galactic": { - return { - [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.BRONZOR, Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], - [TrainerPoolTier.UNCOMMON]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], - [TrainerPoolTier.RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] - }; - } - case "plasma": { - return { - [TrainerPoolTier.COMMON]: [Species.SCRAFTY, Species.LILLIPUP, Species.PURRLOIN, Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], - [TrainerPoolTier.UNCOMMON]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], - [TrainerPoolTier.RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] - }; - } - case "flare": { - return { - [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], - [TrainerPoolTier.UNCOMMON]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], - [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.DRUDDIGON] - }; - } - case "aether": { - return { - [TrainerPoolTier.COMMON]: [ Species.BRUXISH, Species.SLOWPOKE, Species.BALTOY, Species.EXEGGCUTE, Species.ABRA, Species.ALOLA_RAICHU, Species.ELGYEM, Species.NATU], - [TrainerPoolTier.UNCOMMON]: [Species.GALAR_SLOWKING, Species.MEDITITE, Species.BELDUM, Species.ORANGURU, Species.HATTERENE, Species.INKAY, Species.RALTS], - [TrainerPoolTier.RARE]: [Species.ARMAROUGE, Species.GIRAFARIG, Species.PORYGON] - }; - } - case "skull": { - return { - [TrainerPoolTier.COMMON]: [ Species.MAREANIE, Species.ALOLA_GRIMER, Species.GASTLY, Species.ZUBAT, Species.LURANTIS, Species.VENIPEDE, Species.BUDEW, Species.KOFFING], - [TrainerPoolTier.UNCOMMON]: [Species.GALAR_SLOWBRO, Species.SKORUPI, Species.PALDEA_WOOPER, Species.NIDORAN_F, Species.CROAGUNK, Species.MANDIBUZZ], - [TrainerPoolTier.RARE]: [Species.DRAGALGE, Species.HISUI_SNEASEL] - }; - } - case "macro": { - return { - [TrainerPoolTier.COMMON]: [ Species.HATTERENE, Species.MILOTIC, Species.TSAREENA, Species.SALANDIT, Species.GALAR_PONYTA, Species.GOTHITA, Species.FROSLASS], - [TrainerPoolTier.UNCOMMON]: [Species.MANDIBUZZ, Species.MAREANIE, Species.ALOLA_VULPIX, Species.TOGEPI, Species.GALAR_CORSOLA, Species.SINISTEA, Species.APPLIN], - [TrainerPoolTier.RARE]: [Species.TINKATINK, Species.HISUI_LILLIGANT] - }; - } - } - - console.warn(`Evil team admin for ${team} not found. Returning empty species pools.`); - return []; - } - - /** - * Initializes the trainer configuration for an evil team admin. - * @param title - The title of the evil team admin. - * @param poolName - The evil team the admin belongs to. - * @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - * **/ - initForEvilTeamAdmin(title: string, poolName: string, signatureSpecies: (Species | Species[])[],): TrainerConfig { - if (!getIsInitialized()) { - initI18n(); - } - this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); - - // Set the species pools for the evil team admin. - this.speciesPools = this.speciesPoolPerEvilTeamAdmin(poolName); - - signatureSpecies.forEach((speciesPool, s) => { - if (!Array.isArray(speciesPool)) { - speciesPool = [speciesPool]; - } - this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); - }); - - const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); - this.name = i18next.t(`trainerNames:${nameForCall}`); - this.setHasVoucher(false); - this.setTitle(title); - this.setMoneyMultiplier(1.5); - this.setBoss(); - this.setStaticParty(); - this.setBattleBgm("battle_plasma_boss"); - this.setVictoryBgm("victory_team_plasma"); - - 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. - * @param boolean whether or not this is the rematch fight - * @returns {TrainerConfig} - The updated TrainerConfig instance. - * **/ - initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], rematch: boolean = false, ...specialtyTypes: Type[]): TrainerConfig { - if (!getIsInitialized()) { - initI18n(); - } - if (rematch) { - this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR); - } else { - 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.setHasVoucher(true); - this.setBattleBgm("battle_plasma_boss"); - this.setVictoryBgm("victory_team_plasma"); - - return this; - } - - /** - * Initializes the trainer configuration for a Gym Leader. - * @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader. - * @param {Type[]} specialtyTypes - The specialty types for the Gym Leader. - * @param isMale - Whether the Gym Leader is Male or Not (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - * **/ - initForGymLeader(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { - // Check if the internationalization (i18n) system is initialized. - if (!getIsInitialized()) { - initI18n(); - } - - // Set the function to generate the Gym Leader's party template. - this.setPartyTemplateFunc(getGymLeaderPartyTemplate); - - // Set up party members with their corresponding species. - signatureSpecies.forEach((speciesPool, s) => { - // Ensure speciesPool is an array. - if (!Array.isArray(speciesPool)) { - speciesPool = [speciesPool]; - } - // Set a function to get a random party member from the species pool. - this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); - }); - - // If specialty types are provided, set species filter and specialty types. - if (specialtyTypes.length) { - this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined); - this.setSpecialtyTypes(...specialtyTypes); - } - - // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. - const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); - this.name = i18next.t(`trainerNames:${nameForCall}`); - - // Set the title to "gym_leader". (this is the key in the i18n file) - this.setTitle("gym_leader"); - if (!isMale) { - this.setTitle("gym_leader_female"); - } - - // Configure various properties for the Gym Leader. - this.setMoneyMultiplier(2.5); - this.setBoss(); - this.setStaticParty(); - this.setHasVoucher(true); - this.setBattleBgm("battle_unova_gym"); - this.setVictoryBgm("victory_gym"); - this.setGenModifiersFunc(party => { - const waveIndex = party[0].scene.currentBattle.waveIndex; - return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : undefined); - }); - - return this; - } - - /** - * Initializes the trainer configuration for an Elite Four member. - * @param {Species | Species[]} signatureSpecies - The signature species for the Elite Four member. - * @param {Type[]} specialtyTypes - The specialty types for the Elite Four member. - * @param isMale - Whether the Elite Four Member is Male or Female (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ - initForEliteFour(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { - // Check if the internationalization (i18n) system is initialized. - if (!getIsInitialized()) { - initI18n(); - } - - // Set the party templates for the Elite Four. - this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR); - - // Set up party members with their corresponding species. - signatureSpecies.forEach((speciesPool, s) => { - // Ensure speciesPool is an array. - if (!Array.isArray(speciesPool)) { - speciesPool = [speciesPool]; - } - // Set a function to get a random party member from the species pool. - this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); - }); - - // Set species filter and specialty types if provided, otherwise filter by base total. - if (specialtyTypes.length) { - this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= 450); - this.setSpecialtyTypes(...specialtyTypes); - } else { - this.setSpeciesFilter(p => p.baseTotal >= 450); - } - - // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. - const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); - this.name = i18next.t(`trainerNames:${nameForCall}`); - - // Set the title to "elite_four". (this is the key in the i18n file) - this.setTitle("elite_four"); - if (!isMale) { - this.setTitle("elite_four_female"); - } - - // Configure various properties for the Elite Four member. - this.setMoneyMultiplier(3.25); - this.setBoss(); - this.setStaticParty(); - this.setHasVoucher(true); - this.setBattleBgm("battle_unova_elite"); - this.setVictoryBgm("victory_gym"); - this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : undefined)); - - return this; - } - - /** - * Initializes the trainer configuration for a Champion. - * @param {Species | Species[]} signatureSpecies - The signature species for the Champion. - * @param isMale - Whether the Champion is Male or Female (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ - initForChampion(signatureSpecies: (Species | Species[])[], isMale: boolean): TrainerConfig { - // Check if the internationalization (i18n) system is initialized. - if (!getIsInitialized()) { - initI18n(); - } - - // Set the party templates for the Champion. - this.setPartyTemplates(trainerPartyTemplates.CHAMPION); - - // Set up party members with their corresponding species. - signatureSpecies.forEach((speciesPool, s) => { - // Ensure speciesPool is an array. - if (!Array.isArray(speciesPool)) { - speciesPool = [speciesPool]; - } - // Set a function to get a random party member from the species pool. - this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); - }); - - // Set species filter to only include species with a base total of 470 or higher. - this.setSpeciesFilter(p => p.baseTotal >= 470); - - // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. - const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); - this.name = i18next.t(`trainerNames:${nameForCall}`); - - // Set the title to "champion". (this is the key in the i18n file) - this.setTitle("champion"); - if (!isMale) { - this.setTitle("champion_female"); - } - - - // Configure various properties for the Champion. - this.setMoneyMultiplier(10); - this.setBoss(); - this.setStaticParty(); - this.setHasVoucher(true); - this.setBattleBgm("battle_champion_alder"); - this.setVictoryBgm("victory_champion"); - this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 3)); - - return this; - } - - /** - * Retrieves the title for the trainer based on the provided trainer slot and variant. - * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. - * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. - * @returns {string} - The title of the trainer. - **/ - getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string { - const ret = this.name; - - // Check if the variant is double and the name for double exists - if (!trainerSlot && variant === TrainerVariant.DOUBLE && this.nameDouble) { - return this.nameDouble; - } - - // Female variant - if (this.hasGenders) { - // If the name is already set - if (this.nameFemale) { - // Check if the variant is either female or this is for the partner in a double battle - if (variant === TrainerVariant.FEMALE || (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)) { - return this.nameFemale; - } - } else - // Check if !variant is true, if so return the name, else return the name with _female appended - if (variant) { - if (!getIsInitialized()) { - initI18n(); - } - // Check if the female version exists in the i18n file - if (i18next.exists(`trainerClasses:${this.name.toLowerCase()}`)) { - // If it does, return - return ret + "_female"; - } else { - // If it doesn't, we do not do anything and go to the normal return - // This is to prevent the game from displaying an error if a female version of the trainer does not exist in the localization - } - } - } - - return ret; - } - - loadAssets(scene: BattleScene, variant: TrainerVariant): Promise { - return new Promise(resolve => { - const isDouble = variant === TrainerVariant.DOUBLE; - const trainerKey = this.getSpriteKey(variant === TrainerVariant.FEMALE, false); - const partnerTrainerKey = this.getSpriteKey(true, true); - scene.loadAtlas(trainerKey, "trainer"); - if (isDouble) { - scene.loadAtlas(partnerTrainerKey, "trainer"); - } - scene.load.once(Phaser.Loader.Events.COMPLETE, () => { - const originalWarn = console.warn; - // Ignore warnings for missing frames, because there will be a lot - console.warn = () => { - }; - const frameNames = scene.anims.generateFrameNames(trainerKey, { - zeroPad: 4, - suffix: ".png", - start: 1, - end: 128 - }); - const partnerFrameNames = isDouble - ? scene.anims.generateFrameNames(partnerTrainerKey, { - zeroPad: 4, - suffix: ".png", - start: 1, - end: 128 - }) - : ""; - console.warn = originalWarn; - if (!(scene.anims.exists(trainerKey))) { - scene.anims.create({ - key: trainerKey, - frames: frameNames, - frameRate: 24, - repeat: -1 - }); - } - if (isDouble && !(scene.anims.exists(partnerTrainerKey))) { - scene.anims.create({ - key: partnerTrainerKey, - frames: partnerFrameNames, - frameRate: 24, - repeat: -1 - }); - } - resolve(); - }); - if (!scene.load.isLoading()) { - scene.load.start(); - } - }); - } -} - -let t = 0; - -interface TrainerConfigs { - [key: integer]: TrainerConfig -} - -/** - * The function to get variable strength grunts - * @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 < 63) { - return trainerPartyTemplates.THREE_AVG; - } else if (waveIndex < 65) { - return trainerPartyTemplates.TWO_AVG_ONE_STRONG; - } else if (waveIndex < 112) { - return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger - } else { - 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)]; -} - -function getGymLeaderPartyTemplate(scene: BattleScene) { - return getWavePartyTemplate(scene, trainerPartyTemplates.GYM_LEADER_1, trainerPartyTemplates.GYM_LEADER_2, trainerPartyTemplates.GYM_LEADER_3, trainerPartyTemplates.GYM_LEADER_4, trainerPartyTemplates.GYM_LEADER_5); -} - -function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void): PartyMemberFunc { - return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => { - let species = Utils.randSeedItem(speciesPool); - if (!ignoreEvolution) { - species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex); - } - return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess); - }; -} - -function getSpeciesFilterRandomPartyMemberFunc(speciesFilter: PokemonSpeciesFilter, trainerSlot: TrainerSlot = TrainerSlot.TRAINER, allowLegendaries?: boolean, postProcess?: (EnemyPokemon: EnemyPokemon) => void): PartyMemberFunc { - const originalSpeciesFilter = speciesFilter; - speciesFilter = (species: PokemonSpecies) => (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) && !species.isTrainerForbidden() && originalSpeciesFilter(species); - return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => { - const ret = scene.addEnemyPokemon(getPokemonSpecies(scene.randomSpecies(scene.currentBattle.waveIndex, level, false, speciesFilter).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex)), level, trainerSlot, undefined, undefined, postProcess); - return ret; - }; -} - -function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: Type[]): PersistentModifier[] { - const ret: PersistentModifier[] = []; - const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i); - for (let t = 0; t < Math.min(count, party.length); t++) { - const randomIndex = Utils.randSeedItem(partyMemberIndexes); - partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); - ret.push(modifierTypes.TERA_SHARD().generateType([], [Utils.randSeedItem(types ? types : party[randomIndex].getTypes())])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct? - } - return ret; -} - -type SignatureSpecies = { - [key in string]: (Species | Species[])[]; -}; - -/* - * The signature species for each Gym Leader, Elite Four member, and Champion. - * The key is the trainer type, and the value is an array of Species or Species arrays. - * This is in a separate const so it can be accessed from other places and not just the trainerConfigs - */ -export const signatureSpecies: SignatureSpecies = { - BROCK: [Species.GEODUDE, Species.ONIX], - MISTY: [Species.STARYU, Species.PSYDUCK], - LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ], - ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP], - JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT], - SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON], - BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR], - GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F], - FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO], - BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR], - WHITNEY: [Species.GIRAFARIG, Species.MILTANK], - MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE], - CHUCK: [Species.POLIWRATH, Species.MANKEY], - JASMINE: [Species.MAGNEMITE, Species.STEELIX], - PRYCE: [Species.SEEL, Species.SWINUB], - CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS], - ROXANNE: [Species.GEODUDE, Species.NOSEPASS], - BRAWLY: [Species.MACHOP, Species.MAKUHITA], - WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE], - FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL], - NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.CHANSEY, Species.KANGASKHAN], - WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY], - TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE], - LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR], - JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH], - ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE], - GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG], - MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR], - CRASHER_WAKE: [Species.BUIZEL, Species.MAGIKARP, Species.PIPLUP], - FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB], - BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON], - CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT], - VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM], - CILAN: [Species.PANSAGE, Species.COTTONEE, Species.PETILIL], - CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.HEATMOR], - CRESS: [Species.PANPOUR, Species.BASCULIN, Species.TYMPOLE], - CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PATRAT], - LENORA: [Species.KANGASKHAN, Species.DEERLING, Species.AUDINO], - ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI], - BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST], - ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK], - CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT], - SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET], - BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO], - DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO], - MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA], - VIOLA: [Species.SURSKIT, Species.SCATTERBUG], - GRANT: [Species.AMAURA, Species.TYRUNT], - KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO], - RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT], - CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA], - VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME], - OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING], - WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL], - MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET], - NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD], - KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL], - BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS], - ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY], - OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING], - BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR], - GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE], - MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME], - PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY], - MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO], - RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY], - KATY: [Species.NYMBLE, Species.TAROUNTULA, Species.HERACROSS], - BRASSIUS: [Species.SMOLIV, Species.SHROOMISH, Species.ODDISH], - IONO: [Species.TADBULB, Species.WATTREL, Species.VOLTORB], - KOFU: [Species.VELUZA, Species.WIGLETT, Species.WINGULL], - LARRY: [Species.STARLY, Species.DUNSPARCE, Species.KOMALA], - RYME: [Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], - TULIP: [Species.GIRAFARIG, Species.FLITTLE, Species.RALTS], - GRUSHA: [Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO], - 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.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.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.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION], - BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR], - 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], - MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME], - 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, Species.ANNIHILAPE]], - MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO], - 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.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.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 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, 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 -}; - -export const trainerConfigs: TrainerConfigs = { - [TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(), - [TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders("Ace Trainer Female").setHasDouble("Ace Duo").setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER) - .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.THREE_WEAK_BALANCED, trainerPartyTemplates.FOUR_WEAK_BALANCED, trainerPartyTemplates.FIVE_WEAK_BALANCED, trainerPartyTemplates.SIX_WEAK_BALANCED)), - [TrainerType.ARTIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.THREE_AVG) - .setSpeciesPools([Species.SMEARGLE]), - [TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders("Backers").setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders("Backpacker Female").setHasDouble("Backpackers").setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER) - .setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.ONE_WEAK_ONE_STRONG, trainerPartyTemplates.ONE_AVG_ONE_STRONG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.RHYHORN, Species.AIPOM, Species.MAKUHITA, Species.MAWILE, Species.NUMEL, Species.LILLIPUP, Species.SANDILE, Species.WOOLOO], - [TrainerPoolTier.UNCOMMON]: [Species.GIRAFARIG, Species.ZANGOOSE, Species.SEVIPER, Species.CUBCHOO, Species.PANCHAM, Species.SKIDDO, Species.MUDBRAY], - [TrainerPoolTier.RARE]: [Species.TAUROS, Species.STANTLER, Species.DARUMAKA, Species.BOUFFALANT, Species.DEERLING, Species.IMPIDIMP], - [TrainerPoolTier.SUPER_RARE]: [Species.GALAR_DARUMAKA, Species.TEDDIURSA] - }), - [TrainerType.BAKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.35).setSpeciesFilter(s => s.isOfType(Type.GRASS) || s.isOfType(Type.FIRE)), - [TrainerType.BEAUTY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY), - [TrainerType.BIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON)), - [TrainerType.BLACK_BELT]: new TrainerConfig(++t).setHasGenders("Battle Girl", TrainerType.PSYCHIC).setHasDouble("Crush Kin").setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.FIGHTING) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_STRONG, trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_AVG_ONE_STRONG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.NIDORAN_F, Species.NIDORAN_M, Species.MACHOP, Species.MAKUHITA, Species.MEDITITE, Species.CROAGUNK, Species.TIMBURR], - [TrainerPoolTier.UNCOMMON]: [Species.MANKEY, Species.POLIWRATH, Species.TYROGUE, Species.BRELOOM, Species.SCRAGGY, Species.MIENFOO, Species.PANCHAM, Species.STUFFUL, Species.CRABRAWLER], - [TrainerPoolTier.RARE]: [Species.HERACROSS, Species.RIOLU, Species.THROH, Species.SAWK, Species.PASSIMIAN, Species.CLOBBOPUS], - [TrainerPoolTier.SUPER_RARE]: [Species.HITMONTOP, Species.INFERNAPE, Species.GALLADE, Species.HAWLUCHA, Species.HAKAMO_O], - [TrainerPoolTier.ULTRA_RARE]: [Species.KUBFU] - }), - [TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders("Breeder Female").setHasDouble("Breeders") - .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.FIVE_WEAKER, trainerPartyTemplates.SIX_WEAKER)) - .setSpeciesFilter(s => s.baseTotal < 450), - [TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders("Clerk Female").setHasDouble("Colleagues").setEncounterBgm(TrainerType.CLERK) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.MEOWTH, Species.PSYDUCK, Species.BUDEW, Species.PIDOVE, Species.CINCCINO, Species.LITLEO], - [TrainerPoolTier.UNCOMMON]: [Species.JIGGLYPUFF, Species.MAGNEMITE, Species.MARILL, Species.COTTONEE, Species.SKIDDO], - [TrainerPoolTier.RARE]: [Species.BUIZEL, Species.SNEASEL, Species.KLEFKI, Species.INDEEDEE] - }), - [TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders("Cyclist Female").setHasDouble("Cyclists").setEncounterBgm(TrainerType.CYCLIST) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.PICHU, Species.STARLY, Species.TAILLOW, Species.BOLTUND], - [TrainerPoolTier.UNCOMMON]: [Species.DODUO, Species.ELECTRIKE, Species.BLITZLE, Species.WATTREL], - [TrainerPoolTier.RARE]: [Species.YANMA, Species.NINJASK, Species.WHIRLIPEDE, Species.EMOLGA], - [TrainerPoolTier.SUPER_RARE]: [Species.ACCELGOR, Species.DREEPY] - }), - [TrainerType.DANCER]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.CYCLIST) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.RALTS, Species.SPOINK, Species.LOTAD, Species.BUDEW], - [TrainerPoolTier.UNCOMMON]: [Species.SPINDA, Species.SWABLU, Species.MARACTUS,], - [TrainerPoolTier.RARE]: [Species.BELLOSSOM, Species.HITMONTOP, Species.MIME_JR, Species.ORICORIO], - [TrainerPoolTier.SUPER_RARE]: [Species.POPPLIO] - }), - [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK), - [TrainerType.DOCTOR]: new TrainerConfig(++t).setHasGenders("Nurse", "lass").setHasDouble("Medical Team").setMoneyMultiplier(3).setEncounterBgm(TrainerType.CLERK) - .setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.HEAL_PULSE)), - [TrainerType.FIREBREATHER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK) - .setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SMOG) || s.isOfType(Type.FIRE)), - [TrainerType.FISHERMAN]: new TrainerConfig(++t).setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.BACKPACKER).setSpecialtyTypes(Type.WATER) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.THREE_WEAK_SAME, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.SIX_WEAKER) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.TENTACOOL, Species.MAGIKARP, Species.GOLDEEN, Species.STARYU, Species.REMORAID, Species.SKRELP, Species.CLAUNCHER, Species.ARROKUDA], - [TrainerPoolTier.UNCOMMON]: [Species.POLIWAG, Species.SHELLDER, Species.KRABBY, Species.HORSEA, Species.CARVANHA, Species.BARBOACH, Species.CORPHISH, Species.FINNEON, Species.TYMPOLE, Species.BASCULIN, Species.FRILLISH, Species.INKAY], - [TrainerPoolTier.RARE]: [Species.CHINCHOU, Species.CORSOLA, Species.WAILMER, Species.BARBOACH, Species.CLAMPERL, Species.LUVDISC, Species.MANTYKE, Species.ALOMOMOLA, Species.TATSUGIRI, Species.VELUZA], - [TrainerPoolTier.SUPER_RARE]: [Species.LAPRAS, Species.FEEBAS, Species.RELICANTH, Species.DONDOZO] - }), - [TrainerType.GUITARIST]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.ELECTRIC).setSpeciesFilter(s => s.isOfType(Type.ELECTRIC)), - [TrainerType.HARLEQUIN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PSYCHIC).setSpeciesFilter(s => tmSpecies[Moves.TRICK_ROOM].indexOf(s.speciesId) > -1), - [TrainerType.HIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER) - .setPartyTemplates(trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.ONE_STRONG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.SANDSHREW, Species.DIGLETT, Species.GEODUDE, Species.MACHOP, Species.ARON, Species.ROGGENROLA, Species.DRILBUR, Species.NACLI], - [TrainerPoolTier.UNCOMMON]: [Species.ZUBAT, Species.RHYHORN, Species.ONIX, Species.CUBONE, Species.WOOBAT, Species.SWINUB, Species.NOSEPASS, Species.HIPPOPOTAS, Species.DWEBBLE, Species.KLAWF, Species.TOEDSCOOL], - [TrainerPoolTier.RARE]: [Species.TORKOAL, Species.TRAPINCH, Species.BARBOACH, Species.GOLETT, Species.ALOLA_DIGLETT, Species.ALOLA_GEODUDE, Species.GALAR_STUNFISK, Species.PALDEA_WOOPER], - [TrainerPoolTier.SUPER_RARE]: [Species.MAGBY, Species.LARVITAR] - }), - [TrainerType.HOOLIGANS]: new TrainerConfig(++t).setDoubleOnly().setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON) || s.isOfType(Type.DARK)), - [TrainerType.HOOPSTER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.INFIELDER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.JANITOR]: new TrainerConfig(++t).setMoneyMultiplier(1.1).setEncounterBgm(TrainerType.CLERK), - [TrainerType.LINEBACKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.MAID]: new TrainerConfig(++t).setMoneyMultiplier(1.6).setEncounterBgm(TrainerType.RICH), - [TrainerType.MUSICIAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SING)), - [TrainerType.HEX_MANIAC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PSYCHIC) - .setPartyTemplates(trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_AVG_ONE_STRONG, trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_STRONG) - .setSpeciesFilter(s => s.isOfType(Type.GHOST)), - [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm("lass"), - [TrainerType.OFFICER]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.CLERK) - .setPartyTemplates(trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.VULPIX, Species.GROWLITHE, Species.SNUBBULL, Species.POOCHYENA, Species.ELECTRIKE, Species.LILLIPUP, Species.YAMPER, Species.FIDOUGH], - [TrainerPoolTier.UNCOMMON]: [Species.HOUNDOUR, Species.ROCKRUFF, Species.MASCHIFF], - [TrainerPoolTier.RARE]: [Species.JOLTEON, Species.RIOLU], - [TrainerPoolTier.SUPER_RARE]: [], - [TrainerPoolTier.ULTRA_RARE]: [Species.ENTEI, Species.SUICUNE, Species.RAIKOU] - }), - [TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)), - [TrainerType.PILOT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1), - [TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName("PokéFan").setHasGenders("PokéFan Female").setHasDouble("PokéFan Family").setEncounterBgm(TrainerType.POKEFAN) - .setPartyTemplates(trainerPartyTemplates.SIX_WEAKER, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.FOUR_WEAK_SAME, trainerPartyTemplates.FIVE_WEAK, trainerPartyTemplates.SIX_WEAKER_SAME), - [TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Preschooler Female", "lass").setHasDouble("Preschoolers") - .setPartyTemplates(trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.FIVE_WEAKER) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.CATERPIE, Species.PICHU, Species.SANDSHREW, Species.LEDYBA, Species.BUDEW, Species.BURMY, Species.WOOLOO, Species.PAWMI, Species.SMOLIV], - [TrainerPoolTier.UNCOMMON]: [Species.EEVEE, Species.CLEFFA, Species.IGGLYBUFF, Species.SWINUB, Species.WOOPER, Species.DRIFLOON, Species.DEDENNE, Species.STUFFUL], - [TrainerPoolTier.RARE]: [Species.RALTS, Species.RIOLU, Species.JOLTIK, Species.TANDEMAUS], - [TrainerPoolTier.SUPER_RARE]: [Species.DARUMAKA, Species.TINKATINK], - }), - [TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders("Psychic Female").setHasDouble("Psychics").setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC) - .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME, trainerPartyTemplates.ONE_STRONGER) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.ABRA, Species.DROWZEE, Species.RALTS, Species.SPOINK, Species.GOTHITA, Species.SOLOSIS, Species.BLIPBUG, Species.ESPURR, Species.HATENNA], - [TrainerPoolTier.UNCOMMON]: [Species.MIME_JR, Species.EXEGGCUTE, Species.MEDITITE, Species.NATU, Species.EXEGGCUTE, Species.WOOBAT, Species.INKAY, Species.ORANGURU], - [TrainerPoolTier.RARE]: [Species.ELGYEM, Species.SIGILYPH, Species.BALTOY, Species.GIRAFARIG, Species.MEOWSTIC], - [TrainerPoolTier.SUPER_RARE]: [Species.BELDUM, Species.ESPEON, Species.STANTLER], - }), - [TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName("Pokémon Ranger").setEncounterBgm(TrainerType.BACKPACKER).setHasGenders("Pokémon Ranger Female").setHasDouble("Pokémon Rangers") - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.PICHU, Species.GROWLITHE, Species.PONYTA, Species.ZIGZAGOON, Species.SEEDOT, Species.BIDOOF, Species.RIOLU, Species.SEWADDLE, Species.SKIDDO, Species.SALANDIT, Species.YAMPER], - [TrainerPoolTier.UNCOMMON]: [Species.AZURILL, Species.TAUROS, Species.MAREEP, Species.FARFETCHD, Species.TEDDIURSA, Species.SHROOMISH, Species.ELECTRIKE, Species.BUDEW, Species.BUIZEL, Species.MUDBRAY, Species.STUFFUL], - [TrainerPoolTier.RARE]: [Species.EEVEE, Species.SCYTHER, Species.KANGASKHAN, Species.RALTS, Species.MUNCHLAX, Species.ZORUA, Species.PALDEA_TAUROS, Species.TINKATINK, Species.CYCLIZAR, Species.FLAMIGO], - [TrainerPoolTier.SUPER_RARE]: [Species.LARVESTA], - }), - [TrainerType.RICH]: new TrainerConfig(++t).setMoneyMultiplier(5).setName("Gentleman").setHasGenders("Madame").setHasDouble("Rich Couple"), - [TrainerType.RICH_KID]: new TrainerConfig(++t).setMoneyMultiplier(3.75).setName("Rich Boy").setHasGenders("Lady").setHasDouble("Rich Kids").setEncounterBgm(TrainerType.RICH), - [TrainerType.ROUGHNECK]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.DARK)), - [TrainerType.SAILOR]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.BACKPACKER).setSpeciesFilter(s => s.isOfType(Type.WATER) || s.isOfType(Type.FIGHTING)), - [TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders("Scientist Female").setHasDouble("Scientists").setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.MAGNEMITE, Species.GRIMER, Species.DROWZEE, Species.VOLTORB, Species.KOFFING], - [TrainerPoolTier.UNCOMMON]: [Species.BALTOY, Species.BRONZOR, Species.FERROSEED, Species.KLINK, Species.CHARJABUG, Species.BLIPBUG, Species.HELIOPTILE], - [TrainerPoolTier.RARE]: [Species.ABRA, Species.DITTO, Species.PORYGON, Species.ELEKID, Species.SOLOSIS, Species.GALAR_WEEZING], - [TrainerPoolTier.SUPER_RARE]: [Species.OMANYTE, Species.KABUTO, Species.AERODACTYL, Species.LILEEP, Species.ANORITH, Species.CRANIDOS, Species.SHIELDON, Species.TIRTOUGA, Species.ARCHEN, Species.ARCTOVISH, Species.ARCTOZOLT, Species.DRACOVISH, Species.DRACOZOLT], - [TrainerPoolTier.ULTRA_RARE]: [Species.ROTOM, Species.MELTAN] - }), - [TrainerType.SMASHER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName("Worker").setHasGenders("Worker Female").setHasDouble("Workers").setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)), - [TrainerType.STRIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), - [TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("School Kid Female", "lass").setHasDouble("School Kids") - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.ODDISH, Species.EXEGGCUTE, Species.TEDDIURSA, Species.WURMPLE, Species.RALTS, Species.SHROOMISH, Species.FLETCHLING], - [TrainerPoolTier.UNCOMMON]: [Species.VOLTORB, Species.WHISMUR, Species.MEDITITE, Species.MIME_JR, Species.NYMBLE], - [TrainerPoolTier.RARE]: [Species.TANGELA, Species.EEVEE, Species.YANMA], - [TrainerPoolTier.SUPER_RARE]: [Species.TADBULB] - }), - [TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble("Swimmers").setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)), - [TrainerType.TWINS]: new TrainerConfig(++t).setDoubleOnly().setMoneyMultiplier(0.65).setUseSameSeedForAllMembers() - .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_STRONG)) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PLUSLE, Species.VOLBEAT, Species.PACHIRISU, Species.SILCOON, Species.METAPOD, Species.IGGLYBUFF, Species.PETILIL, Species.EEVEE])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.MINUN, Species.ILLUMISE, Species.EMOLGA, Species.CASCOON, Species.KAKUNA, Species.CLEFFA, Species.COTTONEE, Species.EEVEE], TrainerSlot.TRAINER_PARTNER)) - .setEncounterBgm(TrainerType.TWINS), - [TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders("Veteran Female").setHasDouble("Veteran Duo").setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)), - [TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders("Waitress").setHasDouble("Restaurant Staff").setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.CLERK) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.CLEFFA, Species.CHATOT, Species.PANSAGE, Species.PANSEAR, Species.PANPOUR, Species.MINCCINO], - [TrainerPoolTier.UNCOMMON]: [Species.TROPIUS, Species.PETILIL, Species.BOUNSWEET, Species.INDEEDEE], - [TrainerPoolTier.RARE]: [Species.APPLIN, Species.SINISTEA, Species.POLTCHAGEIST] - }), - [TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders("Worker Female").setHasDouble("Workers").setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)), - [TrainerType.YOUNGSTER]: new TrainerConfig(++t).setMoneyMultiplier(0.5).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Lass", "lass").setHasDouble("Beginners").setPartyTemplates(trainerPartyTemplates.TWO_WEAKER) - .setSpeciesPools( - [Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP] - ), - [TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING, Species.GRIMER, Species.ODDISH], - [TrainerPoolTier.UNCOMMON]: [Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], - [TrainerPoolTier.RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], - [TrainerPoolTier.SUPER_RARE]: [Species.DRATINI, Species.LARVITAR] - }), - [TrainerType.ARCHER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.HOUNDOOM]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.ARIANA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin_female", "rocket", [Species.ARBOK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.PROTON]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.CROBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.PETREL]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.WEEZING]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.BALTOY, Species.BARBOACH], - [TrainerPoolTier.UNCOMMON]: [Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR], - [TrainerPoolTier.RARE]: [Species.TRAPINCH, Species.HEATMOR], - [TrainerPoolTier.SUPER_RARE]: [Species.CAPSAKID, Species.CHARCADET] - }), - [TrainerType.TABITHA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.COURTNEY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin_female", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH, Species.SPHEAL], - [TrainerPoolTier.UNCOMMON]: [Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], - [TrainerPoolTier.RARE]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], - [TrainerPoolTier.SUPER_RARE]: [Species.DONDOZO] - }), - [TrainerType.MATT]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.SHELLY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin_female", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE, Species.BRONZOR, Species.DRIFLOON, Species.BURMY], - [TrainerPoolTier.UNCOMMON]: [Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], - [TrainerPoolTier.RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], - [TrainerPoolTier.SUPER_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] - }), - [TrainerType.JUPITER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.SKUNTANK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.MARS]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.PURUGLY]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.SATURN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander", "galactic", [Species.TOXICROAK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE, Species.SANDILE, Species.TRUBBISH], - [TrainerPoolTier.UNCOMMON]: [Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], - [TrainerPoolTier.RARE]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], - [TrainerPoolTier.SUPER_RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] - }), - [TrainerType.ZINZOLIN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.CRYOGONAL]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.ROOD]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.SWOOBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK], - [TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], - [TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], - [TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN, Species.DRUDDIGON] - }), - [TrainerType.BRYONY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin_female", "flare", [Species.LIEPARD]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.XEROSIC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin", "flare", [Species.MALAMAR]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.AETHER_GRUNT]: new TrainerConfig(++t).setHasGenders("Aether Grunt Female").setHasDouble("Aether Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aether_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.PIKIPEK, Species.ROCKRUFF, Species.ALOLA_DIGLETT, Species.YUNGOOS, Species.CORSOLA, Species.ALOLA_GEODUDE, Species.BOUNSWEET, Species.LILLIPUP, Species.ALOLA_MAROWAK], - [TrainerPoolTier.UNCOMMON]: [ Species.POLIWAG, Species.STUFFUL, Species.ALOLA_EXEGGUTOR, Species.CRABRAWLER, Species.CUTIEFLY, Species.ALOLA_RAICHU, Species.ORICORIO, Species.MUDBRAY], - [TrainerPoolTier.RARE]: [ Species.ORANGURU, Species.PASSIMIAN, Species.GALAR_CORSOLA, Species.ALOLA_SANDSHREW, Species.ALOLA_VULPIX, Species.TURTONATOR, Species.DRAMPA], - [TrainerPoolTier.SUPER_RARE]: [Species.JANGMO_O, Species.PORYGON] - }), - [TrainerType.FABA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aether_admin", "aether", [Species.HYPNO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aether_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.SKULL_GRUNT]: new TrainerConfig(++t).setHasGenders("Skull Grunt Female").setHasDouble("Skull Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_skull_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.SALANDIT, Species.ALOLA_RATTATA, Species.ALOLA_MEOWTH, Species.SCRAGGY, Species.KOFFING, Species.ALOLA_GRIMER, Species.MAREANIE, Species.SPINARAK, Species.TRUBBISH], - [TrainerPoolTier.UNCOMMON]: [ Species.FOMANTIS, Species.SABLEYE, Species.SANDILE, Species.ALOLA_MAROWAK, Species.PANCHAM, Species.DROWZEE, Species.ZUBAT, Species.VENIPEDE, Species.VULLABY], - [TrainerPoolTier.RARE]: [Species.SANDYGAST, Species.PAWNIARD, Species.MIMIKYU, Species.DHELMISE, Species.GASTLY, Species.WISHIWASHI], - [TrainerPoolTier.SUPER_RARE]: [Species.GRUBBIN, Species.DEWPIDER] - }), - [TrainerType.PLUMERIA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("skull_admin", "skull", [Species.SALAZZLE]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_skull_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - [TrainerType.MACRO_GRUNT]: new TrainerConfig(++t).setHasGenders("Macro Grunt Female").setHasDouble("Macro Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_macro_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.CUFANT, Species.GALAR_MEOWTH, Species.KLINK, Species.ROOKIDEE, Species.CRAMORANT, Species.GALAR_ZIGZAGOON, Species.SKWOVET, Species.STEELIX, Species.MAWILE, Species.FERROSEED], - [TrainerPoolTier.UNCOMMON]: [ Species.DRILBUR, Species.MAGNEMITE, Species.HATENNA, Species.ARROKUDA, Species.APPLIN, Species.GALAR_PONYTA, Species.GALAR_YAMASK, Species.SINISTEA, Species.RIOLU], - [TrainerPoolTier.RARE]: [Species.FALINKS, Species.BELDUM, Species.GALAR_FARFETCHD, Species.GALAR_MR_MIME, Species.HONEDGE, Species.SCIZOR, Species.GALAR_DARUMAKA], - [TrainerPoolTier.SUPER_RARE]: [Species.DURALUDON, Species.DREEPY] - }), - [TrainerType.OLEANA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("macro_admin", "macro", [Species.GARBODOR]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_oleana").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), - - [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).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").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(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [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(); - p.generateName(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [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(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LATIAS, Species.LATIOS], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").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(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.SWAMPERT], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - })), - [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(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.GARCHOMP], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [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").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(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"], false).setMixedBattleBgm("battle_kalos_champion") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GOURGEIST], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.GARDEVOIR], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [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).setMixedBattleBgm("battle_galar_champion") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.CHARIZARD], TrainerSlot.TRAINER, true, p => { - p.formIndex = 3; - p.generateAndPopulateMoveset(); - p.generateName(); - })), - [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).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).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").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").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").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").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)) - .setSpeciesFilter(species => species.baseTotal >= 540) - .setGenModifiersFunc(party => { - const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? - }), - [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)) - .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) - .setSpeciesFilter(species => species.baseTotal >= 540) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.RAYQUAZA], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 3); - p.pokeball = PokeballType.MASTER_BALL; - p.shiny = true; - p.variant = 1; - })) - .setGenModifiersFunc(party => { - const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; //TODO: is the bang correct? - }), - [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); - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL], TrainerSlot.TRAINER, true, - p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) - .setSpeciesFilter(species => species.baseTotal >= 540) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.RAYQUAZA], TrainerSlot.TRAINER, true, p => { - p.setBoss(); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - p.shiny = true; - p.variant = 1; - p.formIndex = 1; - p.generateName(); - })) - .setGenModifiersFunc(party => { - const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? - }), - - [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") - .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; - p.generateName(); - })), - [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", [], true).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") - .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.HIPPOWDON])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.EXCADRILL])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.KANGASKHAN], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })) - .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", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .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; - p.generateName(); - })), - [TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SOLROCK, Species.TYPHLOSION], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.TORKOAL, Species.NINETALES], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 2; // DROUGHT - })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SHIFTRY, Species.SCOVILLAIN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 0; // Chlorophyll - })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GREAT_TUSK])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CAMERUPT], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GROUDON], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .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; - p.generateName(); - })), - [TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.EMPOLEON, Species.LUDICOLO], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.POLITOED, Species.PELIPPER], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 2; // Drizzle - })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.BEARTIC, Species.ARMALDO], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 2; // Swift Swim - })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.OVERQWIL ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 1; // Swift Swim - })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SHARPEDO], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYOGRE], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", []).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ])) - .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; - p.generateName(); - })) - .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", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") - .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.HOUNDOOM], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.WEAVILE], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DARKRAI], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", []).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") - .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", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - p.formIndex = Utils.randSeedInt(5); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BASCULEGION, Species.JELLICENT ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; - p.formIndex = 1; - })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.KINGAMBIT ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.VOLCARONA, Species.SLITHER_WING ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYUREM], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", []).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; - })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CLAWITZER, Species.DRAGALGE ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HELIOLISK, Species.MALAMAR ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })), - [TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") - .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.PYROAR ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; - })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.IRON_MOTH ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.YVELTAL], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.LUSAMINE]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", []).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LILLIGANT, Species.HISUI_LILLIGANT ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.BEWEAR ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - })), - [TrainerType.LUSAMINE_2]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", [], true).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PHEROMOSA ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.STAKATAKA, Species.CELESTEELA, Species.GUZZLORD ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.NECROZMA ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.GUZMA]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", []).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LOKIX, Species.YANMEGA ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HERACROSS ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALVANTULA, Species.VIKAVOLT])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PINSIR ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - })), - [TrainerType.GUZMA_2]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", [], true).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.abilityIndex = 2; //Anticipation - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HISUI_SAMUROTT, Species.CRAWDAUNT ], TrainerSlot.TRAINER, true, p => { - p.abilityIndex = 2; //Sharpness, Adaptability - })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.PINSIR ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.formIndex = 1; - p.generateName(); - })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.BUZZWOLE ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.XURKITREE ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })), - [TrainerType.ROSE]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", []).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.FERROTHORN, Species.ESCAVALIER ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SIRFETCHD, Species.MR_RIME ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CORVIKNIGHT ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PERRSERKER, Species.KLINKLANG ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.COPPERAJAH ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.formIndex = 1; - p.generateName(); - })), - [TrainerType.ROSE_2]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", [], true).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AEGISLASH, Species.GHOLDENGO ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DRACOVISH, Species.DRACOZOLT ], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 1; //Strong Jaw, Hustle - })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MELMETAL ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GALAR_ARTICUNO, Species.GALAR_ZAPDOS, Species.GALAR_MOLTRES ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.COPPERAJAH ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.formIndex = 1; - p.generateName(); - })), -}; +import BattleScene, {startingWave} from "../battle-scene"; +import {ModifierTypeFunc, modifierTypes} from "../modifier/modifier-type"; +import {EnemyPokemon} from "../field/pokemon"; +import * as Utils from "../utils"; +import {PokeballType} from "./pokeball"; +import {pokemonEvolutions, pokemonPrevolutions} from "./pokemon-evolutions"; +import PokemonSpecies, {getPokemonSpecies, PokemonSpeciesFilter} from "./pokemon-species"; +import {tmSpecies} from "./tms"; +import {Type} from "./type"; +import {doubleBattleDialogue} from "./dialogue"; +import {PersistentModifier} from "../modifier/modifier"; +import {TrainerVariant} from "../field/trainer"; +import {getIsInitialized, initI18n} from "#app/plugins/i18n"; +import i18next from "i18next"; +import {Moves} from "#enums/moves"; +import {PartyMemberStrength} from "#enums/party-member-strength"; +import {Species} from "#enums/species"; +import {TrainerType} from "#enums/trainer-type"; +import {Gender} from "./gender"; + +export enum TrainerPoolTier { + COMMON, + UNCOMMON, + RARE, + SUPER_RARE, + ULTRA_RARE +} + +export interface TrainerTierPools { + [key: integer]: Species[] +} + +export enum TrainerSlot { + NONE, + TRAINER, + TRAINER_PARTNER +} + +export class TrainerPartyTemplate { + public size: integer; + public strength: PartyMemberStrength; + public sameSpecies: boolean; + public balanced: boolean; + + constructor(size: integer, strength: PartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { + this.size = size; + this.strength = strength; + this.sameSpecies = !!sameSpecies; + this.balanced = !!balanced; + } + + getStrength(index: integer): PartyMemberStrength { + return this.strength; + } + + isSameSpecies(index: integer): boolean { + return this.sameSpecies; + } + + isBalanced(index: integer): boolean { + return this.balanced; + } +} + +export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { + public templates: TrainerPartyTemplate[]; + + constructor(...templates: TrainerPartyTemplate[]) { + super(templates.reduce((total: integer, template: TrainerPartyTemplate) => { + total += template.size; + return total; + }, 0), PartyMemberStrength.AVERAGE); + this.templates = templates; + } + + getStrength(index: integer): PartyMemberStrength { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.getStrength(index - t); + } + t += template.size; + } + + return super.getStrength(index); + } + + isSameSpecies(index: integer): boolean { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.isSameSpecies(index - t); + } + t += template.size; + } + + return super.isSameSpecies(index); + } + + isBalanced(index: integer): boolean { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.isBalanced(index - t); + } + t += template.size; + } + + return super.isBalanced(index); + } +} + +export const trainerPartyTemplates = { + ONE_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + ONE_AVG: new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), + ONE_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + ONE_STRONG: new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), + ONE_STRONGER: new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), + TWO_WEAKER: new TrainerPartyTemplate(2, PartyMemberStrength.WEAKER), + TWO_WEAK: new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), + TWO_WEAK_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_WEAK_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_WEAK_SAME_TWO_WEAK_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true)), + TWO_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG: new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), + TWO_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_AVG_SAME_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG_SAME_TWO_AVG_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true)), + TWO_STRONG: new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), + THREE_WEAK: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK), + THREE_WEAK_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, true), + THREE_AVG: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), + THREE_AVG_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, true), + THREE_WEAK_BALANCED: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, false, true), + FOUR_WEAKER: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER), + FOUR_WEAKER_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER, true), + FOUR_WEAK: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK), + FOUR_WEAK_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, true), + FOUR_WEAK_BALANCED: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, false, true), + FIVE_WEAKER: new TrainerPartyTemplate(5, PartyMemberStrength.WEAKER), + FIVE_WEAK: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK), + FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK, false, true), + SIX_WEAKER: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER), + SIX_WEAKER_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true), + SIX_WEAK_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, true), + SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, false, true), + + GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + GYM_LEADER_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + GYM_LEADER_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + GYM_LEADER_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + GYM_LEADER_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + + ELITE_FOUR: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + + CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), new TrainerPartyTemplate(5, PartyMemberStrength.STRONG, false, true)), + + RIVAL: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + RIVAL_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), + RIVAL_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), + RIVAL_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true)), + RIVAL_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + RIVAL_6: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)) +}; + +type PartyTemplateFunc = (scene: BattleScene) => TrainerPartyTemplate; +type PartyMemberFunc = (scene: BattleScene, level: integer, strength: PartyMemberStrength) => EnemyPokemon; +type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; + +export interface PartyMemberFuncs { + [key: integer]: PartyMemberFunc +} + +export class TrainerConfig { + public trainerType: TrainerType; + public trainerTypeDouble: TrainerType; + public name: string; + public nameFemale: string; + public nameDouble: string; + public title: string; + public titleDouble: string; + public hasGenders: boolean = false; + public hasDouble: boolean = false; + public hasCharSprite: boolean = false; + public doubleOnly: boolean = false; + public moneyMultiplier: number = 1; + public isBoss: boolean = false; + public hasStaticParty: boolean = false; + public useSameSeedForAllMembers: boolean = false; + public mixedBattleBgm: string; + public battleBgm: string; + public encounterBgm: string; + public femaleEncounterBgm: string; + public doubleEncounterBgm: string; + public victoryBgm: string; + public genModifiersFunc: GenModifiersFunc; + public modifierRewardFuncs: ModifierTypeFunc[] = []; + public partyTemplates: TrainerPartyTemplate[]; + public partyTemplateFunc: PartyTemplateFunc; + public partyMemberFuncs: PartyMemberFuncs = {}; + public speciesPools: TrainerTierPools; + public speciesFilter: PokemonSpeciesFilter; + public specialtyTypes: Type[] = []; + public hasVoucher: boolean = false; + + public encounterMessages: string[] = []; + public victoryMessages: string[] = []; + public defeatMessages: string[] = []; + + public femaleEncounterMessages: string[]; + public femaleVictoryMessages: string[]; + public femaleDefeatMessages: string[]; + + public doubleEncounterMessages: string[]; + public doubleVictoryMessages: string[]; + public doubleDefeatMessages: string[]; + + constructor(trainerType: TrainerType, allowLegendaries?: boolean) { + 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(); + } + + getKey(): string { + return TrainerType[this.getDerivedType()].toString().toLowerCase(); + } + + getSpriteKey(female?: boolean, isDouble: boolean = false): string { + let ret = this.getKey(); + if (this.hasGenders) { + ret += `_${female ? "f" : "m"}`; + } + // If a special double trainer class was set, set it as the sprite key + if (this.trainerTypeDouble && female && isDouble) { + // Get the derived type for the double trainer since the sprite key is based on the derived type + ret = TrainerType[this.getDerivedType(this.trainerTypeDouble)].toString().toLowerCase(); + } + return ret; + } + + setName(name: string): TrainerConfig { + if (name === "Finn") { + // Give the rival a localized name + // First check if i18n is initialized + if (!getIsInitialized()) { + initI18n(); + } + // This is only the male name, because the female name is handled in a different function (setHasGenders) + if (name === "Finn") { + name = i18next.t("trainerNames:rival"); + } + } + this.name = name; + return this; + } + + /** + * Sets if a boss trainer will have a voucher or not. + * @param hasVoucher - If the boss trainer will have a voucher. + */ + setHasVoucher(hasVoucher: boolean): void { + this.hasVoucher = hasVoucher; + } + + setTitle(title: string): TrainerConfig { + // First check if i18n is initialized + if (!getIsInitialized()) { + initI18n(); + } + + // Make the title lowercase and replace spaces with underscores + title = title.toLowerCase().replace(/\s/g, "_"); + + // Get the title from the i18n file + this.title = i18next.t(`titles:${title}`); + + + return this; + } + + + /** + * Returns the derived trainer type for a given trainer type. + * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) + * @returns {TrainerType} - The derived trainer type. + */ + getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType { + let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType; + switch (trainerType) { + case TrainerType.RIVAL_2: + case TrainerType.RIVAL_3: + case TrainerType.RIVAL_4: + case TrainerType.RIVAL_5: + case TrainerType.RIVAL_6: + trainerType = TrainerType.RIVAL; + break; + case TrainerType.LANCE_CHAMPION: + trainerType = TrainerType.LANCE; + break; + 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.LUSAMINE_2: + trainerType = TrainerType.LUSAMINE; + break; + case TrainerType.GUZMA_2: + trainerType = TrainerType.GUZMA; + break; + case TrainerType.ROSE_2: + trainerType = TrainerType.ROSE; + break; + case TrainerType.MARNIE_ELITE: + trainerType = TrainerType.MARNIE; + break; + case TrainerType.NESSA_ELITE: + trainerType = TrainerType.NESSA; + break; + case TrainerType.BEA_ELITE: + trainerType = TrainerType.BEA; + break; + case TrainerType.ALLISTER_ELITE: + trainerType = TrainerType.ALLISTER; + break; + case TrainerType.RAIHAN_ELITE: + trainerType = TrainerType.RAIHAN; + break; + } + + return trainerType; + } + + /** + * Sets the configuration for trainers with genders, including the female name and encounter background music (BGM). + * @param {string} [nameFemale] - The name of the female trainer. If 'Ivy', a localized name will be assigned. + * @param {TrainerType | string} [femaleEncounterBgm] - The encounter BGM for the female trainer, which can be a TrainerType or a string. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ + setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig { + // If the female name is 'Ivy' (the rival), assign a localized name. + if (nameFemale === "Ivy") { + // Check if the internationalization (i18n) system is initialized. + if (!getIsInitialized()) { + // Initialize the i18n system if it is not already initialized. + initI18n(); + } + // Set the localized name for the female rival. + this.nameFemale = i18next.t("trainerNames:rival_female"); + } else { + // Otherwise, assign the provided female name. + this.nameFemale = nameFemale!; // TODO: is this bang correct? + } + + // Indicate that this trainer configuration includes genders. + this.hasGenders = true; + + // If a female encounter BGM is provided. + if (femaleEncounterBgm) { + // If the BGM is a TrainerType (number), convert it to a string, replace underscores with spaces, and convert to lowercase. + // Otherwise, assign the provided string as the BGM. + this.femaleEncounterBgm = typeof femaleEncounterBgm === "number" + ? TrainerType[femaleEncounterBgm].toString().replace(/_/g, " ").toLowerCase() + : femaleEncounterBgm; + } + + // Return the updated TrainerConfig instance. + return this; + } + + /** + * Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM. + * @param nameDouble - The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles). + * @param doubleEncounterBgm - The encounter BGM for the double trainer, which can be a TrainerType or a string. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ + setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig { + this.hasDouble = true; + this.nameDouble = nameDouble; + if (doubleEncounterBgm) { + this.doubleEncounterBgm = typeof doubleEncounterBgm === "number" ? TrainerType[doubleEncounterBgm].toString().replace(/\_/g, " ").toLowerCase() : doubleEncounterBgm; + } + return this; + } + + /** + * Sets the trainer type for double battles. + * @param trainerTypeDouble - The TrainerType of the partner in a double battle. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ + setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig { + this.trainerTypeDouble = trainerTypeDouble; + this.setDoubleMessages(this.nameDouble); + return this; + } + + /** + * Sets the encounter and victory messages for double trainers. + * @param nameDouble - The name of the pair (e.g. "red_blue_double"). + */ + setDoubleMessages(nameDouble: string) { + // Check if there is double battle dialogue for this trainer + if (doubleBattleDialogue[nameDouble]) { + // Set encounter and victory messages for double trainers + this.doubleEncounterMessages = doubleBattleDialogue[nameDouble].encounter; + this.doubleVictoryMessages = doubleBattleDialogue[nameDouble].victory; + this.doubleDefeatMessages = doubleBattleDialogue[nameDouble].defeat; + } + } + + /** + * Sets the title for double trainers + * @param titleDouble - the key for the title in the i18n file. (e.g., "champion_double"). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ + setDoubleTitle(titleDouble: string): TrainerConfig { + // First check if i18n is initialized + if (!getIsInitialized()) { + initI18n(); + } + + // Make the title lowercase and replace spaces with underscores + titleDouble = titleDouble.toLowerCase().replace(/\s/g, "_"); + + // Get the title from the i18n file + this.titleDouble = i18next.t(`titles:${titleDouble}`); + + return this; + } + + setHasCharSprite(): TrainerConfig { + this.hasCharSprite = true; + return this; + } + + setDoubleOnly(): TrainerConfig { + this.doubleOnly = true; + return this; + } + + setMoneyMultiplier(moneyMultiplier: number): TrainerConfig { + this.moneyMultiplier = moneyMultiplier; + return this; + } + + setBoss(): TrainerConfig { + this.isBoss = true; + return this; + } + + setStaticParty(): TrainerConfig { + this.hasStaticParty = true; + return this; + } + + setUseSameSeedForAllMembers(): TrainerConfig { + this.useSameSeedForAllMembers = true; + return this; + } + + setMixedBattleBgm(mixedBattleBgm: string): TrainerConfig { + this.mixedBattleBgm = mixedBattleBgm; + return this; + } + + setBattleBgm(battleBgm: string): TrainerConfig { + this.battleBgm = battleBgm; + return this; + } + + setEncounterBgm(encounterBgm: TrainerType | string): TrainerConfig { + this.encounterBgm = typeof encounterBgm === "number" ? TrainerType[encounterBgm].toString().toLowerCase() : encounterBgm; + return this; + } + + setVictoryBgm(victoryBgm: string): TrainerConfig { + this.victoryBgm = victoryBgm; + return this; + } + + setPartyTemplates(...partyTemplates: TrainerPartyTemplate[]): TrainerConfig { + this.partyTemplates = partyTemplates; + return this; + } + + setPartyTemplateFunc(partyTemplateFunc: PartyTemplateFunc): TrainerConfig { + this.partyTemplateFunc = partyTemplateFunc; + return this; + } + + setPartyMemberFunc(slotIndex: integer, partyMemberFunc: PartyMemberFunc): TrainerConfig { + this.partyMemberFuncs[slotIndex] = partyMemberFunc; + return this; + } + + setSpeciesPools(speciesPools: TrainerTierPools | Species[]): TrainerConfig { + this.speciesPools = (Array.isArray(speciesPools) ? {[TrainerPoolTier.COMMON]: speciesPools} : speciesPools) as unknown as TrainerTierPools; + return this; + } + + setSpeciesFilter(speciesFilter: PokemonSpeciesFilter, allowLegendaries?: boolean): TrainerConfig { + const baseFilter = this.speciesFilter; + this.speciesFilter = allowLegendaries ? speciesFilter : species => speciesFilter(species) && baseFilter(species); + return this; + } + + setSpecialtyTypes(...specialtyTypes: Type[]): TrainerConfig { + this.specialtyTypes = specialtyTypes; + return this; + } + + setGenModifiersFunc(genModifiersFunc: GenModifiersFunc): TrainerConfig { + this.genModifiersFunc = genModifiersFunc; + return this; + } + + setModifierRewardFuncs(...modifierTypeFuncs: (() => ModifierTypeFunc)[]): TrainerConfig { + this.modifierRewardFuncs = modifierTypeFuncs.map(func => () => { + const modifierTypeFunc = func(); + const modifierType = modifierTypeFunc(); + modifierType.withIdFromFunc(modifierTypeFunc); + return modifierType; + }); + return this; + } + + /** + * Returns the pool of species for an evil team admin + * @param team - The evil team the admin belongs to. + * @returns {TrainerTierPools} + */ + speciesPoolPerEvilTeamAdmin(team): TrainerTierPools { + team = team.toLowerCase(); + switch (team) { + case "rocket": { + return { + [TrainerPoolTier.COMMON]: [Species.RATTATA, Species.KOFFING, Species.EKANS, Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], + [TrainerPoolTier.UNCOMMON]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], + [TrainerPoolTier.RARE]: [Species.DRATINI, Species.LARVITAR] + }; + } + case "magma": { + return { + [TrainerPoolTier.COMMON]: [Species.NUMEL, Species.POOCHYENA, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR], + [TrainerPoolTier.UNCOMMON]: [Species.TRAPINCH, Species.HEATMOR], + [TrainerPoolTier.RARE]: [Species.CAPSAKID, Species.CHARCADET] + }; + } + case "aqua": { + return { + [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.CORPHISH, Species.ZIGZAGOON, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], + [TrainerPoolTier.UNCOMMON]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], + [TrainerPoolTier.RARE]: [Species.DONDOZO] + }; + } + case "galactic": { + return { + [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.BRONZOR, Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], + [TrainerPoolTier.UNCOMMON]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], + [TrainerPoolTier.RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] + }; + } + case "plasma": { + return { + [TrainerPoolTier.COMMON]: [Species.SCRAFTY, Species.LILLIPUP, Species.PURRLOIN, Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], + [TrainerPoolTier.UNCOMMON]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], + [TrainerPoolTier.RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] + }; + } + case "flare": { + return { + [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], + [TrainerPoolTier.UNCOMMON]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], + [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.DRUDDIGON] + }; + } + case "aether": { + return { + [TrainerPoolTier.COMMON]: [ Species.BRUXISH, Species.SLOWPOKE, Species.BALTOY, Species.EXEGGCUTE, Species.ABRA, Species.ALOLA_RAICHU, Species.ELGYEM, Species.NATU], + [TrainerPoolTier.UNCOMMON]: [Species.GALAR_SLOWKING, Species.MEDITITE, Species.BELDUM, Species.ORANGURU, Species.HATTERENE, Species.INKAY, Species.RALTS], + [TrainerPoolTier.RARE]: [Species.ARMAROUGE, Species.GIRAFARIG, Species.PORYGON] + }; + } + case "skull": { + return { + [TrainerPoolTier.COMMON]: [ Species.MAREANIE, Species.ALOLA_GRIMER, Species.GASTLY, Species.ZUBAT, Species.LURANTIS, Species.VENIPEDE, Species.BUDEW, Species.KOFFING], + [TrainerPoolTier.UNCOMMON]: [Species.GALAR_SLOWBRO, Species.SKORUPI, Species.PALDEA_WOOPER, Species.NIDORAN_F, Species.CROAGUNK, Species.MANDIBUZZ], + [TrainerPoolTier.RARE]: [Species.DRAGALGE, Species.HISUI_SNEASEL] + }; + } + case "macro": { + return { + [TrainerPoolTier.COMMON]: [ Species.HATTERENE, Species.MILOTIC, Species.TSAREENA, Species.SALANDIT, Species.GALAR_PONYTA, Species.GOTHITA, Species.FROSLASS], + [TrainerPoolTier.UNCOMMON]: [Species.MANDIBUZZ, Species.MAREANIE, Species.ALOLA_VULPIX, Species.TOGEPI, Species.GALAR_CORSOLA, Species.SINISTEA, Species.APPLIN], + [TrainerPoolTier.RARE]: [Species.TINKATINK, Species.HISUI_LILLIGANT] + }; + } + } + + console.warn(`Evil team admin for ${team} not found. Returning empty species pools.`); + return []; + } + + /** + * Initializes the trainer configuration for an evil team admin. + * @param title - The title of the evil team admin. + * @param poolName - The evil team the admin belongs to. + * @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForEvilTeamAdmin(title: string, poolName: string, signatureSpecies: (Species | Species[])[],): TrainerConfig { + if (!getIsInitialized()) { + initI18n(); + } + this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); + + // Set the species pools for the evil team admin. + this.speciesPools = this.speciesPoolPerEvilTeamAdmin(poolName); + + signatureSpecies.forEach((speciesPool, s) => { + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + this.setHasVoucher(false); + this.setTitle(title); + this.setMoneyMultiplier(1.5); + this.setBoss(); + this.setStaticParty(); + this.setBattleBgm("battle_plasma_boss"); + this.setVictoryBgm("victory_team_plasma"); + + 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. + * @param boolean whether or not this is the rematch fight + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForEvilTeamLeader(title: string, signatureSpecies: (Species | Species[])[], rematch: boolean = false, ...specialtyTypes: Type[]): TrainerConfig { + if (!getIsInitialized()) { + initI18n(); + } + if (rematch) { + this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR); + } else { + 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.setHasVoucher(true); + this.setBattleBgm("battle_plasma_boss"); + this.setVictoryBgm("victory_team_plasma"); + + return this; + } + + /** + * Initializes the trainer configuration for a Gym Leader. + * @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader. + * @param {Type[]} specialtyTypes - The specialty types for the Gym Leader. + * @param isMale - Whether the Gym Leader is Male or Not (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForGymLeader(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { + // Check if the internationalization (i18n) system is initialized. + if (!getIsInitialized()) { + initI18n(); + } + + // Set the function to generate the Gym Leader's party template. + this.setPartyTemplateFunc(getGymLeaderPartyTemplate); + + // Set up party members with their corresponding species. + signatureSpecies.forEach((speciesPool, s) => { + // Ensure speciesPool is an array. + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + // Set a function to get a random party member from the species pool. + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + + // If specialty types are provided, set species filter and specialty types. + if (specialtyTypes.length) { + this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined); + this.setSpecialtyTypes(...specialtyTypes); + } + + // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + + // Set the title to "gym_leader". (this is the key in the i18n file) + this.setTitle("gym_leader"); + if (!isMale) { + this.setTitle("gym_leader_female"); + } + + // Configure various properties for the Gym Leader. + this.setMoneyMultiplier(2.5); + this.setBoss(); + this.setStaticParty(); + this.setHasVoucher(true); + this.setBattleBgm("battle_unova_gym"); + this.setVictoryBgm("victory_gym"); + this.setGenModifiersFunc(party => { + const waveIndex = party[0].scene.currentBattle.waveIndex; + return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : undefined); + }); + + return this; + } + + /** + * Initializes the trainer configuration for an Elite Four member. + * @param {Species | Species[]} signatureSpecies - The signature species for the Elite Four member. + * @param {Type[]} specialtyTypes - The specialty types for the Elite Four member. + * @param isMale - Whether the Elite Four Member is Male or Female (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ + initForEliteFour(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { + // Check if the internationalization (i18n) system is initialized. + if (!getIsInitialized()) { + initI18n(); + } + + // Set the party templates for the Elite Four. + this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR); + + // Set up party members with their corresponding species. + signatureSpecies.forEach((speciesPool, s) => { + // Ensure speciesPool is an array. + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + // Set a function to get a random party member from the species pool. + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + + // Set species filter and specialty types if provided, otherwise filter by base total. + if (specialtyTypes.length) { + this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= 450); + this.setSpecialtyTypes(...specialtyTypes); + } else { + this.setSpeciesFilter(p => p.baseTotal >= 450); + } + + // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + + // Set the title to "elite_four". (this is the key in the i18n file) + this.setTitle("elite_four"); + if (!isMale) { + this.setTitle("elite_four_female"); + } + + // Configure various properties for the Elite Four member. + this.setMoneyMultiplier(3.25); + this.setBoss(); + this.setStaticParty(); + this.setHasVoucher(true); + this.setBattleBgm("battle_unova_elite"); + this.setVictoryBgm("victory_gym"); + this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : undefined)); + + return this; + } + + /** + * Initializes the trainer configuration for a Champion. + * @param {Species | Species[]} signatureSpecies - The signature species for the Champion. + * @param isMale - Whether the Champion is Male or Female (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ + initForChampion(signatureSpecies: (Species | Species[])[], isMale: boolean): TrainerConfig { + // Check if the internationalization (i18n) system is initialized. + if (!getIsInitialized()) { + initI18n(); + } + + // Set the party templates for the Champion. + this.setPartyTemplates(trainerPartyTemplates.CHAMPION); + + // Set up party members with their corresponding species. + signatureSpecies.forEach((speciesPool, s) => { + // Ensure speciesPool is an array. + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + // Set a function to get a random party member from the species pool. + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + + // Set species filter to only include species with a base total of 470 or higher. + this.setSpeciesFilter(p => p.baseTotal >= 470); + + // Localize the trainer's name by converting it to lowercase and replacing spaces with underscores. + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + + // Set the title to "champion". (this is the key in the i18n file) + this.setTitle("champion"); + if (!isMale) { + this.setTitle("champion_female"); + } + + + // Configure various properties for the Champion. + this.setMoneyMultiplier(10); + this.setBoss(); + this.setStaticParty(); + this.setHasVoucher(true); + this.setBattleBgm("battle_champion_alder"); + this.setVictoryBgm("victory_champion"); + this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 3)); + + return this; + } + + /** + * Retrieves the title for the trainer based on the provided trainer slot and variant. + * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. + * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. + * @returns {string} - The title of the trainer. + **/ + getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string { + const ret = this.name; + + // Check if the variant is double and the name for double exists + if (!trainerSlot && variant === TrainerVariant.DOUBLE && this.nameDouble) { + return this.nameDouble; + } + + // Female variant + if (this.hasGenders) { + // If the name is already set + if (this.nameFemale) { + // Check if the variant is either female or this is for the partner in a double battle + if (variant === TrainerVariant.FEMALE || (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER)) { + return this.nameFemale; + } + } else + // Check if !variant is true, if so return the name, else return the name with _female appended + if (variant) { + if (!getIsInitialized()) { + initI18n(); + } + // Check if the female version exists in the i18n file + if (i18next.exists(`trainerClasses:${this.name.toLowerCase()}`)) { + // If it does, return + return ret + "_female"; + } else { + // If it doesn't, we do not do anything and go to the normal return + // This is to prevent the game from displaying an error if a female version of the trainer does not exist in the localization + } + } + } + + return ret; + } + + loadAssets(scene: BattleScene, variant: TrainerVariant): Promise { + return new Promise(resolve => { + const isDouble = variant === TrainerVariant.DOUBLE; + const trainerKey = this.getSpriteKey(variant === TrainerVariant.FEMALE, false); + const partnerTrainerKey = this.getSpriteKey(true, true); + scene.loadAtlas(trainerKey, "trainer"); + if (isDouble) { + scene.loadAtlas(partnerTrainerKey, "trainer"); + } + scene.load.once(Phaser.Loader.Events.COMPLETE, () => { + const originalWarn = console.warn; + // Ignore warnings for missing frames, because there will be a lot + console.warn = () => { + }; + const frameNames = scene.anims.generateFrameNames(trainerKey, { + zeroPad: 4, + suffix: ".png", + start: 1, + end: 128 + }); + const partnerFrameNames = isDouble + ? scene.anims.generateFrameNames(partnerTrainerKey, { + zeroPad: 4, + suffix: ".png", + start: 1, + end: 128 + }) + : ""; + console.warn = originalWarn; + if (!(scene.anims.exists(trainerKey))) { + scene.anims.create({ + key: trainerKey, + frames: frameNames, + frameRate: 24, + repeat: -1 + }); + } + if (isDouble && !(scene.anims.exists(partnerTrainerKey))) { + scene.anims.create({ + key: partnerTrainerKey, + frames: partnerFrameNames, + frameRate: 24, + repeat: -1 + }); + } + resolve(); + }); + if (!scene.load.isLoading()) { + scene.load.start(); + } + }); + } +} + +let t = 0; + +interface TrainerConfigs { + [key: integer]: TrainerConfig +} + +/** + * The function to get variable strength grunts + * @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 < 63) { + return trainerPartyTemplates.THREE_AVG; + } else if (waveIndex < 65) { + return trainerPartyTemplates.TWO_AVG_ONE_STRONG; + } else if (waveIndex < 112) { + return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + } else { + 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)]; +} + +function getGymLeaderPartyTemplate(scene: BattleScene) { + return getWavePartyTemplate(scene, trainerPartyTemplates.GYM_LEADER_1, trainerPartyTemplates.GYM_LEADER_2, trainerPartyTemplates.GYM_LEADER_3, trainerPartyTemplates.GYM_LEADER_4, trainerPartyTemplates.GYM_LEADER_5); +} + +function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void): PartyMemberFunc { + return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => { + let species = Utils.randSeedItem(speciesPool); + if (!ignoreEvolution) { + species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex); + } + return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess); + }; +} + +function getSpeciesFilterRandomPartyMemberFunc(speciesFilter: PokemonSpeciesFilter, trainerSlot: TrainerSlot = TrainerSlot.TRAINER, allowLegendaries?: boolean, postProcess?: (EnemyPokemon: EnemyPokemon) => void): PartyMemberFunc { + const originalSpeciesFilter = speciesFilter; + speciesFilter = (species: PokemonSpecies) => (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) && !species.isTrainerForbidden() && originalSpeciesFilter(species); + return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => { + const ret = scene.addEnemyPokemon(getPokemonSpecies(scene.randomSpecies(scene.currentBattle.waveIndex, level, false, speciesFilter).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex)), level, trainerSlot, undefined, undefined, postProcess); + return ret; + }; +} + +function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: Type[]): PersistentModifier[] { + const ret: PersistentModifier[] = []; + const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i); + for (let t = 0; t < Math.min(count, party.length); t++) { + const randomIndex = Utils.randSeedItem(partyMemberIndexes); + partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); + ret.push(modifierTypes.TERA_SHARD().generateType([], [Utils.randSeedItem(types ? types : party[randomIndex].getTypes())])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct? + } + return ret; +} + +type SignatureSpecies = { + [key in string]: (Species | Species[])[]; +}; + +/* + * The signature species for each Gym Leader, Elite Four member, and Champion. + * The key is the trainer type, and the value is an array of Species or Species arrays. + * This is in a separate const so it can be accessed from other places and not just the trainerConfigs + */ +export const signatureSpecies: SignatureSpecies = { + BROCK: [Species.GEODUDE, Species.ONIX], + MISTY: [Species.STARYU, Species.PSYDUCK], + LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ], + ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP], + JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT], + SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON], + BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR], + GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F], + FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO], + BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR], + WHITNEY: [Species.GIRAFARIG, Species.MILTANK], + MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE], + CHUCK: [Species.POLIWRATH, Species.MANKEY], + JASMINE: [Species.MAGNEMITE, Species.STEELIX], + PRYCE: [Species.SEEL, Species.SWINUB], + CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS], + ROXANNE: [Species.GEODUDE, Species.NOSEPASS], + BRAWLY: [Species.MACHOP, Species.MAKUHITA], + WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE], + FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL], + NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.CHANSEY, Species.KANGASKHAN], + WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY], + TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE], + LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR], + JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH], + ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE], + GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG], + MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR], + CRASHER_WAKE: [Species.BUIZEL, Species.MAGIKARP, Species.PIPLUP], + FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB], + BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON], + CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT], + VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM], + CILAN: [Species.PANSAGE, Species.COTTONEE, Species.PETILIL], + CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.HEATMOR], + CRESS: [Species.PANPOUR, Species.BASCULIN, Species.TYMPOLE], + CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PATRAT], + LENORA: [Species.KANGASKHAN, Species.DEERLING, Species.AUDINO], + ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI], + BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST], + ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK], + CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT], + SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET], + BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO], + DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO], + MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA], + VIOLA: [Species.SURSKIT, Species.SCATTERBUG], + GRANT: [Species.AMAURA, Species.TYRUNT], + KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO], + RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT], + CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA], + VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME], + OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING], + WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL], + MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET], + NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD], + KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL], + BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS], + ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY], + OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING], + BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR], + GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE], + MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME], + PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY], + MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO], + RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY], + KATY: [Species.NYMBLE, Species.TAROUNTULA, Species.HERACROSS], + BRASSIUS: [Species.SMOLIV, Species.SHROOMISH, Species.ODDISH], + IONO: [Species.TADBULB, Species.WATTREL, Species.VOLTORB], + KOFU: [Species.VELUZA, Species.WIGLETT, Species.WINGULL], + LARRY: [Species.STARLY, Species.DUNSPARCE, Species.KOMALA], + RYME: [Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], + TULIP: [Species.GIRAFARIG, Species.FLITTLE, Species.RALTS], + GRUSHA: [Species.CETODDLE, Species.ALOLA_VULPIX, Species.CUBCHOO], + 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.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.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.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION], + BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR], + 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], + MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME], + 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, Species.ANNIHILAPE]], + MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO], + 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.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.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 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, 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 +}; + +export const trainerConfigs: TrainerConfigs = { + [TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(), + [TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders("Ace Trainer Female").setHasDouble("Ace Duo").setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER) + .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.THREE_WEAK_BALANCED, trainerPartyTemplates.FOUR_WEAK_BALANCED, trainerPartyTemplates.FIVE_WEAK_BALANCED, trainerPartyTemplates.SIX_WEAK_BALANCED)), + [TrainerType.ARTIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.THREE_AVG) + .setSpeciesPools([Species.SMEARGLE]), + [TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders("Backers").setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders("Backpacker Female").setHasDouble("Backpackers").setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER) + .setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.ONE_WEAK_ONE_STRONG, trainerPartyTemplates.ONE_AVG_ONE_STRONG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.RHYHORN, Species.AIPOM, Species.MAKUHITA, Species.MAWILE, Species.NUMEL, Species.LILLIPUP, Species.SANDILE, Species.WOOLOO], + [TrainerPoolTier.UNCOMMON]: [Species.GIRAFARIG, Species.ZANGOOSE, Species.SEVIPER, Species.CUBCHOO, Species.PANCHAM, Species.SKIDDO, Species.MUDBRAY], + [TrainerPoolTier.RARE]: [Species.TAUROS, Species.STANTLER, Species.DARUMAKA, Species.BOUFFALANT, Species.DEERLING, Species.IMPIDIMP], + [TrainerPoolTier.SUPER_RARE]: [Species.GALAR_DARUMAKA, Species.TEDDIURSA] + }), + [TrainerType.BAKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.35).setSpeciesFilter(s => s.isOfType(Type.GRASS) || s.isOfType(Type.FIRE)), + [TrainerType.BEAUTY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY), + [TrainerType.BIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON)), + [TrainerType.BLACK_BELT]: new TrainerConfig(++t).setHasGenders("Battle Girl", TrainerType.PSYCHIC).setHasDouble("Crush Kin").setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.FIGHTING) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_STRONG, trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_AVG_ONE_STRONG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.NIDORAN_F, Species.NIDORAN_M, Species.MACHOP, Species.MAKUHITA, Species.MEDITITE, Species.CROAGUNK, Species.TIMBURR], + [TrainerPoolTier.UNCOMMON]: [Species.MANKEY, Species.POLIWRATH, Species.TYROGUE, Species.BRELOOM, Species.SCRAGGY, Species.MIENFOO, Species.PANCHAM, Species.STUFFUL, Species.CRABRAWLER], + [TrainerPoolTier.RARE]: [Species.HERACROSS, Species.RIOLU, Species.THROH, Species.SAWK, Species.PASSIMIAN, Species.CLOBBOPUS], + [TrainerPoolTier.SUPER_RARE]: [Species.HITMONTOP, Species.INFERNAPE, Species.GALLADE, Species.HAWLUCHA, Species.HAKAMO_O], + [TrainerPoolTier.ULTRA_RARE]: [Species.KUBFU] + }), + [TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders("Breeder Female").setHasDouble("Breeders") + .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.FIVE_WEAKER, trainerPartyTemplates.SIX_WEAKER)) + .setSpeciesFilter(s => s.baseTotal < 450), + [TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders("Clerk Female").setHasDouble("Colleagues").setEncounterBgm(TrainerType.CLERK) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.MEOWTH, Species.PSYDUCK, Species.BUDEW, Species.PIDOVE, Species.CINCCINO, Species.LITLEO], + [TrainerPoolTier.UNCOMMON]: [Species.JIGGLYPUFF, Species.MAGNEMITE, Species.MARILL, Species.COTTONEE, Species.SKIDDO], + [TrainerPoolTier.RARE]: [Species.BUIZEL, Species.SNEASEL, Species.KLEFKI, Species.INDEEDEE] + }), + [TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders("Cyclist Female").setHasDouble("Cyclists").setEncounterBgm(TrainerType.CYCLIST) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.PICHU, Species.STARLY, Species.TAILLOW, Species.BOLTUND], + [TrainerPoolTier.UNCOMMON]: [Species.DODUO, Species.ELECTRIKE, Species.BLITZLE, Species.WATTREL], + [TrainerPoolTier.RARE]: [Species.YANMA, Species.NINJASK, Species.WHIRLIPEDE, Species.EMOLGA], + [TrainerPoolTier.SUPER_RARE]: [Species.ACCELGOR, Species.DREEPY] + }), + [TrainerType.DANCER]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.CYCLIST) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.RALTS, Species.SPOINK, Species.LOTAD, Species.BUDEW], + [TrainerPoolTier.UNCOMMON]: [Species.SPINDA, Species.SWABLU, Species.MARACTUS,], + [TrainerPoolTier.RARE]: [Species.BELLOSSOM, Species.HITMONTOP, Species.MIME_JR, Species.ORICORIO], + [TrainerPoolTier.SUPER_RARE]: [Species.POPPLIO] + }), + [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK), + [TrainerType.DOCTOR]: new TrainerConfig(++t).setHasGenders("Nurse", "lass").setHasDouble("Medical Team").setMoneyMultiplier(3).setEncounterBgm(TrainerType.CLERK) + .setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.HEAL_PULSE)), + [TrainerType.FIREBREATHER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK) + .setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SMOG) || s.isOfType(Type.FIRE)), + [TrainerType.FISHERMAN]: new TrainerConfig(++t).setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.BACKPACKER).setSpecialtyTypes(Type.WATER) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.THREE_WEAK_SAME, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.SIX_WEAKER) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.TENTACOOL, Species.MAGIKARP, Species.GOLDEEN, Species.STARYU, Species.REMORAID, Species.SKRELP, Species.CLAUNCHER, Species.ARROKUDA], + [TrainerPoolTier.UNCOMMON]: [Species.POLIWAG, Species.SHELLDER, Species.KRABBY, Species.HORSEA, Species.CARVANHA, Species.BARBOACH, Species.CORPHISH, Species.FINNEON, Species.TYMPOLE, Species.BASCULIN, Species.FRILLISH, Species.INKAY], + [TrainerPoolTier.RARE]: [Species.CHINCHOU, Species.CORSOLA, Species.WAILMER, Species.BARBOACH, Species.CLAMPERL, Species.LUVDISC, Species.MANTYKE, Species.ALOMOMOLA, Species.TATSUGIRI, Species.VELUZA], + [TrainerPoolTier.SUPER_RARE]: [Species.LAPRAS, Species.FEEBAS, Species.RELICANTH, Species.DONDOZO] + }), + [TrainerType.GUITARIST]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.ROUGHNECK).setSpecialtyTypes(Type.ELECTRIC).setSpeciesFilter(s => s.isOfType(Type.ELECTRIC)), + [TrainerType.HARLEQUIN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PSYCHIC).setSpeciesFilter(s => tmSpecies[Moves.TRICK_ROOM].indexOf(s.speciesId) > -1), + [TrainerType.HIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER) + .setPartyTemplates(trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.ONE_STRONG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.SANDSHREW, Species.DIGLETT, Species.GEODUDE, Species.MACHOP, Species.ARON, Species.ROGGENROLA, Species.DRILBUR, Species.NACLI], + [TrainerPoolTier.UNCOMMON]: [Species.ZUBAT, Species.RHYHORN, Species.ONIX, Species.CUBONE, Species.WOOBAT, Species.SWINUB, Species.NOSEPASS, Species.HIPPOPOTAS, Species.DWEBBLE, Species.KLAWF, Species.TOEDSCOOL], + [TrainerPoolTier.RARE]: [Species.TORKOAL, Species.TRAPINCH, Species.BARBOACH, Species.GOLETT, Species.ALOLA_DIGLETT, Species.ALOLA_GEODUDE, Species.GALAR_STUNFISK, Species.PALDEA_WOOPER], + [TrainerPoolTier.SUPER_RARE]: [Species.MAGBY, Species.LARVITAR] + }), + [TrainerType.HOOLIGANS]: new TrainerConfig(++t).setDoubleOnly().setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON) || s.isOfType(Type.DARK)), + [TrainerType.HOOPSTER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.INFIELDER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.JANITOR]: new TrainerConfig(++t).setMoneyMultiplier(1.1).setEncounterBgm(TrainerType.CLERK), + [TrainerType.LINEBACKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.MAID]: new TrainerConfig(++t).setMoneyMultiplier(1.6).setEncounterBgm(TrainerType.RICH), + [TrainerType.MUSICIAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SING)), + [TrainerType.HEX_MANIAC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PSYCHIC) + .setPartyTemplates(trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_AVG_ONE_STRONG, trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_STRONG) + .setSpeciesFilter(s => s.isOfType(Type.GHOST)), + [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm("lass"), + [TrainerType.OFFICER]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.CLERK) + .setPartyTemplates(trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.VULPIX, Species.GROWLITHE, Species.SNUBBULL, Species.POOCHYENA, Species.ELECTRIKE, Species.LILLIPUP, Species.YAMPER, Species.FIDOUGH], + [TrainerPoolTier.UNCOMMON]: [Species.HOUNDOUR, Species.ROCKRUFF, Species.MASCHIFF], + [TrainerPoolTier.RARE]: [Species.JOLTEON, Species.RIOLU], + [TrainerPoolTier.SUPER_RARE]: [], + [TrainerPoolTier.ULTRA_RARE]: [Species.ENTEI, Species.SUICUNE, Species.RAIKOU] + }), + [TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)), + [TrainerType.PILOT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1), + [TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName("PokéFan").setHasGenders("PokéFan Female").setHasDouble("PokéFan Family").setEncounterBgm(TrainerType.POKEFAN) + .setPartyTemplates(trainerPartyTemplates.SIX_WEAKER, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.FOUR_WEAK_SAME, trainerPartyTemplates.FIVE_WEAK, trainerPartyTemplates.SIX_WEAKER_SAME), + [TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Preschooler Female", "lass").setHasDouble("Preschoolers") + .setPartyTemplates(trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.FIVE_WEAKER) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.CATERPIE, Species.PICHU, Species.SANDSHREW, Species.LEDYBA, Species.BUDEW, Species.BURMY, Species.WOOLOO, Species.PAWMI, Species.SMOLIV], + [TrainerPoolTier.UNCOMMON]: [Species.EEVEE, Species.CLEFFA, Species.IGGLYBUFF, Species.SWINUB, Species.WOOPER, Species.DRIFLOON, Species.DEDENNE, Species.STUFFUL], + [TrainerPoolTier.RARE]: [Species.RALTS, Species.RIOLU, Species.JOLTIK, Species.TANDEMAUS], + [TrainerPoolTier.SUPER_RARE]: [Species.DARUMAKA, Species.TINKATINK], + }), + [TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders("Psychic Female").setHasDouble("Psychics").setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC) + .setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME, trainerPartyTemplates.ONE_STRONGER) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.ABRA, Species.DROWZEE, Species.RALTS, Species.SPOINK, Species.GOTHITA, Species.SOLOSIS, Species.BLIPBUG, Species.ESPURR, Species.HATENNA], + [TrainerPoolTier.UNCOMMON]: [Species.MIME_JR, Species.EXEGGCUTE, Species.MEDITITE, Species.NATU, Species.EXEGGCUTE, Species.WOOBAT, Species.INKAY, Species.ORANGURU], + [TrainerPoolTier.RARE]: [Species.ELGYEM, Species.SIGILYPH, Species.BALTOY, Species.GIRAFARIG, Species.MEOWSTIC], + [TrainerPoolTier.SUPER_RARE]: [Species.BELDUM, Species.ESPEON, Species.STANTLER], + }), + [TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName("Pokémon Ranger").setEncounterBgm(TrainerType.BACKPACKER).setHasGenders("Pokémon Ranger Female").setHasDouble("Pokémon Rangers") + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.PICHU, Species.GROWLITHE, Species.PONYTA, Species.ZIGZAGOON, Species.SEEDOT, Species.BIDOOF, Species.RIOLU, Species.SEWADDLE, Species.SKIDDO, Species.SALANDIT, Species.YAMPER], + [TrainerPoolTier.UNCOMMON]: [Species.AZURILL, Species.TAUROS, Species.MAREEP, Species.FARFETCHD, Species.TEDDIURSA, Species.SHROOMISH, Species.ELECTRIKE, Species.BUDEW, Species.BUIZEL, Species.MUDBRAY, Species.STUFFUL], + [TrainerPoolTier.RARE]: [Species.EEVEE, Species.SCYTHER, Species.KANGASKHAN, Species.RALTS, Species.MUNCHLAX, Species.ZORUA, Species.PALDEA_TAUROS, Species.TINKATINK, Species.CYCLIZAR, Species.FLAMIGO], + [TrainerPoolTier.SUPER_RARE]: [Species.LARVESTA], + }), + [TrainerType.RICH]: new TrainerConfig(++t).setMoneyMultiplier(5).setName("Gentleman").setHasGenders("Madame").setHasDouble("Rich Couple"), + [TrainerType.RICH_KID]: new TrainerConfig(++t).setMoneyMultiplier(3.75).setName("Rich Boy").setHasGenders("Lady").setHasDouble("Rich Kids").setEncounterBgm(TrainerType.RICH), + [TrainerType.ROUGHNECK]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.DARK)), + [TrainerType.SAILOR]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.BACKPACKER).setSpeciesFilter(s => s.isOfType(Type.WATER) || s.isOfType(Type.FIGHTING)), + [TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders("Scientist Female").setHasDouble("Scientists").setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.MAGNEMITE, Species.GRIMER, Species.DROWZEE, Species.VOLTORB, Species.KOFFING], + [TrainerPoolTier.UNCOMMON]: [Species.BALTOY, Species.BRONZOR, Species.FERROSEED, Species.KLINK, Species.CHARJABUG, Species.BLIPBUG, Species.HELIOPTILE], + [TrainerPoolTier.RARE]: [Species.ABRA, Species.DITTO, Species.PORYGON, Species.ELEKID, Species.SOLOSIS, Species.GALAR_WEEZING], + [TrainerPoolTier.SUPER_RARE]: [Species.OMANYTE, Species.KABUTO, Species.AERODACTYL, Species.LILEEP, Species.ANORITH, Species.CRANIDOS, Species.SHIELDON, Species.TIRTOUGA, Species.ARCHEN, Species.ARCTOVISH, Species.ARCTOZOLT, Species.DRACOVISH, Species.DRACOZOLT], + [TrainerPoolTier.ULTRA_RARE]: [Species.ROTOM, Species.MELTAN] + }), + [TrainerType.SMASHER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName("Worker").setHasGenders("Worker Female").setHasDouble("Workers").setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)), + [TrainerType.STRIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST), + [TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("School Kid Female", "lass").setHasDouble("School Kids") + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.ODDISH, Species.EXEGGCUTE, Species.TEDDIURSA, Species.WURMPLE, Species.RALTS, Species.SHROOMISH, Species.FLETCHLING], + [TrainerPoolTier.UNCOMMON]: [Species.VOLTORB, Species.WHISMUR, Species.MEDITITE, Species.MIME_JR, Species.NYMBLE], + [TrainerPoolTier.RARE]: [Species.TANGELA, Species.EEVEE, Species.YANMA], + [TrainerPoolTier.SUPER_RARE]: [Species.TADBULB] + }), + [TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble("Swimmers").setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)), + [TrainerType.TWINS]: new TrainerConfig(++t).setDoubleOnly().setMoneyMultiplier(0.65).setUseSameSeedForAllMembers() + .setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_STRONG)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PLUSLE, Species.VOLBEAT, Species.PACHIRISU, Species.SILCOON, Species.METAPOD, Species.IGGLYBUFF, Species.PETILIL, Species.EEVEE])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.MINUN, Species.ILLUMISE, Species.EMOLGA, Species.CASCOON, Species.KAKUNA, Species.CLEFFA, Species.COTTONEE, Species.EEVEE], TrainerSlot.TRAINER_PARTNER)) + .setEncounterBgm(TrainerType.TWINS), + [TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders("Veteran Female").setHasDouble("Veteran Duo").setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)), + [TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders("Waitress").setHasDouble("Restaurant Staff").setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.CLERK) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.CLEFFA, Species.CHATOT, Species.PANSAGE, Species.PANSEAR, Species.PANPOUR, Species.MINCCINO], + [TrainerPoolTier.UNCOMMON]: [Species.TROPIUS, Species.PETILIL, Species.BOUNSWEET, Species.INDEEDEE], + [TrainerPoolTier.RARE]: [Species.APPLIN, Species.SINISTEA, Species.POLTCHAGEIST] + }), + [TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders("Worker Female").setHasDouble("Workers").setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)), + [TrainerType.YOUNGSTER]: new TrainerConfig(++t).setMoneyMultiplier(0.5).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Lass", "lass").setHasDouble("Beginners").setPartyTemplates(trainerPartyTemplates.TWO_WEAKER) + .setSpeciesPools( + [Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP] + ), + [TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING, Species.GRIMER, Species.ODDISH], + [TrainerPoolTier.UNCOMMON]: [Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], + [TrainerPoolTier.RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], + [TrainerPoolTier.SUPER_RARE]: [Species.DRATINI, Species.LARVITAR] + }), + [TrainerType.ARCHER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.HOUNDOOM]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.ARIANA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin_female", "rocket", [Species.ARBOK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.PROTON]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.CROBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.PETREL]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.WEEZING]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.BALTOY, Species.BARBOACH], + [TrainerPoolTier.UNCOMMON]: [Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.ROLYCOLY, Species.GLIGAR], + [TrainerPoolTier.RARE]: [Species.TRAPINCH, Species.HEATMOR], + [TrainerPoolTier.SUPER_RARE]: [Species.CAPSAKID, Species.CHARCADET] + }), + [TrainerType.TABITHA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.COURTNEY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin_female", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH, Species.SPHEAL], + [TrainerPoolTier.UNCOMMON]: [Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], + [TrainerPoolTier.RARE]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], + [TrainerPoolTier.SUPER_RARE]: [Species.DONDOZO] + }), + [TrainerType.MATT]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.SHELLY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin_female", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE, Species.BRONZOR, Species.DRIFLOON, Species.BURMY], + [TrainerPoolTier.UNCOMMON]: [Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], + [TrainerPoolTier.RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], + [TrainerPoolTier.SUPER_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] + }), + [TrainerType.JUPITER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.SKUNTANK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.MARS]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.PURUGLY]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.SATURN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander", "galactic", [Species.TOXICROAK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE, Species.SANDILE, Species.TRUBBISH], + [TrainerPoolTier.UNCOMMON]: [Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], + [TrainerPoolTier.RARE]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], + [TrainerPoolTier.SUPER_RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] + }), + [TrainerType.ZINZOLIN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.CRYOGONAL]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.ROOD]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.SWOOBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK], + [TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], + [TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], + [TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN, Species.DRUDDIGON] + }), + [TrainerType.BRYONY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin_female", "flare", [Species.LIEPARD]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.XEROSIC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin", "flare", [Species.MALAMAR]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.AETHER_GRUNT]: new TrainerConfig(++t).setHasGenders("Aether Grunt Female").setHasDouble("Aether Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aether_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.PIKIPEK, Species.ROCKRUFF, Species.ALOLA_DIGLETT, Species.YUNGOOS, Species.CORSOLA, Species.ALOLA_GEODUDE, Species.BOUNSWEET, Species.LILLIPUP, Species.ALOLA_MAROWAK], + [TrainerPoolTier.UNCOMMON]: [ Species.POLIWAG, Species.STUFFUL, Species.ALOLA_EXEGGUTOR, Species.CRABRAWLER, Species.CUTIEFLY, Species.ALOLA_RAICHU, Species.ORICORIO, Species.MUDBRAY], + [TrainerPoolTier.RARE]: [ Species.ORANGURU, Species.PASSIMIAN, Species.GALAR_CORSOLA, Species.ALOLA_SANDSHREW, Species.ALOLA_VULPIX, Species.TURTONATOR, Species.DRAMPA], + [TrainerPoolTier.SUPER_RARE]: [Species.JANGMO_O, Species.PORYGON] + }), + [TrainerType.FABA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aether_admin", "aether", [Species.HYPNO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aether_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.SKULL_GRUNT]: new TrainerConfig(++t).setHasGenders("Skull Grunt Female").setHasDouble("Skull Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_skull_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.SALANDIT, Species.ALOLA_RATTATA, Species.ALOLA_MEOWTH, Species.SCRAGGY, Species.KOFFING, Species.ALOLA_GRIMER, Species.MAREANIE, Species.SPINARAK, Species.TRUBBISH], + [TrainerPoolTier.UNCOMMON]: [ Species.FOMANTIS, Species.SABLEYE, Species.SANDILE, Species.ALOLA_MAROWAK, Species.PANCHAM, Species.DROWZEE, Species.ZUBAT, Species.VENIPEDE, Species.VULLABY], + [TrainerPoolTier.RARE]: [Species.SANDYGAST, Species.PAWNIARD, Species.MIMIKYU, Species.DHELMISE, Species.GASTLY, Species.WISHIWASHI], + [TrainerPoolTier.SUPER_RARE]: [Species.GRUBBIN, Species.DEWPIDER] + }), + [TrainerType.PLUMERIA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("skull_admin", "skull", [Species.SALAZZLE]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_skull_admin").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.MACRO_GRUNT]: new TrainerConfig(++t).setHasGenders("Macro Grunt Female").setHasDouble("Macro Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_macro_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ Species.CUFANT, Species.GALAR_MEOWTH, Species.KLINK, Species.ROOKIDEE, Species.CRAMORANT, Species.GALAR_ZIGZAGOON, Species.SKWOVET, Species.STEELIX, Species.MAWILE, Species.FERROSEED], + [TrainerPoolTier.UNCOMMON]: [ Species.DRILBUR, Species.MAGNEMITE, Species.HATENNA, Species.ARROKUDA, Species.APPLIN, Species.GALAR_PONYTA, Species.GALAR_YAMASK, Species.SINISTEA, Species.RIOLU], + [TrainerPoolTier.RARE]: [Species.FALINKS, Species.BELDUM, Species.GALAR_FARFETCHD, Species.GALAR_MR_MIME, Species.HONEDGE, Species.SCIZOR, Species.GALAR_DARUMAKA], + [TrainerPoolTier.SUPER_RARE]: [Species.DURALUDON, Species.DREEPY] + }), + [TrainerType.OLEANA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("macro_admin", "macro", [Species.GARBODOR]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_oleana").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + + [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).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").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(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [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(); + p.generateName(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [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(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LATIAS, Species.LATIOS], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").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(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.SWAMPERT], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + })), + [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(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.GARCHOMP], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [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").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(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"], false).setMixedBattleBgm("battle_kalos_champion") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GOURGEIST], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.GARDEVOIR], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [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).setMixedBattleBgm("battle_galar_champion") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.CHARIZARD], TrainerSlot.TRAINER, true, p => { + p.formIndex = 3; + p.generateAndPopulateMoveset(); + p.generateName(); + })), + [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).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).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").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").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").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").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)) + .setSpeciesFilter(species => species.baseTotal >= 540) + .setGenModifiersFunc(party => { + const starter = party[0]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? + }), + [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)) + .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) + .setSpeciesFilter(species => species.baseTotal >= 540) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.RAYQUAZA], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 3); + p.pokeball = PokeballType.MASTER_BALL; + p.shiny = true; + p.variant = 1; + })) + .setGenModifiersFunc(party => { + const starter = party[0]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; //TODO: is the bang correct? + }), + [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); + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL], TrainerSlot.TRAINER, true, + p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) + .setSpeciesFilter(species => species.baseTotal >= 540) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.RAYQUAZA], TrainerSlot.TRAINER, true, p => { + p.setBoss(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + p.shiny = true; + p.variant = 1; + p.formIndex = 1; + p.generateName(); + })) + .setGenModifiersFunc(party => { + const starter = party[0]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? + }), + + [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") + .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; + p.generateName(); + })), + [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", [], true).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") + .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.HIPPOWDON])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.EXCADRILL])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.KANGASKHAN], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })) + .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", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .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; + p.generateName(); + })), + [TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SOLROCK, Species.TYPHLOSION], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.TORKOAL, Species.NINETALES], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // DROUGHT + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SHIFTRY, Species.SCOVILLAIN], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 0; // Chlorophyll + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GREAT_TUSK])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CAMERUPT], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GROUDON], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .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; + p.generateName(); + })), + [TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.EMPOLEON, Species.LUDICOLO], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.POLITOED, Species.PELIPPER], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // Drizzle + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.BEARTIC, Species.ARMALDO], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; // Swift Swim + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.OVERQWIL ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 1; // Swift Swim + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SHARPEDO], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYOGRE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", []).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ])) + .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; + p.generateName(); + })) + .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", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") + .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.HOUNDOOM], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.WEAVILE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DARKRAI], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", []).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") + .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", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GENESECT ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + p.formIndex = Utils.randSeedInt(5); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BASCULEGION, Species.JELLICENT ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; + p.formIndex = 1; + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.KINGAMBIT ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.VOLCARONA, Species.SLITHER_WING ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYUREM], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", []).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CLAWITZER, Species.DRAGALGE ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HELIOLISK, Species.MALAMAR ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })), + [TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") + .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.PYROAR ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.IRON_MOTH ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.YVELTAL], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.LUSAMINE]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", []).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.LILLIGANT, Species.HISUI_LILLIGANT ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.BEWEAR ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })), + [TrainerType.LUSAMINE_2]: new TrainerConfig(++t).setName("Lusamine").initForEvilTeamLeader("Aether Boss", [], true).setMixedBattleBgm("battle_aether_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLEFABLE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MILOTIC, Species.PRIMARINA ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PHEROMOSA ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.STAKATAKA, Species.CELESTEELA, Species.GUZZLORD ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.NIHILEGO ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.NECROZMA ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.GUZMA]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", []).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LOKIX, Species.YANMEGA ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HERACROSS ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALVANTULA, Species.VIKAVOLT])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PINSIR ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })), + [TrainerType.GUZMA_2]: new TrainerConfig(++t).setName("Guzma").initForEvilTeamLeader("Skull Boss", [], true).setMixedBattleBgm("battle_skull_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GOLISOPOD ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.abilityIndex = 2; //Anticipation + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HISUI_SAMUROTT, Species.CRAWDAUNT ], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 2; //Sharpness, Adaptability + })) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SCIZOR, Species.KLEAVOR ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.PINSIR ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.formIndex = 1; + p.generateName(); + })) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.BUZZWOLE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.XURKITREE ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })), + [TrainerType.ROSE]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", []).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.FERROTHORN, Species.ESCAVALIER ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SIRFETCHD, Species.MR_RIME ])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CORVIKNIGHT ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.PERRSERKER, Species.KLINKLANG ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.COPPERAJAH ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.formIndex = 1; + p.generateName(); + })), + [TrainerType.ROSE_2]: new TrainerConfig(++t).setName("Rose").initForEvilTeamLeader("Macro Boss", [], true).setMixedBattleBgm("battle_macro_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ARCHALUDON ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + })) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AEGISLASH, Species.GHOLDENGO ])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DRACOVISH, Species.DRACOZOLT ], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 1; //Strong Jaw, Hustle + })) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MELMETAL ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GALAR_ARTICUNO, Species.GALAR_ZAPDOS, Species.GALAR_MOLTRES ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.MASTER_BALL; + })) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.COPPERAJAH ], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.formIndex = 1; + p.generateName(); + })), +}; From f1111dc0d291b3861af770031bf0bcc377fa26da Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Fri, 30 Aug 2024 00:13:53 +0100 Subject: [PATCH 08/14] chore: Update AdminUiHandler to clear input fields and set mode to ADMIN --- src/ui/admin-ui-handler.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/admin-ui-handler.ts b/src/ui/admin-ui-handler.ts index 049e5b01cdf..0e5202fc1a8 100644 --- a/src/ui/admin-ui-handler.ts +++ b/src/ui/admin-ui-handler.ts @@ -66,11 +66,13 @@ export default class AdminUiHandler extends FormModalUiHandler { if (!response.ok) { console.error(response); } - this.scene.ui.revertMode(); + this.inputs[0].setText(""); + this.inputs[1].setText(""); + this.scene.ui.setMode(Mode.ADMIN); }) .catch((err) => { console.error(err); - this.scene.ui.revertMode(); + this.scene.ui.setMode(Mode.ADMIN); }); return false; }; From 7eb6ba4dfdf8b3c536685708f4b9f0618c33908f Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Fri, 30 Aug 2024 00:19:03 +0100 Subject: [PATCH 09/14] chore: Clear input fields and revert mode in AdminUiHandler --- src/ui/admin-ui-handler.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ui/admin-ui-handler.ts b/src/ui/admin-ui-handler.ts index 0e5202fc1a8..141a4893714 100644 --- a/src/ui/admin-ui-handler.ts +++ b/src/ui/admin-ui-handler.ts @@ -68,10 +68,12 @@ export default class AdminUiHandler extends FormModalUiHandler { } this.inputs[0].setText(""); this.inputs[1].setText(""); + this.scene.ui.revertMode(); this.scene.ui.setMode(Mode.ADMIN); }) .catch((err) => { console.error(err); + this.scene.ui.revertMode(); this.scene.ui.setMode(Mode.ADMIN); }); return false; From f7169868f3b015c8046c5f959e5a3df02f241068 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Fri, 30 Aug 2024 00:22:09 +0100 Subject: [PATCH 10/14] chore: Refactor AdminUiHandler to clear input fields and revert mode --- src/ui/admin-ui-handler.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ui/admin-ui-handler.ts b/src/ui/admin-ui-handler.ts index 141a4893714..5c91a36ab64 100644 --- a/src/ui/admin-ui-handler.ts +++ b/src/ui/admin-ui-handler.ts @@ -69,12 +69,10 @@ export default class AdminUiHandler extends FormModalUiHandler { this.inputs[0].setText(""); this.inputs[1].setText(""); this.scene.ui.revertMode(); - this.scene.ui.setMode(Mode.ADMIN); }) .catch((err) => { console.error(err); this.scene.ui.revertMode(); - this.scene.ui.setMode(Mode.ADMIN); }); return false; }; From d1132a57659b045b72381710457a093879fb41d1 Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:38:46 +1000 Subject: [PATCH 11/14] [QoL] Test dialogue menu option (#3725) * Adding code to allow use of a testing dialogue translation menu * Updated to include autocomplete functionality * Added multiple inputs * Added locales for other languages as well as checks to make this only available on local/beta * Updated a few things to try get the dialogue to work for full length of the window * Fixed issue with message box not taking up full length of the screen (thanks Moka!) and some minor bugs * Whoops, forgot to stage a file * Updated locale files * Fixed broken tests and docs * Removed keys from json * Reordered and reorganised some things * Put admin enum at end to match handlers * Removed old unneeded line of code * Updated to include the ability to handle cases where i18 keys are null in the locales json --- src/locales/en/menu-ui-handler.json | 4 +- src/ui/abstact-option-select-ui-handler.ts | 29 +++- src/ui/autocomplete-ui-handler.ts | 45 +++++++ src/ui/battle-message-ui-handler.ts | 10 +- src/ui/menu-ui-handler.ts | 113 +++++++++++++--- src/ui/test-dialogue-ui-handler.ts | 147 +++++++++++++++++++++ src/ui/ui.ts | 8 ++ 7 files changed, 332 insertions(+), 24 deletions(-) create mode 100644 src/ui/autocomplete-ui-handler.ts create mode 100644 src/ui/test-dialogue-ui-handler.ts diff --git a/src/locales/en/menu-ui-handler.json b/src/locales/en/menu-ui-handler.json index 8230a675b39..fccf9cd3002 100644 --- a/src/locales/en/menu-ui-handler.json +++ b/src/locales/en/menu-ui-handler.json @@ -14,8 +14,8 @@ "importSlotSelect": "Select a slot to import to.", "exportSession": "Export Session", "exportSlotSelect": "Select a slot to export from.", - "importRunHistory":"Import Run History", - "exportRunHistory":"Export Run History", + "importRunHistory": "Import Run History", + "exportRunHistory": "Export Run History", "importData": "Import Data", "exportData": "Export Data", "consentPreferences": "Consent Preferences", diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index 5172075da52..c6abecda4c0 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -77,7 +77,21 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { } protected setupOptions() { - const options = this.config?.options || []; + const configOptions = this.config?.options ?? []; + + let options: OptionSelectItem[]; + + // for performance reasons, this limits how many options we can see at once. Without this, it would try to make text options for every single options + // which makes the performance take a hit. If there's not enough options to do this (set to 10 at the moment) and the ui mode !== Mode.AUTO_COMPLETE, + // this is ignored and the original code is untouched, with the options array being all the options from the config + if (configOptions.length >= 10 && this.scene.ui.getMode() === Mode.AUTO_COMPLETE) { + const optionsScrollTotal = configOptions.length; + const optionStartIndex = this.scrollCursor; + const optionEndIndex = Math.min(optionsScrollTotal, optionStartIndex + (!optionStartIndex || this.scrollCursor + (this.config?.maxOptions! - 1) >= optionsScrollTotal ? this.config?.maxOptions! - 1 : this.config?.maxOptions! - 2)); + options = configOptions.slice(optionStartIndex, optionEndIndex + 2); + } else { + options = configOptions; + } if (this.optionSelectText) { this.optionSelectText.destroy(); @@ -192,6 +206,19 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { } else { ui.playError(); } + } else if (button === Button.SUBMIT && ui.getMode() === Mode.AUTO_COMPLETE) { + // this is here to differentiate between a Button.SUBMIT vs Button.ACTION within the autocomplete handler + // this is here because Button.ACTION is picked up as z on the keyboard, meaning if you're typing and hit z, it'll select the option you've chosen + success = true; + const option = this.config?.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))]; + if (option?.handler()) { + if (!option.keepOpen) { + this.clear(); + } + playSound = !option.overrideSound; + } else { + ui.playError(); + } } else { switch (button) { case Button.UP: diff --git a/src/ui/autocomplete-ui-handler.ts b/src/ui/autocomplete-ui-handler.ts new file mode 100644 index 00000000000..480a3cf72d0 --- /dev/null +++ b/src/ui/autocomplete-ui-handler.ts @@ -0,0 +1,45 @@ +import { Button } from "#enums/buttons"; +import BattleScene from "../battle-scene"; +import AbstractOptionSelectUiHandler from "./abstact-option-select-ui-handler"; +import { Mode } from "./ui"; + +export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler { + modalContainer: Phaser.GameObjects.Container; + constructor(scene: BattleScene, mode: Mode = Mode.OPTION_SELECT) { + super(scene, mode); + } + + getWindowWidth(): integer { + return 64; + } + + show(args: any[]): boolean { + if (args[0].modalContainer) { + const { modalContainer } = args[0]; + const show = super.show(args); + this.modalContainer = modalContainer; + this.setupOptions(); + + return show; + } + return false; + } + + protected setupOptions() { + super.setupOptions(); + if (this.modalContainer) { + this.optionSelectContainer.setSize(this.optionSelectContainer.height, Math.max(this.optionSelectText.displayWidth + 24, this.getWindowWidth())); + this.optionSelectContainer.setPositionRelative(this.modalContainer, this.optionSelectBg.width, this.optionSelectBg.height + 50); + } + } + + processInput(button: Button): boolean { + // the cancel and action button are here because if you're typing, x and z are used for cancel/action. This means you could be typing something and accidentally cancel/select when you don't mean to + // the submit button is therefore used to select a choice (the enter button), though this does not work on my local dev testing for phones, as for my phone/keyboard combo, the enter and z key are both + // bound to Button.ACTION, which makes this not work on mobile + if (button !== Button.CANCEL && button !== Button.ACTION) { + return super.processInput(button); + } + return false; + } +} diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 189305ce4c1..86f8d9e01a8 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -21,6 +21,8 @@ export default class BattleMessageUiHandler extends MessageUiHandler { public movesWindowContainer: Phaser.GameObjects.Container; public nameBoxContainer: Phaser.GameObjects.Container; + public readonly wordWrapWidth: number = 1780; + constructor(scene: BattleScene) { super(scene, Mode.MESSAGE); } @@ -63,7 +65,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { const message = addTextObject(this.scene, 0, 0, "", TextStyle.MESSAGE, { maxLines: 2, wordWrap: { - width: 1780 + width: this.wordWrapWidth } }); messageContainer.add(message); @@ -129,7 +131,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { this.commandWindow.setVisible(false); this.movesWindowContainer.setVisible(false); - this.message.setWordWrapWidth(1780); + this.message.setWordWrapWidth(this.wordWrapWidth); return true; } @@ -161,7 +163,9 @@ export default class BattleMessageUiHandler extends MessageUiHandler { } showDialogue(text: string, name?: string, delay?: integer | null, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { - name && this.showNameText(name); + if (name) { + this.showNameText(name); + } super.showDialogue(text, name, delay, callback, callbackDelay, prompt, promptDelay); } diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 0bbfe21e4f9..9e96eda9cc5 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -2,7 +2,7 @@ import BattleScene, { bypassLogin } from "../battle-scene"; import { TextStyle, addTextObject, getTextStyleOptions } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; -import { addWindow } from "./ui-theme"; +import { addWindow, WindowVariant } from "./ui-theme"; import MessageUiHandler from "./message-ui-handler"; import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler"; import { Tutorial, handleTutorial } from "../tutorial"; @@ -11,6 +11,7 @@ import i18next from "i18next"; import { Button } from "#enums/buttons"; import { GameDataType } from "#enums/game-data-type"; import BgmBar from "#app/ui/bgm-bar"; +import AwaitableUiHandler from "./awaitable-ui-handler"; enum MenuOptions { GAME_SETTINGS, @@ -31,6 +32,10 @@ const githubUrl = "https://github.com/pagefaultgames/pokerogue"; const redditUrl = "https://www.reddit.com/r/pokerogue"; export default class MenuUiHandler extends MessageUiHandler { + private readonly textPadding = 8; + private readonly defaultMessageBoxWidth = 220; + private readonly defaultWordWrapWidth = 1224; + private menuContainer: Phaser.GameObjects.Container; private menuMessageBoxContainer: Phaser.GameObjects.Container; private menuOverlay: Phaser.GameObjects.Rectangle; @@ -46,17 +51,20 @@ export default class MenuUiHandler extends MessageUiHandler { protected manageDataConfig: OptionSelectConfig; protected communityConfig: OptionSelectConfig; + // Windows for the default message box and the message box for testing dialogue + private menuMessageBox: Phaser.GameObjects.NineSlice; + private dialogueMessageBox: Phaser.GameObjects.NineSlice; + protected scale: number = 0.1666666667; public bgmBar: BgmBar; - constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.excludedMenus = () => [ - { condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, - { condition: bypassLogin, options: [ MenuOptions.LOG_OUT ] } + { condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, + { condition: bypassLogin, options: [MenuOptions.LOG_OUT] } ]; this.menuOptions = Utils.getEnumKeys(MenuOptions) @@ -98,8 +106,8 @@ export default class MenuUiHandler extends MessageUiHandler { render() { const ui = this.getUi(); this.excludedMenus = () => [ - { condition: ![Mode.COMMAND, Mode.TITLE].includes(ui.getModeChain()[0]), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, - { condition: bypassLogin, options: [ MenuOptions.LOG_OUT ] } + { condition: ![Mode.COMMAND, Mode.TITLE].includes(ui.getModeChain()[0]), options: [MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, + { condition: bypassLogin, options: [MenuOptions.LOG_OUT] } ]; this.menuOptions = Utils.getEnumKeys(MenuOptions) @@ -115,12 +123,12 @@ export default class MenuUiHandler extends MessageUiHandler { this.menuBg = addWindow(this.scene, (this.scene.game.canvas.width / 6) - (this.optionSelectText.displayWidth + 25), 0, - this.optionSelectText.displayWidth + 19+24*this.scale, + this.optionSelectText.displayWidth + 19 + 24 * this.scale, (this.scene.game.canvas.height / 6) - 2 ); this.menuBg.setOrigin(0, 0); - this.optionSelectText.setPositionRelative(this.menuBg, 10+24*this.scale, 6); + this.optionSelectText.setPositionRelative(this.menuBg, 10 + 24 * this.scale, 6); this.menuContainer.add(this.menuBg); @@ -131,20 +139,27 @@ export default class MenuUiHandler extends MessageUiHandler { this.menuMessageBoxContainer = this.scene.add.container(0, 130); this.menuMessageBoxContainer.setName("menu-message-box"); this.menuMessageBoxContainer.setVisible(false); - this.menuContainer.add(this.menuMessageBoxContainer); - const menuMessageBox = addWindow(this.scene, 0, -0, 220, 48); - menuMessageBox.setOrigin(0, 0); - this.menuMessageBoxContainer.add(menuMessageBox); + // Window for general messages + this.menuMessageBox = addWindow(this.scene, 0, 0, this.defaultMessageBoxWidth, 48); + this.menuMessageBox.setOrigin(0, 0); + this.menuMessageBoxContainer.add(this.menuMessageBox); - const menuMessageText = addTextObject(this.scene, 8, 8, "", TextStyle.WINDOW, { maxLines: 2 }); + // Full-width window used for testing dialog messages in debug mode + this.dialogueMessageBox = addWindow(this.scene, -this.textPadding, 0, this.scene.game.canvas.width / 6 + this.textPadding * 2, 49, false, false, 0, 0, WindowVariant.THIN); + this.dialogueMessageBox.setOrigin(0, 0); + this.menuMessageBoxContainer.add(this.dialogueMessageBox); + + const menuMessageText = addTextObject(this.scene, this.textPadding, this.textPadding, "", TextStyle.WINDOW, { maxLines: 2 }); menuMessageText.setName("menu-message"); - menuMessageText.setWordWrapWidth(1224); menuMessageText.setOrigin(0, 0); this.menuMessageBoxContainer.add(menuMessageText); this.message = menuMessageText; + // By default we use the general purpose message window + this.setDialogTestMode(false); + this.menuContainer.add(this.menuMessageBoxContainer); const manageDataOptions: any[] = []; // TODO: proper type @@ -155,7 +170,7 @@ export default class MenuUiHandler extends MessageUiHandler { const config: OptionSelectConfig = { options: new Array(5).fill(null).map((_, i) => i).filter(slotFilter).map(i => { return { - label: i18next.t("menuUiHandler:slot", {slotNumber: i+1}), + label: i18next.t("menuUiHandler:slot", { slotNumber: i + 1 }), handler: () => { callback(i); ui.revertMode(); @@ -257,8 +272,55 @@ export default class MenuUiHandler extends MessageUiHandler { return true; }, keepOpen: true - }, - { + }); + if (Utils.isLocal || Utils.isBeta) { // this should make sure we don't have this option in live + manageDataOptions.push({ + label: "Test Dialogue", + handler: () => { + ui.playSelect(); + const prefilledText = ""; + const buttonAction: any = {}; + buttonAction["buttonActions"] = [ + (sanitizedName: string) => { + ui.revertMode(); + ui.playSelect(); + const dialogueTestName = sanitizedName; + const dialogueName = decodeURIComponent(escape(atob(dialogueTestName))); + const handler = ui.getHandler() as AwaitableUiHandler; + handler.tutorialActive = true; + const interpolatorOptions: any = {}; + const splitArr = dialogueName.split(" "); // this splits our inputted text into words to cycle through later + const translatedString = splitArr[0]; // this is our outputted i18 string + const regex = RegExp("\\{\\{(\\w*)\\}\\}", "g"); // this is a regex expression to find all the text between {{ }} in the i18 output + const matches = i18next.t(translatedString).match(regex) ?? []; + if (matches.length > 0) { + for (let match = 0; match < matches.length; match++) { + // we add 1 here because splitArr[0] is our first value for the translatedString, and after that is where the variables are + // the regex here in the replace (/\W/g) is to remove the {{ and }} and just give us all alphanumeric characters + if (typeof splitArr[match + 1] !== "undefined") { + interpolatorOptions[matches[match].replace(/\W/g, "")] = i18next.t(splitArr[match + 1]); + } + } + } + // Switch to the dialog test window + this.setDialogTestMode(true); + ui.showText(String(i18next.t(translatedString, interpolatorOptions)), null, () => this.scene.ui.showText("", 0, () => { + handler.tutorialActive = false; + // Go back to the default message window + this.setDialogTestMode(false); + }), null, true); + }, + () => { + ui.revertMode(); + } + ]; + ui.setMode(Mode.TEST_DIALOGUE, buttonAction, prefilledText); + return true; + }, + keepOpen: true + }); + } + manageDataOptions.push({ label: i18next.t("menuUiHandler:cancel"), handler: () => { this.scene.ui.revertMode(); @@ -421,7 +483,7 @@ export default class MenuUiHandler extends MessageUiHandler { break; case MenuOptions.MANAGE_DATA: if (!bypassLogin && !this.manageDataConfig.options.some(o => o.label === i18next.t("menuUiHandler:linkDiscord") || o.label === i18next.t("menuUiHandler:unlinkDiscord"))) { - this.manageDataConfig.options.splice(this.manageDataConfig.options.length-1, 0, + this.manageDataConfig.options.splice(this.manageDataConfig.options.length - 1, 0, { label: loggedInUser?.discordId === "" ? i18next.t("menuUiHandler:linkDiscord") : i18next.t("menuUiHandler:unlinkDiscord"), handler: () => { @@ -547,6 +609,21 @@ export default class MenuUiHandler extends MessageUiHandler { return success || error; } + /** + * Switch the message window style and size when we are replaying dialog for debug purposes + * In "dialog test mode", the window takes the whole width of the screen and the text + * is set up to wrap around the same way as the dialogue during the game + * @param isDialogMode whether to use the dialog test + */ + setDialogTestMode(isDialogMode: boolean) { + this.menuMessageBox.setVisible(!isDialogMode); + this.dialogueMessageBox.setVisible(isDialogMode); + // If we're testing dialog, we use the same word wrapping as the battle message handler + this.message.setWordWrapWidth(isDialogMode ? this.scene.ui.getMessageHandler().wordWrapWidth : this.defaultWordWrapWidth); + this.message.setX(isDialogMode ? this.textPadding + 1 : this.textPadding); + this.message.setY(isDialogMode ? this.textPadding + 0.4 : this.textPadding); + } + showText(text: string, delay?: number, callback?: Function, callbackDelay?: number, prompt?: boolean, promptDelay?: number): void { this.menuMessageBoxContainer.setVisible(!!text); diff --git a/src/ui/test-dialogue-ui-handler.ts b/src/ui/test-dialogue-ui-handler.ts new file mode 100644 index 00000000000..3f353bbc461 --- /dev/null +++ b/src/ui/test-dialogue-ui-handler.ts @@ -0,0 +1,147 @@ +import { FormModalUiHandler } from "./form-modal-ui-handler"; +import { ModalConfig } from "./modal-ui-handler"; +import i18next from "i18next"; +import { PlayerPokemon } from "#app/field/pokemon"; +import { OptionSelectItem } from "./abstact-option-select-ui-handler"; +import { isNullOrUndefined } from "#app/utils"; +import { Mode } from "./ui"; + +export default class TestDialogueUiHandler extends FormModalUiHandler { + + keys: string[]; + + constructor(scene, mode) { + super(scene, mode); + } + + setup() { + super.setup(); + + const flattenKeys = (object, topKey?: string, midleKey?: string[]): Array => { + return Object.keys(object).map((t, i) => { + const value = Object.values(object)[i]; + + if (typeof value === "object" && !isNullOrUndefined(value)) { // we check for not null or undefined here because if the language json file has a null key, the typeof will still be an object, but that object will be null, causing issues + // If the value is an object, execute the same process + // si el valor es un objeto ejecuta el mismo proceso + + return flattenKeys(value, topKey ?? t, topKey ? midleKey ? [...midleKey, t] : [t] : undefined).filter((t) => t.length > 0); + } else if (typeof value === "string" || isNullOrUndefined(value)) { // we check for null or undefined here as per above - the typeof is still an object but the value is null so we need to exit out of this and pass the null key + + // Return in the format expected by i18next + return midleKey ? `${topKey}:${midleKey.map((m) => m).join(".")}.${t}` : `${topKey}:${t}`; + } + }).filter((t) => t); + }; + + const keysInArrays = flattenKeys(i18next.getDataByLanguage(String(i18next.resolvedLanguage))).filter((t) => t.length > 0); // Array of arrays + const keys = keysInArrays.flat(Infinity).map(String); // One array of string + this.keys = keys; + } + + getModalTitle(config?: ModalConfig): string { + return "Test Dialogue"; + } + + getFields(config?: ModalConfig): string[] { + return [ "Dialogue" ]; + } + + getWidth(config?: ModalConfig): number { + return 300; + } + + getMargin(config?: ModalConfig): [number, number, number, number] { + return [ 0, 0, 48, 0 ]; + } + + getButtonLabels(config?: ModalConfig): string[] { + return [ "Check", "Cancel" ]; + } + + getReadableErrorMessage(error: string): string { + const colonIndex = error?.indexOf(":"); + if (colonIndex > 0) { + error = error.slice(0, colonIndex); + } + + return super.getReadableErrorMessage(error); + } + + show(args: any[]): boolean { + const ui = this.getUi(); + const input = this.inputs[0]; + input.setMaxLength(255); + + input.on("keydown", (inputObject, evt: KeyboardEvent) => { + if (["escape", "space"].some((v) => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) && ui.getMode() === Mode.AUTO_COMPLETE) { + // Delete autocomplete list and recovery focus. + inputObject.on("blur", () => inputObject.node.focus(), { once: true }); + ui.revertMode(); + } + }); + + input.on("textchange", (inputObject, evt: InputEvent) => { + // Delete autocomplete. + if (ui.getMode() === Mode.AUTO_COMPLETE) { + ui.revertMode(); + } + + let options: OptionSelectItem[] = []; + const splitArr = inputObject.text.split(" "); + const filteredKeys = this.keys.filter((command) => command.toLowerCase().includes(splitArr[splitArr.length - 1].toLowerCase())); + if (inputObject.text !== "" && filteredKeys.length > 0) { + // if performance is required, you could reduce the number of total results by changing the slice below to not have all ~8000 inputs going + options = filteredKeys.slice(0).map((value) => { + return { + label: value, + handler: () => { + // this is here to make sure that if you try to backspace then enter, the last known evt.data (backspace) is picked up + // this is because evt.data is null for backspace, so without this, the autocomplete windows just closes + if (!isNullOrUndefined(evt.data) || evt.inputType?.toLowerCase() === "deletecontentbackward") { + const separatedArray = inputObject.text.split(" "); + separatedArray[separatedArray.length - 1] = value; + inputObject.setText(separatedArray.join(" ")); + } + ui.revertMode(); + return true; + } + }; + }); + } + + if (options.length > 0) { + const modalOpts = { + options: options, + maxOptions: 5, + modalContainer: this.modalContainer + }; + ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts); + } + + }); + + + if (super.show(args)) { + const config = args[0] as ModalConfig; + this.inputs[0].resize(1150, 116); + this.inputContainers[0].list[0].width = 200; + if (args[1] && typeof (args[1] as PlayerPokemon).getNameToRender === "function") { + this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender(); + } else { + this.inputs[0].text = args[1]; + } + this.submitAction = (_) => { + if (ui.getMode() === Mode.TEST_DIALOGUE) { + this.sanitizeInputs(); + const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text))); + config.buttonActions[0](sanitizedName); + return true; + } + return false; + }; + return true; + } + return false; + } +} diff --git a/src/ui/ui.ts b/src/ui/ui.ts index dc12ac92be2..282bbb227f6 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -49,6 +49,8 @@ import RenameFormUiHandler from "./rename-form-ui-handler"; import AdminUiHandler from "./admin-ui-handler"; import RunHistoryUiHandler from "./run-history-ui-handler"; import RunInfoUiHandler from "./run-info-ui-handler"; +import TestDialogueUiHandler from "#app/ui/test-dialogue-ui-handler"; +import AutoCompleteUiHandler from "./autocomplete-ui-handler"; export enum Mode { MESSAGE, @@ -89,6 +91,8 @@ export enum Mode { RENAME_POKEMON, RUN_HISTORY, RUN_INFO, + TEST_DIALOGUE, + AUTO_COMPLETE, ADMIN, } @@ -127,6 +131,8 @@ const noTransitionModes = [ Mode.UNAVAILABLE, Mode.OUTDATED, Mode.RENAME_POKEMON, + Mode.TEST_DIALOGUE, + Mode.AUTO_COMPLETE, Mode.ADMIN, ]; @@ -191,6 +197,8 @@ export default class UI extends Phaser.GameObjects.Container { new RenameFormUiHandler(scene), new RunHistoryUiHandler(scene), new RunInfoUiHandler(scene), + new TestDialogueUiHandler(scene, Mode.TEST_DIALOGUE), + new AutoCompleteUiHandler(scene), new AdminUiHandler(scene), ]; } From aeecb67f32cb1a78b01ad5acd30e22a902143bbe Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Thu, 29 Aug 2024 20:56:05 -0500 Subject: [PATCH 12/14] Add inverse "item" sprite Pull #3525 forgot to add this graphic into the items folder, which would mean the sprite would be lost if the items atlas was overwritten at any point. This shouldn't affect any existing functionality. --- public/images/items/inverse.png | Bin 0 -> 413 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/items/inverse.png diff --git a/public/images/items/inverse.png b/public/images/items/inverse.png new file mode 100644 index 0000000000000000000000000000000000000000..b1ad5d2c00ef54f1323d947921363faf1381aea3 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T3KmRl#X6Fc*eCO{UXElvc|L!;@BKeN zb(;_V7cW?lIcu9VU$9?z;=k7c zwzjKOs<(Em&~sovRka|c{rBq*&H}*${EIWc?fraQ+2Y}c%PAL+xn79od~v8+uz{Oz z|GDXFmDC(U%k?Ke+azsad5P&@h^*2K=C5bu;+&?gan65z^>veH&ojPj7EyZ}I$rRe zYt;_zVV-#E<=i*yUo_nxT72MKlfU;sYQ3jJ%#rQSpDjxAoAOIPT%=*E|G~X0rwIly zxh+^X@088&U-dDk8`;a}YfJC`e|ZToRQXaPJkxxA8MJ_G4j=}BOTm*tl&7no%Q~lo FCIDMrsfz#r literal 0 HcmV?d00001 From db4a63dbb9056a5e4e0f86e5a74601c5a05d539d Mon Sep 17 00:00:00 2001 From: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com> Date: Fri, 30 Aug 2024 03:15:35 -0400 Subject: [PATCH 13/14] [Sprite] Fix Courtney eye whites (#3907) --- public/images/trainer/courtney.png | Bin 1508 -> 888 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/trainer/courtney.png b/public/images/trainer/courtney.png index 991e7ac006f416414404789ac4e889141b058506..0efdb615fcd3e59dd53d370a6869be7b7d14a8e2 100644 GIT binary patch delta 876 zcmV-y1C#vZ3-|_*8Gi!+001!#Hzoi800DDSM?wIu&K&6g002c$OjJbx000mW5D*_C zH6k}i9t&X~A9pt%JU~QvNLXz~abIF(u}&<2bvL6uOSo`Y<7|7ruxFoaq}Zr{{OE}I z;JCz_#sB~Rsl@)80000NbW%=J0RR90|NsC0|NsC0|NsC0|9}7g|NsC0u#0ow0008M zNklvG~S3P7;cDIDgtY#1?5HS*HY=ZQF_hozDc*lu||187|)Elxj`qb4^6tHbo$pK2bS7 zCkBdCBO~Zzt?72VRZ>CG!CE^|Ze8n5MokR?%i{fO#haR{sP$HXoh$<+D#`plR%Rf) z5dMso!oj85!feG`yU^HSU5a8Bl$^I~k*WD%1287b&3|u_Kc!q5YTPr-90D-U8*4Vk zaxI!RW9E!ZSc+^Bm8Q!e5JeYaXp zjQJ@hc7KyiG=ak|;crZqcMio#FX$f_wpBCFOu#UQU(C_gYW4GIz0~UcmA>dhsGbT2rX6IxA~|50000P!Uj5;q zRS3%X&Y17;5I^OhYr%*@@{ne)Bhx%ZqqcS2DV;W%064x9j;04=!Xz4`F= zp?t(K05Xuje}BJr{D2}*#RsdamDX#ZTi;zBgTm=YJ6}{z7bD+YMIV~GZoqsyM&Ccywuafq?X>(dOAp3P= z3R#z%IoFb$=lz{?;^K~E`cLL<0P(j0vaMT*lOr7Ug z&nNY#tU&Yu1_xB~sxX?NfEggFOlNs02KDmu%f*YLgaMF54QTh%%@LGWY1*xCKhnDz~G-j_EF&jzI`%>t4Q$Uxq|@?r7jxqo*`!zpVs1Bht@zyOhVW(CO(WKL6? zDIjY2oTE_l!ejw5XUuU0B1u|1j>mFN6J@dh5n2X8xB;W#1ym}CtU#z^PBTKqpvXBX zVUhybsDy(+c_3z_xnLRtY2j#jgP|56h4j@x?|{fDBte{ysf02%0xD!`n7M(>8O`h- zhJS15OTcig{Q$iK(nMGlLO`i9sF@3DE*PH(HN(fQweZt|vo}BrRu7e7 zMeT)==_xL;!KuN-P*d|zb(UoMpfgF-@P8pTDMZLagxxGqJ}kLU<32PPgt0y{ZAA=> z7N^rfQH|^WaF50_*5{U%=9By>5d9~n67BSzNia!(=IW5c+cEw2qaco|;!HDuQD_bQ zBq291P;4gZ3sc?4!jYmk$)J!D$b)EMs;{PeC^jixlLN&Dju?wvdpGu~%3Yc1pkgMkgz;c)+6dCoq|)`l`x ztcFN(U08)SPOpbyMIE-j`mZ0cKY!fcPyets)M1K%Qp|&bQ)wX-GIjj+%KGWiv8t3} zB+L$U^`E73fAHXb`19y~8G3AX{Oa~@d7Lc#a)+Ev2XubKEY-i+;cubgySY|IIbGGR zdTF8)yxs%p?35S#EVE##-gUQL%f0c^@@RkX3`o~}CZrYVPW~tT5rjS+FL&s~cNveu&DHXx= ziz*$mRUvXu>J{;1FqTX7V^{q~)WZOjB9UeVs`{!o29u-zB<(}D9v+MxU;g=KxPEl> zzw78b$wxP~9DOKAiKE{qkXCo}OUJr(+Rj2wp>S6Fl7^YCO0d+~Yaps=6soGGxi%$C zav%>C`-s+G*LxtG^;UIF@@MA&>e4!Q-~{LdXu<7Yis85r0ur9m00000NkvXXu0mjf DcoNja From 60aa61e56e06ff263b2d7a718be31001efde607c Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Fri, 30 Aug 2024 02:16:15 -0700 Subject: [PATCH 14/14] [Bug] Skip Eternatus dialogue again (#3716) * The fix. * Ordinals.... * tsdocs.. * my forgetting * Fixed issues * Update src/phases/encounter-phase.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * The actual change * actual fixes --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/locales/en/dialogue-final-boss.json | 6 ++- src/phases/encounter-phase.ts | 69 +++++++++++++------------ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/locales/en/dialogue-final-boss.json b/src/locales/en/dialogue-final-boss.json index 48a5aa439f3..3abe4cd8831 100644 --- a/src/locales/en/dialogue-final-boss.json +++ b/src/locales/en/dialogue-final-boss.json @@ -2,5 +2,9 @@ "encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.", "encounter_female": null, "firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.", - "secondStageWin": "…Magnificent." + "secondStageWin": "…Magnificent.", + "key_ordinal_one": "st", + "key_ordinal_two": "nd", + "key_ordinal_few": "rd", + "key_ordinal_other": "th" } \ No newline at end of file diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 9d74063627a..07bfd72a8bf 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -1,23 +1,23 @@ -import BattleScene from "#app/battle-scene.js"; -import { BattleType, BattlerIndex } from "#app/battle.js"; -import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability.js"; -import { getCharVariantFromDialogue } from "#app/data/dialogue.js"; -import { TrainerSlot } from "#app/data/trainer-config.js"; -import { getRandomWeatherType } from "#app/data/weather.js"; -import { BattleSpec } from "#app/enums/battle-spec.js"; -import { PlayerGender } from "#app/enums/player-gender.js"; -import { Species } from "#app/enums/species.js"; -import { EncounterPhaseEvent } from "#app/events/battle-scene.js"; -import Pokemon, { FieldPosition } from "#app/field/pokemon.js"; -import { getPokemonNameWithAffix } from "#app/messages.js"; -import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type.js"; -import { IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier.js"; -import { achvs } from "#app/system/achv.js"; -import { handleTutorial, Tutorial } from "#app/tutorial.js"; -import { Mode } from "#app/ui/ui.js"; +import BattleScene from "#app/battle-scene"; +import { BattleType, BattlerIndex } from "#app/battle"; +import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability"; +import { getCharVariantFromDialogue } from "#app/data/dialogue"; +import { TrainerSlot } from "#app/data/trainer-config"; +import { getRandomWeatherType } from "#app/data/weather"; +import { BattleSpec } from "#app/enums/battle-spec"; +import { PlayerGender } from "#app/enums/player-gender"; +import { Species } from "#app/enums/species"; +import { EncounterPhaseEvent } from "#app/events/battle-scene"; +import Pokemon, { FieldPosition } from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type"; +import { IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier"; +import { achvs } from "#app/system/achv"; +import { handleTutorial, Tutorial } from "#app/tutorial"; +import { Mode } from "#app/ui/ui"; import i18next from "i18next"; import { BattlePhase } from "./battle-phase"; -import * as Utils from "#app/utils.js"; +import * as Utils from "#app/utils"; import { CheckSwitchPhase } from "./check-switch-phase"; import { GameOverPhase } from "./game-over-phase"; import { PostSummonPhase } from "./post-summon-phase"; @@ -358,24 +358,29 @@ export class EncounterPhase extends BattlePhase { case BattleSpec.FINAL_BOSS: const enemy = this.scene.getEnemyPokemon(); this.scene.ui.showText(this.getEncounterMessage(), null, () => { - const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; - //The two lines below check if English ordinals (1st, 2nd, 3rd, Xth) are used and determine which one to use. - //Otherwise, it defaults to an empty string. - //As of 08-07-24: Spanish and Italian default to the English translations - const ordinalUse = ["en", "es", "it"]; - const currentLanguage = i18next.resolvedLanguage ?? "en"; - const ordinalIndex = (ordinalUse.includes(currentLanguage)) ? ["st", "nd", "rd"][((count + 90) % 100 - 10) % 10 - 1] ?? "th" : ""; - const cycleCount = count.toLocaleString() + ordinalIndex; - const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET; - const genderStr = PlayerGender[genderIndex].toLowerCase(); - const encounterDialogue = i18next.t("battleSpecDialogue:encounter", { context: genderStr, cycleCount: cycleCount }); - this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => { + const localizationKey = "battleSpecDialogue:encounter"; + if (this.scene.ui.shouldSkipDialogue(localizationKey)) { + // Logging mirrors logging found in dialogue-ui-handler + console.log(`Dialogue ${localizationKey} skipped`); this.doEncounterCommon(false); - }); + } else { + const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; + // The line below checks if an English ordinal is necessary or not based on whether an entry for encounterLocalizationKey exists in the language or not. + const ordinalUsed = !i18next.exists(localizationKey, {fallbackLng: []}) || i18next.resolvedLanguage === "en" ? i18next.t("battleSpecDialogue:key", { count: count, ordinal: true }) : ""; + const cycleCount = count.toLocaleString() + ordinalUsed; + const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET; + const genderStr = PlayerGender[genderIndex].toLowerCase(); + const encounterDialogue = i18next.t(localizationKey, { context: genderStr, cycleCount: cycleCount }); + if (!this.scene.gameData.getSeenDialogues()[localizationKey]) { + this.scene.gameData.saveSeenDialogue(localizationKey); + } + this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => { + this.doEncounterCommon(false); + }); + } }, 1500, true); return true; } - return false; } }