From 65294f408e1c8b26e13fa7ff01d6f42039ed0cfa Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sat, 19 Apr 2025 10:04:19 -0500 Subject: [PATCH 1/6] [Bug][UI/UX] Fix type hint after enemy disappears (#5677) * Fix type hint after enemy disappears * Add automated test for type hint bugfix * Make onField default to true * Replace reference to Mode with UiMode and battleType with BattleStyle --- src/data/moves/move.ts | 4 ++-- src/data/terrain.ts | 2 +- src/field/pokemon.ts | 9 +++++++-- src/phases/move-phase.ts | 2 +- test/ui/type-hints.test.ts | 41 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 513ab3f6a74..26654fee18f 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -8183,7 +8183,7 @@ export type MoveTargetSet = { export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveTarget): MoveTargetSet { const variableTarget = new NumberHolder(0); - user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); + user.getOpponents(false).forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); let moveTarget: MoveTarget | undefined; if (allMoves[move].hasAttr(VariableTargetAttr)) { @@ -8195,7 +8195,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT } else if (move === undefined) { moveTarget = MoveTarget.NEAR_ENEMY; } - const opponents = user.getOpponents(); + const opponents = user.getOpponents(false); let set: Pokemon[] = []; let multiple = false; diff --git a/src/data/terrain.ts b/src/data/terrain.ts index 894fb8a7955..5b6063cee68 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -59,7 +59,7 @@ export class Terrain { // Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain return ( move.getPriority(user) > 0 && - user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) + user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) ); } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 0242820dcde..f2e5fd4c2b6 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3852,12 +3852,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return null; } - getOpponents(): Pokemon[] { + /** + * Returns the pokemon that oppose this one and are active + * + * @param onField - whether to also check if the pokemon is currently on the field (defaults to true) + */ + getOpponents(onField = true): Pokemon[] { return ( (this.isPlayer() ? globalScene.getEnemyField() : globalScene.getPlayerField()) as Pokemon[] - ).filter(p => p.isActive()); + ).filter(p => p.isActive(onField)); } getOpponentDescriptor(): string { diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index f42a2aefa34..7d2848a5d70 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -654,7 +654,7 @@ export class MovePhase extends BattlePhase { }), 500, ); - applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents()[0], this.move.getMove()); + applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents(false)[0], this.move.getMove()); } public showFailedText(failedText: string = i18next.t("battle:attackFailed")): void { diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index 08d9806ec7f..2051af76754 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -40,7 +40,7 @@ describe("UI - Type Hints", () => { .moveset([Moves.DRAGON_CLAW]); game.settings.typeHints(true); //activate type hints - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; @@ -65,7 +65,7 @@ describe("UI - Type Hints", () => { it("check status move color", async () => { game.override.enemySpecies(Species.FLORGES).moveset([Moves.GROWL]); - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; @@ -86,4 +86,41 @@ describe("UI - Type Hints", () => { }); await game.phaseInterceptor.to(CommandPhase); }); + + it("should show the proper hint for a move in doubles after one of the enemy pokemon flees", async () => { + game.override + .enemySpecies(Species.ABRA) + .moveset([Moves.SPLASH, Moves.SHADOW_BALL, Moves.SOAK]) + .enemyMoveset([Moves.SPLASH, Moves.TELEPORT]) + .battleStyle("double"); + + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + game.move.select(Moves.SPLASH); + // Use soak to change type of remaining abra to water + game.move.select(Moves.SOAK, 1); + + await game.forceEnemyMove(Moves.SPLASH); + await game.forceEnemyMove(Moves.TELEPORT); + await game.toNextTurn(); + + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const shadowBallText = movesContainer + .getAll() + .find(text => text.text === i18next.t("move:shadowBall.name"))! as unknown as MockText; + expect.soft(shadowBallText).toBeDefined(); + + expect.soft(shadowBallText.color).toBe(undefined); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); }); From bda286cebb7285400925c5eefa3b3f4811549cda Mon Sep 17 00:00:00 2001 From: Chris <75648912+ChrisLolz@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:00:12 -0400 Subject: [PATCH 2/6] [Bug] Fix Login Screen Buttons can be Pressed While Animating (#5170) * destroy containers when processing external containers * make form buttons uninteractible until tweens finished instead * fix holding enter spam * fix conflicts --- src/ui/form-modal-ui-handler.ts | 2 +- src/ui/login-form-ui-handler.ts | 132 +++++++++++++------------ src/ui/modal-ui-handler.ts | 6 +- src/ui/registration-form-ui-handler.ts | 86 ++++++++-------- 4 files changed, 120 insertions(+), 106 deletions(-) diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index e8e67d591d5..8c30b4e0bc4 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -124,7 +124,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { if (this.buttonBgs.length) { this.buttonBgs[0].off("pointerdown"); this.buttonBgs[0].on("pointerdown", () => { - if (this.submitAction) { + if (this.submitAction && globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { this.submitAction(); } }); diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/login-form-ui-handler.ts index 2dfab9c0c40..714a9b39771 100644 --- a/src/ui/login-form-ui-handler.ts +++ b/src/ui/login-form-ui-handler.ts @@ -40,25 +40,9 @@ export default class LoginFormUiHandler extends FormModalUiHandler { setup(): void { super.setup(); + this.buildExternalPartyContainer(); - - this.infoContainer = globalScene.add.container(0, 0); - - this.usernameInfoImage = this.buildInteractableImage("settings_icon", "username-info-icon", { - x: 20, - scale: 0.5, - }); - - this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", { - x: 0, - scale: 0.75, - }); - - this.infoContainer.add(this.usernameInfoImage); - this.infoContainer.add(this.saveDownloadImage); - this.getUi().add(this.infoContainer); - this.infoContainer.setVisible(false); - this.infoContainer.disableInteractive(); + this.buildInfoContainer(); } private buildExternalPartyContainer() { @@ -84,6 +68,26 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.externalPartyContainer.setVisible(false); } + private buildInfoContainer() { + this.infoContainer = globalScene.add.container(0, 0); + + this.usernameInfoImage = this.buildInteractableImage("settings_icon", "username-info-icon", { + x: 20, + scale: 0.5, + }); + + this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", { + x: 0, + scale: 0.75, + }); + + this.infoContainer.add(this.usernameInfoImage); + this.infoContainer.add(this.saveDownloadImage); + this.getUi().add(this.infoContainer); + this.infoContainer.setVisible(false); + this.infoContainer.disableInteractive(); + } + override getModalTitle(_config?: ModalConfig): string { let key = "menu:login"; if (import.meta.env.VITE_SERVER_URL === "https://apibeta.pokerogue.net") { @@ -143,27 +147,29 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.processExternalProvider(config); const originalLoginAction = this.submitAction; this.submitAction = _ => { - // Prevent overlapping overrides on action modification - this.submitAction = originalLoginAction; - this.sanitizeInputs(); + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + // Prevent overlapping overrides on action modification + this.submitAction = originalLoginAction; + this.sanitizeInputs(); globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); - const onFail = error => { + const onFail = error => { globalScene.ui.setMode(UiMode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() })); - globalScene.ui.playError(); - }; - if (!this.inputs[0].text) { - return onFail(i18next.t("menu:emptyUsername")); - } - - const [usernameInput, passwordInput] = this.inputs; - - pokerogueApi.account.login({ username: usernameInput.text, password: passwordInput.text }).then(error => { - if (!error && originalLoginAction) { - originalLoginAction(); - } else { - onFail(error); + globalScene.ui.playError(); + }; + if (!this.inputs[0].text) { + return onFail(i18next.t("menu:emptyUsername")); } - }); + + const [usernameInput, passwordInput] = this.inputs; + + pokerogueApi.account.login({ username: usernameInput.text, password: passwordInput.text }).then(error => { + if (!error && originalLoginAction) { + originalLoginAction(); + } else { + onFail(error); + } + }); + } }; return true; @@ -221,34 +227,36 @@ export default class LoginFormUiHandler extends FormModalUiHandler { }; this.usernameInfoImage.on("pointerdown", () => { - const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage - const keyToFind = "data_"; - const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0); - if (dataKeys.length > 0 && dataKeys.length <= 2) { - const options: OptionSelectItem[] = []; - for (let i = 0; i < dataKeys.length; i++) { - options.push({ - label: dataKeys[i].replace(keyToFind, ""), - handler: () => { - globalScene.ui.revertMode(); - this.infoContainer.disableInteractive(); - return true; - }, - }); - } + if (globalScene.tweens.getTweensOf(this.infoContainer).length === 0) { + const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage + const keyToFind = "data_"; + const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0); + if (dataKeys.length > 0 && dataKeys.length <= 2) { + const options: OptionSelectItem[] = []; + for (let i = 0; i < dataKeys.length; i++) { + options.push({ + label: dataKeys[i].replace(keyToFind, ""), + handler: () => { + globalScene.ui.revertMode(); + this.infoContainer.disableInteractive(); + return true; + }, + }); + } globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { - options: options, - delay: 1000, - }); - this.infoContainer.setInteractive( - new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width, globalScene.game.canvas.height), - Phaser.Geom.Rectangle.Contains, - ); - } else { - if (dataKeys.length > 2) { - return onFail(this.ERR_TOO_MANY_SAVES); + options: options, + delay: 1000, + }); + this.infoContainer.setInteractive( + new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width, globalScene.game.canvas.height), + Phaser.Geom.Rectangle.Contains, + ); + } else { + if (dataKeys.length > 2) { + return onFail(this.ERR_TOO_MANY_SAVES); + } + return onFail(this.ERR_NO_SAVES); } - return onFail(this.ERR_NO_SAVES); } }); diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index a3b94296d3f..56c1c2c3fcf 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -134,7 +134,11 @@ export abstract class ModalUiHandler extends UiHandler { for (let a = 0; a < this.buttonBgs.length; a++) { if (a < this.buttonBgs.length) { - this.buttonBgs[a].on("pointerdown", _ => config.buttonActions[a]()); + this.buttonBgs[a].on("pointerdown", _ => { + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + config.buttonActions[a](); + } + }); } } diff --git a/src/ui/registration-form-ui-handler.ts b/src/ui/registration-form-ui-handler.ts index bb10efc5869..3d4613c21d6 100644 --- a/src/ui/registration-form-ui-handler.ts +++ b/src/ui/registration-form-ui-handler.ts @@ -98,51 +98,53 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler { const originalRegistrationAction = this.submitAction; this.submitAction = _ => { - // Prevent overlapping overrides on action modification - this.submitAction = originalRegistrationAction; - this.sanitizeInputs(); + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + // Prevent overlapping overrides on action modification + this.submitAction = originalRegistrationAction; + this.sanitizeInputs(); globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); - const onFail = error => { + const onFail = error => { globalScene.ui.setMode(UiMode.REGISTRATION_FORM, Object.assign(config, { errorMessage: error?.trim() })); - globalScene.ui.playError(); - const errorMessageFontSize = languageSettings[i18next.resolvedLanguage!]?.errorMessageFontSize; - if (errorMessageFontSize) { - this.errorMessage.setFontSize(errorMessageFontSize); - } - }; - if (!this.inputs[0].text) { - return onFail(i18next.t("menu:emptyUsername")); - } - if (!this.inputs[1].text) { - return onFail(this.getReadableErrorMessage("invalid password")); - } - if (this.inputs[1].text !== this.inputs[2].text) { - return onFail(i18next.t("menu:passwordNotMatchingConfirmPassword")); - } - const [usernameInput, passwordInput] = this.inputs; - pokerogueApi.account - .register({ - username: usernameInput.text, - password: passwordInput.text, - }) - .then(registerError => { - if (!registerError) { - pokerogueApi.account - .login({ - username: usernameInput.text, - password: passwordInput.text, - }) - .then(loginError => { - if (!loginError) { - originalRegistrationAction?.(); - } else { - onFail(loginError); - } - }); - } else { - onFail(registerError); + globalScene.ui.playError(); + const errorMessageFontSize = languageSettings[i18next.resolvedLanguage!]?.errorMessageFontSize; + if (errorMessageFontSize) { + this.errorMessage.setFontSize(errorMessageFontSize); } - }); + }; + if (!this.inputs[0].text) { + return onFail(i18next.t("menu:emptyUsername")); + } + if (!this.inputs[1].text) { + return onFail(this.getReadableErrorMessage("invalid password")); + } + if (this.inputs[1].text !== this.inputs[2].text) { + return onFail(i18next.t("menu:passwordNotMatchingConfirmPassword")); + } + const [usernameInput, passwordInput] = this.inputs; + pokerogueApi.account + .register({ + username: usernameInput.text, + password: passwordInput.text, + }) + .then(registerError => { + if (!registerError) { + pokerogueApi.account + .login({ + username: usernameInput.text, + password: passwordInput.text, + }) + .then(loginError => { + if (!loginError) { + originalRegistrationAction?.(); + } else { + onFail(loginError); + } + }); + } else { + onFail(registerError); + } + }); + } }; return true; From 8515cadd7735c0046a9185dec936f208f07c2281 Mon Sep 17 00:00:00 2001 From: Blitzy <118096277+Blitz425@users.noreply.github.com> Date: Sun, 20 Apr 2025 00:20:07 -0500 Subject: [PATCH 3/6] [Balance] Update Gym Leader Teams and Teras (#5670) * Update Gym Leader Teams * Set Tera slots for Gym Leaders * Change Giovanni's Specialty Type to Ground --- Co-authored-by: damocleas --- src/data/balance/signature-species.ts | 134 +++++++++++++------------- src/data/trainers/trainer-config.ts | 132 ++++++++++++------------- 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/src/data/balance/signature-species.ts b/src/data/balance/signature-species.ts index a1b73af40cd..e2fecaa12ff 100644 --- a/src/data/balance/signature-species.ts +++ b/src/data/balance/signature-species.ts @@ -11,87 +11,87 @@ export type SignatureSpecies = { */ export const signatureSpecies: SignatureSpecies = { // Gym Leaders- Kanto - BROCK: [Species.GEODUDE, Species.ONIX], - MISTY: [Species.STARYU, Species.PSYDUCK], - LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ], + BROCK: [Species.ONIX, Species.GEODUDE, [Species.OMANYTE, Species.KABUTO], Species.AERODACTYL], + MISTY: [Species.STARYU, Species.PSYDUCK, Species.WOOPER, Species.LAPRAS], + LT_SURGE: [Species.PICHU, Species.VOLTORB, Species.ELEKID, Species.JOLTEON], 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], + JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT, Species.KOFFING], + SABRINA: [Species.ABRA, Species.MR_MIME, Species.SMOOCHUM, Species.ESPEON], + BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGBY, Species.VULPIX], + GIOVANNI: [Species.RHYHORN, Species.MEOWTH, [Species.NIDORAN_F, Species.NIDORAN_M], Species.DIGLETT], // Tera Ground Meowth // Gym Leaders- Johto - FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO], - BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR], - WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG], - 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], + FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.NATU, Species.MURKROW], + BUGSY: [Species.SCYTHER, Species.SHUCKLE, Species.YANMA, [Species.PINSIR, Species.HERACROSS]], + WHITNEY: [Species.MILTANK, Species.AIPOM, Species.IGGLYBUFF, [Species.GIRAFARIG, Species.STANTLER]], + MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.DUSKULL, Species.SABLEYE], + CHUCK: [Species.POLIWRATH, Species.MANKEY, Species.TYROGUE, Species.MACHOP], + JASMINE: [Species.STEELIX, Species.MAGNEMITE, Species.PINECO, Species.SKARMORY], + PRYCE: [Species.SWINUB, Species.SEEL, Species.SHELLDER, Species.SNEASEL], + CLAIR: [Species.HORSEA, Species.DRATINI, Species.MAGIKARP, Species.DRUDDIGON], // Tera Dragon Magikarp // Gym Leaders- Hoenn - 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.ZIGZAGOON, Species.KECLEON], + ROXANNE: [Species.NOSEPASS, Species.GEODUDE, [Species.LILEEP, Species.ANORITH], Species.ARON], + BRAWLY: [Species.MAKUHITA, Species.MACHOP, Species.MEDITITE, Species.SHROOMISH], + WATTSON: [Species.ELECTRIKE, Species.VOLTORB, Species.MAGNEMITE, [Species.PLUSLE, Species.MINUN]], + FLANNERY: [Species.TORKOAL, Species.SLUGMA, Species.NUMEL, Species.HOUNDOUR], + NORMAN: [Species.SLAKOTH, Species.KECLEON, Species.WHISMUR, Species.ZANGOOSE], 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], + TATE: [Species.SOLROCK, Species.NATU, Species.CHINGLING, Species.GALLADE], + LIZA: [Species.LUNATONE, Species.BALTOY, Species.SPOINK, Species.GARDEVOIR], + JUAN: [Species.HORSEA, Species.SPHEAL, Species.BARBOACH, Species.CORPHISH], // Gym Leaders- Sinnoh - ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE], - GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG], - MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR], + ROARK: [Species.CRANIDOS, Species.GEODUDE, Species.NOSEPASS, Species.LARVITAR], + GARDENIA: [Species.BUDEW, Species.CHERUBI, Species.TURTWIG, Species.LEAFEON], + MAYLENE: [Species.RIOLU, Species.MEDITITE, Species.CHIMCHAR, Species.CROAGUNK], CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP], - 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], + FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.DUSKULL, Species.SPIRITOMB], + BYRON: [Species.SHIELDON, Species.BRONZOR, Species.ARON, Species.SKARMORY], + CANDICE: [Species.FROSLASS, Species.SNOVER, Species.SNEASEL, Species.GLACEON], + VOLKNER: [Species.ELEKID, Species.SHINX, Species.CHINCHOU, Species.ROTOM], // Gym Leaders- Unova - CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL], - CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL], - CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE], - CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE], - LENORA: [Species.PATRAT, 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], + CILAN: [Species.PANSAGE, Species.SNIVY, Species.MARACTUS, Species.FERROSEED], + CHILI: [Species.PANSEAR, Species.TEPIG, Species.HEATMOR, Species.DARUMAKA], + CRESS: [Species.PANPOUR, Species.OSHAWOTT, Species.BASCULIN, Species.TYMPOLE], + CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE, Species.BOUFFALANT], + LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO, Species.BRAVIARY], + ROXIE: [Species.VENIPEDE, Species.KOFFING, Species.TRUBBISH, Species.TOXEL], + BURGH: [Species.SEWADDLE, Species.DWEBBLE, [Species.KARRABLAST, Species.SHELMET], Species.DURANT], + ELESA: [Species.BLITZLE, Species.EMOLGA, Species.JOLTIK, Species.TYNAMO], + CLAY: [Species.DRILBUR, Species.SANDILE, Species.TYMPOLE, Species.GOLETT], + SKYLA: [Species.DUCKLETT, Species.WOOBAT, [Species.RUFFLET, Species.VULLABY], Species.ARCHEN], + BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO, Species.GALAR_DARUMAKA], + DRAYDEN: [Species.AXEW, Species.DRUDDIGON, Species.TRAPINCH, Species.DEINO], + MARLON: [Species.FRILLISH, Species.TIRTOUGA, Species.WAILMER, Species.MANTYKE], // Gym Leaders- Kalos - 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], + VIOLA: [Species.SCATTERBUG, Species.SURSKIT, Species.CUTIEFLY, Species.BLIPBUG], + GRANT: [Species.TYRUNT, Species.AMAURA, Species.BINACLE, Species.DWEBBLE], + KORRINA: [Species.RIOLU, Species.MIENFOO, Species.HAWLUCHA, Species.PANCHAM], + RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT, [Species.PHANTUMP, Species.PUMPKABOO]], + CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.DEDENNE, Species.ROTOM], + VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME, [Species.SPRITZEE, Species.SWIRLIX]], + OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.INKAY, Species.SLOWKING], + WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL, Species.SWINUB], // Gym Leaders- Galar - 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], + MILO: [Species.GOSSIFLEUR, Species.SEEDOT, Species.APPLIN, Species.LOTAD], + NESSA: [Species.CHEWTLE, Species.WIMPOD, Species.ARROKUDA, Species.MAREANIE], + KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.GROWLITHE, Species.TORKOAL], + BEA: [Species.MACHOP, Species.GALAR_FARFETCHD, Species.CLOBBOPUS, Species.FALINKS], + ALLISTER: [Species.GASTLY, Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.SINISTEA], + OPAL: [Species.MILCERY, Species.GALAR_WEEZING, Species.TOGEPI, Species.MAWILE], + BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR, Species.SYLVEON], + GORDIE: [Species.ROLYCOLY, [Species.SHUCKLE, Species.BINACLE], Species.STONJOURNER, Species.LARVITAR], + MELONY: [Species.LAPRAS, Species.SNOM, Species.EISCUE, [Species.GALAR_MR_MIME, Species.GALAR_DARUMAKA]], + PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.TOXEL, Species.INKAY], // Tera Dark Toxel + MARNIE: [Species.IMPIDIMP, Species.MORPEKO, Species.PURRLOIN, Species.CROAGUNK], // Tera Dark Croagunk + RAIHAN: [Species.DURALUDON, Species.TRAPINCH, Species.GOOMY, Species.TURTONATOR], // Gym Leaders- Paldea; First slot is Tera - KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa - BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo - IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus + KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA, Species.RELLOR], // Tera Bug Teddiursa + BRASSIUS: [Species.BONSLY, Species.SMOLIV, Species.BRAMBLIN, Species.SUNKERN], // Tera Grass Bonsly + IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL, Species.MAGNEMITE], // Tera Ghost Misdreavus KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe - GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu + GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.SNOM, Species.CUBCHOO], // Tera Ice Swablu // Elite Four- Kanto LORELEI: [ diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index fec1d4757e7..a2e62e6761b 100644 --- a/src/data/trainers/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -2579,252 +2579,252 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)) - .initForGymLeader(signatureSpecies["BROCK"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["BROCK"], true, PokemonType.ROCK, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.MISTY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MISTY"], false, PokemonType.WATER) + .initForGymLeader(signatureSpecies["MISTY"], false, PokemonType.WATER, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.LT_SURGE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["LT_SURGE"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["LT_SURGE"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.ERIKA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ERIKA"], false, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["ERIKA"], false, PokemonType.GRASS, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.JANINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["JANINE"], false, PokemonType.POISON) + .initForGymLeader(signatureSpecies["JANINE"], false, PokemonType.POISON, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.SABRINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["SABRINA"], false, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["SABRINA"], false, PokemonType.PSYCHIC, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.BLAINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BLAINE"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["BLAINE"], true, PokemonType.FIRE, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.GIOVANNI]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GIOVANNI"], true, PokemonType.DARK) + .initForGymLeader(signatureSpecies["GIOVANNI"], true, PokemonType.GROUND, false, -2) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.FALKNER]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FALKNER"], true, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["FALKNER"], true, PokemonType.FLYING, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.BUGSY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BUGSY"], true, PokemonType.BUG) + .initForGymLeader(signatureSpecies["BUGSY"], true, PokemonType.BUG, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.WHITNEY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WHITNEY"], false, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["WHITNEY"], false, PokemonType.NORMAL, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.MORTY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MORTY"], true, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["MORTY"], true, PokemonType.GHOST, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.CHUCK]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHUCK"], true, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["CHUCK"], true, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.JASMINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["JASMINE"], false, PokemonType.STEEL) + .initForGymLeader(signatureSpecies["JASMINE"], false, PokemonType.STEEL, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.PRYCE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["PRYCE"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["PRYCE"], true, PokemonType.ICE, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.CLAIR]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLAIR"], false, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["CLAIR"], false, PokemonType.DRAGON, false, -3) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.ROXANNE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROXANNE"], false, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["ROXANNE"], false, PokemonType.ROCK, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.BRAWLY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BRAWLY"], true, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["BRAWLY"], true, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.WATTSON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WATTSON"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["WATTSON"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.FLANNERY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FLANNERY"], false, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["FLANNERY"], false, PokemonType.FIRE, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.NORMAN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["NORMAN"], true, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["NORMAN"], true, PokemonType.NORMAL, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.WINONA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WINONA"], false, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["WINONA"], false, PokemonType.FLYING, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.TATE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["TATE"], true, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["TATE"], true, PokemonType.PSYCHIC, false, -1) .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, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["LIZA"], false, PokemonType.PSYCHIC, false, -1) .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, PokemonType.WATER) + .initForGymLeader(signatureSpecies["JUAN"], true, PokemonType.WATER, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.ROARK]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROARK"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["ROARK"], true, PokemonType.ROCK, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.GARDENIA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GARDENIA"], false, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["GARDENIA"], false, PokemonType.GRASS, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.MAYLENE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MAYLENE"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["MAYLENE"], false, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CRASHER_WAKE"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["CRASHER_WAKE"], true, PokemonType.WATER, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.FANTINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FANTINA"], false, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["FANTINA"], false, PokemonType.GHOST, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.BYRON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BYRON"], true, PokemonType.STEEL) + .initForGymLeader(signatureSpecies["BYRON"], true, PokemonType.STEEL, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CANDICE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CANDICE"], false, PokemonType.ICE) + .initForGymLeader(signatureSpecies["CANDICE"], false, PokemonType.ICE, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.VOLKNER]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VOLKNER"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["VOLKNER"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CILAN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CILAN"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["CILAN"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CHILI]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHILI"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["CHILI"], true, PokemonType.FIRE, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CRESS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CRESS"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["CRESS"], true, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CHEREN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHEREN"], true, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["CHEREN"], true, PokemonType.NORMAL, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.LENORA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["LENORA"], false, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["LENORA"], false, PokemonType.NORMAL, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.ROXIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROXIE"], false, PokemonType.POISON) + .initForGymLeader(signatureSpecies["ROXIE"], false, PokemonType.POISON, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.BURGH]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BURGH"], true, PokemonType.BUG) + .initForGymLeader(signatureSpecies["BURGH"], true, PokemonType.BUG, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.ELESA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ELESA"], false, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["ELESA"], false, PokemonType.ELECTRIC, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CLAY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLAY"], true, PokemonType.GROUND) + .initForGymLeader(signatureSpecies["CLAY"], true, PokemonType.GROUND, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.SKYLA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["SKYLA"], false, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["SKYLA"], false, PokemonType.FLYING, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.BRYCEN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BRYCEN"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["BRYCEN"], true, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.DRAYDEN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["DRAYDEN"], true, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["DRAYDEN"], true, PokemonType.DRAGON, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.MARLON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MARLON"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["MARLON"], true, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.VIOLA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VIOLA"], false, PokemonType.BUG) + .initForGymLeader(signatureSpecies["VIOLA"], false, PokemonType.BUG, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.GRANT]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GRANT"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["GRANT"], true, PokemonType.ROCK, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.KORRINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["KORRINA"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["KORRINA"], false, PokemonType.FIGHTING, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.RAMOS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["RAMOS"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["RAMOS"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.CLEMONT]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLEMONT"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["CLEMONT"], true, PokemonType.ELECTRIC, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.VALERIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VALERIE"], false, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["VALERIE"], false, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.OLYMPIA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["OLYMPIA"], false, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["OLYMPIA"], false, PokemonType.PSYCHIC, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.WULFRIC]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WULFRIC"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["WULFRIC"], true, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.MILO]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MILO"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["MILO"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.NESSA]: new TrainerConfig(++t) .setName("Nessa") - .initForGymLeader(signatureSpecies["NESSA"], false, PokemonType.WATER) + .initForGymLeader(signatureSpecies["NESSA"], false, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.KABU]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["KABU"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["KABU"], true, PokemonType.FIRE, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.BEA]: new TrainerConfig(++t) .setName("Bea") - .initForGymLeader(signatureSpecies["BEA"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["BEA"], false, PokemonType.FIGHTING, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.ALLISTER]: new TrainerConfig(++t) .setName("Allister") - .initForGymLeader(signatureSpecies["ALLISTER"], true, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["ALLISTER"], true, PokemonType.GHOST, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.OPAL]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["OPAL"], false, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["OPAL"], false, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.BEDE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BEDE"], true, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["BEDE"], true, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.GORDIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GORDIE"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["GORDIE"], true, PokemonType.ROCK, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.MELONY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MELONY"], false, PokemonType.ICE) + .initForGymLeader(signatureSpecies["MELONY"], false, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.PIERS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["PIERS"], true, PokemonType.DARK) + .initForGymLeader(signatureSpecies["PIERS"], true, PokemonType.DARK, false, -3) .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, PokemonType.DARK) + .initForGymLeader(signatureSpecies["MARNIE"], false, PokemonType.DARK, false, -4) .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, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["RAIHAN"], true, PokemonType.DRAGON, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.KATY]: new TrainerConfig(++t) .initForGymLeader(signatureSpecies["KATY"], false, PokemonType.BUG, true, -1) From 2cf0b51299ef78f1313410441d1ffd6458552813 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Sun, 20 Apr 2025 11:14:19 -0700 Subject: [PATCH 4/6] [Bug] Properly handle suppression with Illusion (#5671) * Remove extra attributes on neutralizing gas * Add IllusionBreakAbAttr to applyOnLose * Add test case --- src/data/abilities/ability.ts | 45 ++++++++++++++++++--------------- test/abilities/illusion.test.ts | 14 ++++++++++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 55a1a4eb902..27c3cb69073 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -2219,18 +2219,6 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr { } } -/** - * Removes illusions when a Pokemon is summoned. - */ -export class PostSummonRemoveIllusionAbAttr extends PostSummonAbAttr { - applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - for (const pokemon of globalScene.getField(true)) { - pokemon.breakIllusion(); - } - return true; - } -} - export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr { //Attr doesn't force pokemon name on the message private message: string; @@ -5177,7 +5165,14 @@ export class IllusionPreSummonAbAttr extends PreSummonAbAttr { } } -export class IllusionBreakAbAttr extends PostDefendAbAttr { +export class IllusionBreakAbAttr extends AbAttr { + override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void { + pokemon.breakIllusion(); + pokemon.summonData.illusionBroken = true; + } +} + +export class PostDefendIllusionBreakAbAttr extends PostDefendAbAttr { /** * Destroy the illusion upon taking damage * @@ -6269,7 +6264,7 @@ export function applyOnGainAbAttrs( } /** - * Clears primal weather/neutralizing gas during the turn if {@linkcode pokemon}'s ability corresponds to one + * Applies ability attributes which activate when the ability is lost or suppressed (i.e. primal weather) */ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated = false, ...args: any[]): void { applySingleAbAttrs( @@ -6281,6 +6276,17 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated args, true, simulated); + + applySingleAbAttrs( + pokemon, + passive, + IllusionBreakAbAttr, + (attr, passive) => attr.apply(pokemon, passive, simulated, null, args), + (attr, passive) => attr.canApply(pokemon, passive, simulated, args), + args, + true, + simulated + ) } /** @@ -6780,11 +6786,12 @@ export function initAbilities() { return isNullOrUndefined(movePhase); }, 1.3), new Ability(Abilities.ILLUSION, 5) - //The pokemon generate an illusion if it's available + // The Pokemon generate an illusion if it's available .attr(IllusionPreSummonAbAttr, false) - //The pokemon loses his illusion when he is damaged by a move - .attr(IllusionBreakAbAttr, true) - //Illusion is available again after a battle + .attr(IllusionBreakAbAttr) + // The Pokemon loses its illusion when damaged by a move + .attr(PostDefendIllusionBreakAbAttr, true) + // Illusion is available again after a battle .conditionalAttr((pokemon) => pokemon.isAllowedInBattle(), IllusionPostBattleAbAttr, false) .uncopiable() .bypassFaint(), @@ -7198,8 +7205,6 @@ export function initAbilities() { .attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr) .uncopiable() .attr(NoTransformAbilityAbAttr) - .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonNeutralizingGas", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) - .attr(PostSummonRemoveIllusionAbAttr) .bypassFaint(), new Ability(Abilities.PASTEL_VEIL, 8) .attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) diff --git a/test/abilities/illusion.test.ts b/test/abilities/illusion.test.ts index 382d7d74a08..b7c116a1b67 100644 --- a/test/abilities/illusion.test.ts +++ b/test/abilities/illusion.test.ts @@ -142,4 +142,18 @@ describe("Abilities - Illusion", () => { expect(zoroark.isShiny(true)).equals(true); expect(zoroark.getPokeball(true)).equals(PokeballType.GREAT_BALL); }); + + it("breaks when suppressed", async () => { + game.override.moveset(Moves.GASTRO_ACID); + await game.classicMode.startBattle([Species.MAGIKARP]); + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zorua.summonData?.illusion).toBe(true); + + game.move.select(Moves.GASTRO_ACID); + await game.phaseInterceptor.to(BerryPhase); + + expect(zorua.isFullHp()).toBe(true); + expect(!!zorua.summonData?.illusion).toBe(false); + }); }); From d0be6a9274862456ca806e0869833a45d9fe21b6 Mon Sep 17 00:00:00 2001 From: zaccie Date: Mon, 21 Apr 2025 06:33:17 +1200 Subject: [PATCH 5/6] [Bug] Fix order of operations when displaying enemy Boss level (#5685) * order of operations in creating boss battleInfo fixed a bug where because of an order of operations error in this file it ignored the position update of the boss life value set in battle-info.ts (around line 562) --- src/field/pokemon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f2e5fd4c2b6..6356f723a79 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -7162,8 +7162,8 @@ export class EnemyPokemon extends Pokemon { initBattleInfo(): void { if (!this.battleInfo) { this.battleInfo = new EnemyBattleInfo(); - this.battleInfo.updateBossSegments(this); this.battleInfo.initInfo(this); + this.battleInfo.updateBossSegments(this); } else { this.battleInfo.updateBossSegments(this); } From b89b945b11ce8891b28f595cc7ab70266e08cb37 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 20 Apr 2025 11:51:06 -0700 Subject: [PATCH 6/6] [Dev] Fix imports in `overrides.ts` and `illusion.test.ts` (#5686) --- src/overrides.ts | 8 ++++---- test/abilities/illusion.test.ts | 26 ++++++++++++-------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/overrides.ts b/src/overrides.ts index d36cfbfac98..7e6a46f2f85 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -2,10 +2,11 @@ import { type PokeballCounts } from "#app/battle-scene"; import { EvolutionItem } from "#app/data/balance/pokemon-evolutions"; import { Gender } from "#app/data/gender"; import { FormChangeItem } from "#app/data/pokemon-forms"; -import { Variant } from "#app/sprites/variant"; import { type ModifierOverride } from "#app/modifier/modifier-type"; +import { Variant } from "#app/sprites/variant"; import { Unlockables } from "#app/system/unlockables"; import { Abilities } from "#enums/abilities"; +import { BattleType } from "#enums/battle-type"; import { BerryType } from "#enums/berry-type"; import { Biome } from "#enums/biome"; import { EggTier } from "#enums/egg-type"; @@ -15,13 +16,12 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PokeballType } from "#enums/pokeball"; import { PokemonType } from "#enums/pokemon-type"; import { Species } from "#enums/species"; -import { BATTLE_STATS, Stat } from "#enums/stat"; +import { Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { TimeOfDay } from "#enums/time-of-day"; +import { TrainerType } from "#enums/trainer-type"; import { VariantTier } from "#enums/variant-tier"; import { WeatherType } from "#enums/weather-type"; -import { TrainerType } from "#enums/trainer-type"; -import { BattleType } from "#enums/battle-type"; /** * This comment block exists to prevent IDEs from automatically removing unused imports diff --git a/test/abilities/illusion.test.ts b/test/abilities/illusion.test.ts index b7c116a1b67..c743a59ef00 100644 --- a/test/abilities/illusion.test.ts +++ b/test/abilities/illusion.test.ts @@ -1,13 +1,11 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/testUtils/gameManager"; -import { Species } from "#enums/species"; -import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { Moves } from "#enums/moves"; -import { Abilities } from "#enums/abilities"; -import { PokeballType } from "#app/enums/pokeball"; import { Gender } from "#app/data/gender"; -import { BerryPhase } from "#app/phases/berry-phase"; +import { PokeballType } from "#app/enums/pokeball"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Abilities - Illusion", () => { let phaserGame: Phaser.Game; @@ -48,7 +46,7 @@ describe("Abilities - Illusion", () => { await game.classicMode.startBattle([Species.AXEW]); game.move.select(Moves.TACKLE); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); const zorua = game.scene.getEnemyPokemon()!; @@ -60,7 +58,7 @@ describe("Abilities - Illusion", () => { await game.classicMode.startBattle([Species.AXEW]); game.move.select(Moves.WORRY_SEED); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); const zorua = game.scene.getEnemyPokemon()!; @@ -114,7 +112,7 @@ describe("Abilities - Illusion", () => { game.move.select(Moves.FLARE_BLITZ); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); const zoroark = game.scene.getPlayerPokemon()!; @@ -132,7 +130,7 @@ describe("Abilities - Illusion", () => { game.doSwitchPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); const zoroark = game.scene.getPlayerPokemon()!; @@ -151,7 +149,7 @@ describe("Abilities - Illusion", () => { expect(!!zorua.summonData?.illusion).toBe(true); game.move.select(Moves.GASTRO_ACID); - await game.phaseInterceptor.to(BerryPhase); + await game.phaseInterceptor.to("BerryPhase"); expect(zorua.isFullHp()).toBe(true); expect(!!zorua.summonData?.illusion).toBe(false);