From d9288a7908c2fa9ae65f17b9a54573d4c48cab6e Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:19:37 -0700 Subject: [PATCH 01/14] [Bug] Add Neutralizing Gas Message for each user (#5527) Add message to onOverlap Co-authored-by: damocleas --- src/data/arena-tag.ts | 23 +++++++++++++++-------- src/field/arena.ts | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 276cfa035b8..6e8339dd54c 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -64,7 +64,7 @@ export abstract class ArenaTag { } } - onOverlap(_arena: Arena): void {} + onOverlap(_arena: Arena, _source: Pokemon | null): void {} lapse(_arena: Arena): boolean { return this.turnCount < 1 || !!--this.turnCount; @@ -706,7 +706,7 @@ export class ArenaTrapTag extends ArenaTag { this.maxLayers = maxLayers; } - onOverlap(arena: Arena): void { + onOverlap(arena: Arena, _source: Pokemon | null): void { if (this.layers < this.maxLayers) { this.layers++; @@ -1427,11 +1427,7 @@ export class SuppressAbilitiesTag extends ArenaTag { public override onAdd(_arena: Arena): void { const pokemon = this.getSourcePokemon(); if (pokemon) { - globalScene.queueMessage( - i18next.t("arenaTag:neutralizingGasOnAdd", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - }), - ); + this.playActivationMessage(pokemon); for (const fieldPokemon of globalScene.getField(true)) { if (fieldPokemon && fieldPokemon.id !== pokemon.id) { @@ -1441,8 +1437,9 @@ export class SuppressAbilitiesTag extends ArenaTag { } } - public override onOverlap(_arena: Arena): void { + public override onOverlap(_arena: Arena, source: Pokemon | null): void { this.sourceCount++; + this.playActivationMessage(source); } public onSourceLeave(arena: Arena): void { @@ -1481,6 +1478,16 @@ export class SuppressAbilitiesTag extends ArenaTag { public isBeingRemoved() { return this.beingRemoved; } + + private playActivationMessage(pokemon: Pokemon | null) { + if (pokemon) { + globalScene.queueMessage( + i18next.t("arenaTag:neutralizingGasOnAdd", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), + }), + ); + } + } } // TODO: swap `sourceMove` and `sourceId` and make `sourceMove` an optional parameter diff --git a/src/field/arena.ts b/src/field/arena.ts index 997b80b3237..2c538de890f 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -673,7 +673,7 @@ export class Arena { ): boolean { const existingTag = this.getTagOnSide(tagType, side); if (existingTag) { - existingTag.onOverlap(this); + existingTag.onOverlap(this, globalScene.getPokemonById(sourceId)); if (existingTag instanceof ArenaTrapTag) { const { tagType, side, turnCount, layers, maxLayers } = existingTag as ArenaTrapTag; From 3b99d3aea211e3421f4cbf99271f190c95815b52 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:52:49 -0700 Subject: [PATCH 02/14] [Misc] Add `* -crlf` to `.gitattributes` (#5539) --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index dfe0770424b..a6bfb838587 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ # Auto detect text files and perform LF normalization * text=auto +* -crlf From b1d494eadbf057da6e11bdb330a462935f321e12 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Wed, 19 Mar 2025 04:22:52 +0100 Subject: [PATCH 03/14] [UI/UX] [Bug] Icons for egg moves and passives show up even when not unlocked (#5540) Reworked icons to more compact code --- src/ui/pokedex-ui-handler.ts | 50 +++++++++++++++--------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index f4cb9f51c16..f3625f64476 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -1742,36 +1742,26 @@ export default class PokedexUiHandler extends MessageUiHandler { container.icon.setTint(0); } - if (data.eggMove1) { - container.eggMove1Icon.setVisible(true); - } else { - container.eggMove1Icon.setVisible(false); - } - if (data.eggMove2) { - container.eggMove2Icon.setVisible(true); - } else { - container.eggMove2Icon.setVisible(false); - } - if (data.tmMove1) { - container.tmMove1Icon.setVisible(true); - } else { - container.tmMove1Icon.setVisible(false); - } - if (data.tmMove2) { - container.tmMove2Icon.setVisible(true); - } else { - container.tmMove2Icon.setVisible(false); - } - if (data.passive1) { - container.passive1Icon.setVisible(true); - } else { - container.passive1Icon.setVisible(false); - } - if (data.passive2) { - container.passive2Icon.setVisible(true); - } else { - container.passive2Icon.setVisible(false); - } + const pairs: [boolean | undefined, Phaser.GameObjects.Image][] = [ + [data.eggMove1, container.eggMove1Icon], + [data.eggMove2, container.eggMove2Icon], + [data.tmMove1, container.tmMove1Icon], + [data.tmMove2, container.tmMove2Icon], + [data.passive1, container.passive1Icon], + [data.passive2, container.passive2Icon], + ]; + + pairs.forEach(([unlocked, icon]) => { + if (unlocked) { + icon.setVisible(true); + icon.clearTint(); + } else if (unlocked === false) { + icon.setVisible(true); + icon.setTint(0x808080); + } else { + icon.setVisible(false); + } + }); if (this.showDecorations) { if (this.pokerusSpecies.includes(data.species)) { From b2848af8990da1b4d5d8ee45736a3c8fc6a6a88a Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 18 Mar 2025 21:00:46 -0700 Subject: [PATCH 04/14] [Test] Add ability overrides to Tailwind tests (#5541) --- test/moves/tailwind.test.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/test/moves/tailwind.test.ts b/test/moves/tailwind.test.ts index 24a7fa25061..591b94408ce 100644 --- a/test/moves/tailwind.test.ts +++ b/test/moves/tailwind.test.ts @@ -1,9 +1,9 @@ -import { Stat } from "#enums/stat"; import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagType } from "#app/enums/arena-tag-type"; -import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -24,13 +24,16 @@ describe("Moves - Tailwind", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); - game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]); - game.override.enemyMoveset(Moves.SPLASH); + game.override + .battleType("double") + .moveset([Moves.TAILWIND, Moves.SPLASH]) + .enemyMoveset(Moves.SPLASH) + .enemyAbility(Abilities.BALL_FETCH) + .ability(Abilities.BALL_FETCH); }); it("doubles the Speed stat of the Pokemons on its side", async () => { - await game.startBattle([Species.MAGIKARP, Species.MEOWTH]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MEOWTH]); const magikarp = game.scene.getPlayerField()[0]; const meowth = game.scene.getPlayerField()[1]; @@ -43,7 +46,7 @@ describe("Moves - Tailwind", () => { game.move.select(Moves.TAILWIND); game.move.select(Moves.SPLASH, 1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); expect(magikarp.getEffectiveStat(Stat.SPD)).toBe(magikarpSpd * 2); expect(meowth.getEffectiveStat(Stat.SPD)).toBe(meowthSpd * 2); @@ -53,7 +56,7 @@ describe("Moves - Tailwind", () => { it("lasts for 4 turns", async () => { game.override.battleType("single"); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); game.move.select(Moves.TAILWIND); await game.toNextTurn(); @@ -76,7 +79,7 @@ describe("Moves - Tailwind", () => { it("does not affect the opposing side", async () => { game.override.battleType("single"); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const ally = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; @@ -91,7 +94,7 @@ describe("Moves - Tailwind", () => { game.move.select(Moves.TAILWIND); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); expect(ally.getEffectiveStat(Stat.SPD)).toBe(allySpd * 2); expect(enemy.getEffectiveStat(Stat.SPD)).equal(enemySpd); From a1a6b0dd5a66e9323289f20aeb0c49da1d375b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilde=20Sim=C3=B5es?= Date: Wed, 19 Mar 2025 22:01:33 +0000 Subject: [PATCH 05/14] [Bug] Nicknames not properly sanitized (#5537) * Fix #5082: Nicknames not properly sanitized When a player changes the name of the pokemon to one that uses one of the following combination of letters: "@c{}", "@s{}", "@d{}", "@f{}" and "$" the game shows the name of the pokemon incorrectly in a battle. Changes made: - on message-ui-handler.ts file I updated the "showTextInternal" function to get the original name of the pokemon or pokemons (in case it's a double battle) saving it in a list named "pokename" and change it in the text for their correspondent placeholder which is saved in the list "repname" (e.g "#POKEMON1" for the first pokemon and "#POKEMON2" for the second pokemon). After the text is properly modified because of the special characters ("@c{}", "@s{}", "@d{}", "@f{}") the name of the pokemons is replaced to it's original value. - on message-phase.ts file I updated the "start" function to use a similar approach but only change the pokemon name to it's original form after the "pageIndex" (which checks the index of the "$") is updated, so the text is cut properly. - on ui.ts file I updated the "showtext" function to use same approach of the previous files, ensuring that the pokemon names were only replaced back to their original values after all text processing on "$" was completed. * Replace `let` with `const` --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/phases/message-phase.ts | 31 +++++++++++++++++++++---------- src/ui/message-ui-handler.ts | 9 +++++++++ src/ui/ui.ts | 11 +++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/phases/message-phase.ts b/src/phases/message-phase.ts index f671307d86a..2a5bcf6b99c 100644 --- a/src/phases/message-phase.ts +++ b/src/phases/message-phase.ts @@ -28,17 +28,28 @@ export class MessagePhase extends Phase { super.start(); if (this.text.indexOf("$") > -1) { + const pokename: string[] = []; + const repname = [ "#POKEMON1", "#POKEMON2" ]; + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + pokename.push(globalScene.getPlayerField()[p].getNameToRender()); + this.text = this.text.split(pokename[p]).join(repname[p]); + } const pageIndex = this.text.indexOf("$"); - globalScene.unshiftPhase( - new MessagePhase( - this.text.slice(pageIndex + 1), - this.callbackDelay, - this.prompt, - this.promptDelay, - this.speaker, - ), - ); - this.text = this.text.slice(0, pageIndex).trim(); + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + this.text = this.text.split(repname[p]).join(pokename[p]); + } + if (pageIndex !== -1) { + globalScene.unshiftPhase( + new MessagePhase( + this.text.slice(pageIndex + 1), + this.callbackDelay, + this.prompt, + this.promptDelay, + this.speaker, + ), + ); + this.text = this.text.slice(0, pageIndex).trim(); + } } if (this.speaker) { diff --git a/src/ui/message-ui-handler.ts b/src/ui/message-ui-handler.ts index 50522152021..230b951de59 100644 --- a/src/ui/message-ui-handler.ts +++ b/src/ui/message-ui-handler.ts @@ -76,6 +76,12 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { const fadeMap = new Map(); const actionPattern = /@(c|d|s|f)\{(.*?)\}/; let actionMatch: RegExpExecArray | null; + const pokename: string[] = []; + const repname = [ "#POKEMON1", "#POKEMON2" ]; + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + pokename.push(globalScene.getPlayerField()[p].getNameToRender()); + text = text.split(pokename[p]).join(repname[p]); + } while ((actionMatch = actionPattern.exec(text))) { switch (actionMatch[1]) { case "c": @@ -94,6 +100,9 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4); } + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + text = text.split(repname[p]).join(pokename[p]); + } if (text) { // Predetermine overflow line breaks to avoid words breaking while displaying const textWords = text.split(" "); diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 7c202e9210d..026e42ccf46 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -328,17 +328,28 @@ export default class UI extends Phaser.GameObjects.Container { prompt?: boolean | null, promptDelay?: number | null, ): void { + const pokename: string[] = []; + const repname = [ "#POKEMON1", "#POKEMON2" ]; + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + pokename.push(globalScene.getPlayerField()[p].getNameToRender()); + text = text.split(pokename[p]).join(repname[p]); + } if (prompt && text.indexOf("$") > -1) { const messagePages = text.split(/\$/g).map(m => m.trim()); // biome-ignore lint/complexity/useOptionalChain: optional chain would change this to be null instead of undefined. let showMessageAndCallback = () => callback && callback(); for (let p = messagePages.length - 1; p >= 0; p--) { const originalFunc = showMessageAndCallback; + messagePages[p] = messagePages[p].split(repname[0]).join(pokename[0]); + messagePages[p] = messagePages[p].split(repname[1]).join(pokename[1]); showMessageAndCallback = () => this.showText(messagePages[p], null, originalFunc, null, true); } showMessageAndCallback(); } else { const handler = this.getHandler(); + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + text = text.split(repname[p]).join(pokename[p]); + } if (handler instanceof MessageUiHandler) { (handler as MessageUiHandler).showText(text, delay, callback, callbackDelay, prompt, promptDelay); } else { From 3f887988a6126d96e3624c3dcd34884746c04e6e Mon Sep 17 00:00:00 2001 From: Matheus Rabello Noya Alves Date: Wed, 19 Mar 2025 22:45:41 +0000 Subject: [PATCH 06/14] [Bug] [UI/UX] Smack Down and Thousand Arrows now display a message for Grounding (#5536) Fix #5027: Missing confirmation message for moves special effects When using the moves Thousand Arrows and Smack Down, though the special effect of grounding the opponent is applied, a confirming message was not displayed. In this fix a new AddBattlerTagAttr subclass has been created to handle the message display, compared to previous multiple attribute additions. This new subclass verifies the conditions for the message to be displayed through asserting if target is grounded and accesses a new locale message created to display if necessary. --- src/data/moves/move.ts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index f2157ab65b7..3d80b6b3f4c 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -5542,6 +5542,31 @@ export class LeechSeedAttr extends AddBattlerTagAttr { } } +/** + * Adds the appropriate battler tag for Smack Down and Thousand arrows + * @extends AddBattlerTagAttr + */ +export class FallDownAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true); + } + + /** + * Adds Grounded Tag to the target and checks if fallDown message should be displayed + * @param user the {@linkcode Pokemon} using the move + * @param target the {@linkcode Pokemon} targeted by the move + * @param move the {@linkcode Move} invoking this effect + * @param args n/a + * @returns `true` if the effect successfully applies; `false` otherwise + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!target.isGrounded()) { + globalScene.queueMessage(i18next.t("moveTriggers:fallDown", { targetPokemonName: getPokemonNameWithAffix(target) })); + } + return super.apply(user, target, move, args); + } +} + /** * Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used. * @extends MoveEffectAttr @@ -9646,7 +9671,7 @@ export function initMoves() { .target(MoveTarget.BOTH_SIDES) .unimplemented(), new AttackMove(Moves.SMACK_DOWN, PokemonType.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5) - .attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true) + .attr(FallDownAttr) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ]) .attr(HitsTagAttr, BattlerTagType.FLYING) @@ -10097,7 +10122,7 @@ export function initMoves() { .triageMove(), new AttackMove(Moves.THOUSAND_ARROWS, PokemonType.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6) .attr(NeutralDamageAgainstFlyingTypeMultiplierAttr) - .attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true) + .attr(FallDownAttr) .attr(HitsTagAttr, BattlerTagType.FLYING) .attr(HitsTagAttr, BattlerTagType.FLOATING) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) From 585f040057d0eef323918bb28b46981252da9aa4 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Wed, 19 Mar 2025 16:25:14 -0700 Subject: [PATCH 07/14] [Test] Fix Chilly Reception Test Ability Overrides (#5543) * Fix ability overrides * Remove extraneous resets --- test/moves/chilly_reception.test.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/moves/chilly_reception.test.ts b/test/moves/chilly_reception.test.ts index f90aaf6bb02..39342a921b6 100644 --- a/test/moves/chilly_reception.test.ts +++ b/test/moves/chilly_reception.test.ts @@ -27,8 +27,8 @@ describe("Moves - Chilly Reception", () => { .battleType("single") .moveset([Moves.CHILLY_RECEPTION, Moves.SNOWSCAPE]) .enemyMoveset(Array(4).fill(Moves.SPLASH)) - .enemyAbility(Abilities.NONE) - .ability(Abilities.NONE); + .enemyAbility(Abilities.BALL_FETCH) + .ability(Abilities.BALL_FETCH); }); it("should still change the weather if user can't switch out", async () => { @@ -72,7 +72,6 @@ describe("Moves - Chilly Reception", () => { game.override .battleType("single") .enemyMoveset([Moves.CHILLY_RECEPTION, Moves.TACKLE]) - .enemyAbility(Abilities.NONE) .moveset(Array(4).fill(Moves.SPLASH)); await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]); @@ -89,7 +88,6 @@ describe("Moves - Chilly Reception", () => { .battleType("single") .startingWave(8) .enemyMoveset(Array(4).fill(Moves.CHILLY_RECEPTION)) - .enemyAbility(Abilities.NONE) .enemySpecies(Species.MAGIKARP) .moveset([Moves.SPLASH, Moves.THUNDERBOLT]); From b3c7300c37ce0b7a13e54e12abe3df91f28f936c Mon Sep 17 00:00:00 2001 From: Unicorn_Power <189861924+Unicornpowerstar@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:15:12 +0100 Subject: [PATCH 08/14] [Sprite] Fixing the naming issue in exp-sprite.json +Disabling few problematic exp's (#5526) * fixing the naming in exp-sprite.json * Did the same thing to 931 * Undo for 3 pokemons due to exp animation quality. * Corrected the Indicator for the exp being disabled * Charcadet line exp disable --- public/exp-sprites.json | 256 ++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 127 deletions(-) diff --git a/public/exp-sprites.json b/public/exp-sprites.json index 50e10a8822d..c83fb910010 100644 --- a/public/exp-sprites.json +++ b/public/exp-sprites.json @@ -13,10 +13,10 @@ "1005", "1006", "1006", - "1007-apex", - "1007-apex", - "1008-ultimate", - "1008-ultimate", + "1007-apex-build-Disabled", + "1007-apex-build-Disabled", + "1008-ultimate-mode-Disabled", + "1008-ultimate-mode-Disabled", "115-mega", "115-mega", "127-mega", @@ -185,9 +185,9 @@ "531-mega", "569-gigantamax", "569-gigantamax", - "6-mega", - "6-mega", "6-mega-x", + "6-mega-x", + "6-mega-y", "6-mega-y", "6058", "6058", @@ -825,8 +825,8 @@ "873", "874", "874", - "875-no", - "875-no", + "875-no-ice", + "875-no-ice", "875", "875", "876-female", @@ -963,26 +963,26 @@ "929", "930", "930", - "931-blue", - "931-blue", - "931-green", - "931-green", - "931-white", - "931-white", - "931-yellow", - "931-yellow", + "931-blue-plumage-Disabled", + "931-blue-plumage-Disabled", + "931-green-plumage-Disabled", + "931-green-plumage-Disabled", + "931-white-plumage-Disabled", + "931-white-plumage-Disabled", + "931-yellow-plumage-Disabled", + "931-yellow-plumage-Disabled", "932", "932", "933", "933", "934", "934", - "935", - "935", - "936", - "936", - "937", - "937", + "935-Disabled", + "935-Disabled", + "936-Disabled", + "936-Disabled", + "937-Disabled", + "937-Disabled", "938", "938", "939", @@ -1073,6 +1073,8 @@ "978-droopy", "978-stretchy", "978-stretchy", + "979-Disabled", + "979-Disabled", "980", "980", "981", @@ -1131,10 +1133,10 @@ "1005b", "1006b", "1006b", - "1007b-apex", - "1007b-apex", - "1008b-ultimate", - "1008b-ultimate", + "1007b-apex-build-Disabled", + "1007b-apex-build-Disabled", + "1008b-ultimate-mode-Disabled", + "1008b-ultimate-mode-Disabled", "115b-mega", "115b-mega", "127b-mega", @@ -1303,9 +1305,9 @@ "531b-mega", "569b-gigantamax", "569b-gigantamax", - "6b-mega", - "6b-mega", "6b-mega-x", + "6b-mega-x", + "6b-mega-y", "6b-mega-y", "6058b", "6058b", @@ -1943,8 +1945,8 @@ "873b", "874b", "874b", - "875b-no", - "875b-no", + "875b-no-ice", + "875b-no-ice", "875b", "875b", "876b-female", @@ -2083,26 +2085,26 @@ "929b", "930b", "930b", - "931b-blue", - "931b-blue", - "931b-green", - "931b-green", - "931b-white", - "931b-white", - "931b-yellow", - "931b-yellow", + "931b-blue-plumage-Disabled", + "931b-blue-plumage-Disabled", + "931b-green-plumage-Disabled", + "931b-green-plumage-Disabled", + "931b-white-plumage-Disabled", + "931b-white-plumage-Disabled", + "931b-yellow-plumage-Disabled", + "931b-yellow-plumage-Disabled", "932b", "932b", "933b", "933b", "934b", "934b", - "935b", - "935b", - "936b", - "936b", - "937b", - "937b", + "935b-Disabled", + "935b-Disabled", + "936b-Disabled", + "936b-Disabled", + "937b-Disabled", + "937b-Disabled", "938b", "938b", "939b", @@ -2251,10 +2253,10 @@ "1005sb", "1006sb", "1006sb", - "1007sb-apex", - "1007sb-apex", - "1008sb-ultimate", - "1008sb-ultimate", + "1007sb-apex-build-Disabled", + "1007sb-apex-build-Disabled", + "1008sb-ultimate-mode-Disabled", + "1008sb-ultimate-mode-Disabled", "115sb-mega", "115sb-mega", "127sb-mega", @@ -3063,8 +3065,8 @@ "873sb", "874sb", "874sb", - "875sb-no", - "875sb-no", + "875sb-no-ice", + "875sb-no-ice", "875sb", "875sb", "876sb-female", @@ -3203,26 +3205,26 @@ "929sb", "930sb", "930sb", - "931sb-blue", - "931sb-blue", - "931sb-green", - "931sb-green", - "931sb-white", - "931sb-white", - "931sb-yellow", - "931sb-yellow", + "931sb-blue-plumage-Disabled", + "931sb-blue-plumage-Disabled", + "931sb-green-plumage-Disabled", + "931sb-green-plumage-Disabled", + "931sb-white-plumage-Disabled", + "931sb-white-plumage-Disabled", + "931sb-yellow-plumage-Disabled", + "931sb-yellow-plumage-Disabled", "932sb", "932sb", "933sb", "933sb", "934sb", "934sb", - "935sb", - "935sb", - "936sb", - "936sb", - "937sb", - "937sb", + "935sb-Disabled", + "935sb-Disabled", + "936sb-Disabled", + "936sb-Disabled", + "937sb-Disabled", + "937sb-Disabled", "938sb", "938sb", "939sb", @@ -3376,10 +3378,10 @@ "1005s", "1006s", "1006s", - "1007s-apex", - "1007s-apex", - "1008s-ultimate", - "1008s-ultimate", + "1007s-apex-build-Disabled", + "1007s-apex-build-Disabled", + "1008s-ultimate-mode-Disabled", + "1008s-ultimate-mode-Disabled", "115s-mega", "115s-mega", "127s-mega", @@ -4188,8 +4190,8 @@ "873s", "874s", "874s", - "875s-no", - "875s-no", + "875s-no-ice", + "875s-no-ice", "875s", "875s", "876s-female", @@ -4328,26 +4330,26 @@ "929s", "930s", "930s", - "931s-blue", - "931s-blue", - "931s-green", - "931s-green", - "931s-white", - "931s-white", - "931s-yellow", - "931s-yellow", + "931s-blue-plumage-Disabled", + "931s-blue-plumage-Disabled", + "931s-green-plumage-Disabled", + "931s-green-plumage-Disabled", + "931s-white-plumage-Disabled", + "931s-white-plumage-Disabled", + "931s-yellow-plumage-Disabled", + "931s-yellow-plumage-Disabled", "932s", "932s", "933s", "933s", "934s", "934s", - "935s", - "935s", - "936s", - "936s", - "937s", - "937s", + "935s-Disabled", + "935s-Disabled", + "936s-Disabled", + "936s-Disabled", + "937s-Disabled", + "937s-Disabled", "938s", "938s", "939s", @@ -4438,6 +4440,8 @@ "978s-droopy", "978s-stretchy", "978s-stretchy", + "979s-Disabled", + "979s-Disabled", "980s", "980s", "981s", @@ -4485,11 +4489,10 @@ "1000", "1001", "1004", - "1007-apex", - "1007-apex", - "1007-apex", - "1007-apex", - "1008-ultimate", + "1007-apex-build-Disabled", + "1007-apex-build-Disabled", + "1008-ultimate-mode-Disabled", + "1008-ultimate-mode-Disabled", "127-mega", "142-mega", "150-mega", @@ -4698,21 +4701,21 @@ "933_3", "933_3", "934", - "935", - "935_3", - "935_3", - "936_1", - "936_1", - "936_2", - "936_2", - "936_3", - "936_3", - "937_1", - "937_1", - "937_2", - "937_2", - "937_3", - "937_3", + "935-Disabled", + "935_3-Disabled", + "935_3-Disabled", + "936_1-Disabled", + "936_1-Disabled", + "936_2-Disabled", + "936_2-Disabled", + "936_3-Disabled", + "936_3-Disabled", + "937_1-Disabled", + "937_1-Disabled", + "937_2-Disabled", + "937_2-Disabled", + "937_3-Disabled", + "937_3-Disabled", "94-mega_1", "94-mega_1", "94-mega_2", @@ -4755,11 +4758,10 @@ "1000b", "1001b", "1004b", - "1007b-apex", - "1007b-apex", - "1007b-apex", - "1007b-apex", - "1008b-ultimate", + "1007b-apex-build-Disabled", + "1007b-apex-build-Disabled", + "1008b-ultimate-mode-Disabled", + "1008b-ultimate-mode-Disabled", "127b-mega", "142b-mega", "150b-mega", @@ -4920,24 +4922,24 @@ "932b", "933b", "934b", - "935_1b", - "935_1b", - "935_2b", - "935_2b", - "935_3b", - "935_3b", - "936_1b", - "936_1b", - "936_2b", - "936_2b", - "936_3b", - "936_3b", - "937_1b", - "937_1b", - "937_2b", - "937_2b", - "937_3b", - "937_3b", + "935_1b-Disabled", + "935_1b-Disabled", + "935_2b-Disabled", + "935_2b-Disabled", + "935_3b-Disabled", + "935_3b-Disabled", + "936_1b-Disabled", + "936_1b-Disabled", + "936_2b-Disabled", + "936_2b-Disabled", + "936_3b-Disabled", + "936_3b-Disabled", + "937_1b-Disabled", + "937_1b-Disabled", + "937_2b-Disabled", + "937_2b-Disabled", + "937_3b-Disabled", + "937_3b-Disabled", "94b-mega", "948b", "949b", From 17e71a1b8affcac6def2fb180b8b53064c5384f5 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:26:49 -0700 Subject: [PATCH 09/14] [Bug] Fix Poison Heal Crash on beta (#5544) Fix !== null uses --- src/data/ability.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index ab78d1dd06c..d9e29c5506c 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3860,7 +3860,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { } override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return (pokemon.status !== null) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp(); + return !Utils.isNullOrUndefined(pokemon.status) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp(); } /** @@ -4103,7 +4103,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr { } override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return !simulated && globalScene.currentBattle.lastUsedPokeball !== null && !!pokemon.isPlayer; + return !simulated && !Utils.isNullOrUndefined(globalScene.currentBattle.lastUsedPokeball) && !!pokemon.isPlayer; } /** From 66965bf7e29f1bc9c136451565870ab4da0300d4 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:37:16 -0700 Subject: [PATCH 10/14] [Bug] Fix Slow Start Message being Deferred (#5534) Fix deferred message --- src/data/battler-tags.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 43a7072fd12..7ff74d893b6 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1922,10 +1922,6 @@ export class SlowStartTag extends AbilityBattlerTag { i18next.t("battlerTags:slowStartOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), }), - null, - false, - null, - true, ); } From c792d5e7046f06db415078854a6a4cc2bbb007be Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:53:27 -0400 Subject: [PATCH 11/14] [Balance] Changes to several trainer classes (#5505) * Changes to Biker, Baker, Beauty, Cyclist, Parasol Lady, Hex Maniac * Linting and extra beauty mons * Further changes * Find to some --------- Co-authored-by: damocleas --- src/data/balance/biomes.ts | 28 +++++---- src/data/trainer-config.ts | 126 ++++++++++++++++++++++++++++++++++--- 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts index 71a48162e57..a4e051d80c9 100644 --- a/src/data/balance/biomes.ts +++ b/src/data/balance/biomes.ts @@ -1680,7 +1680,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.METROPOLIS]: { - [BiomePoolTier.COMMON]: [ TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER ], + [BiomePoolTier.COMMON]: [ TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER, TrainerType.BEAUTY ], [BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER, TrainerType.DEPOT_AGENT, TrainerType.GUITARIST ], [BiomePoolTier.RARE]: [ TrainerType.ARTIST ], [BiomePoolTier.SUPER_RARE]: [], @@ -1713,7 +1713,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.SWAMP]: { - [BiomePoolTier.COMMON]: [], + [BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.SUPER_RARE]: [], @@ -1724,7 +1724,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.BEACH]: { - [BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.PARASOL_LADY, TrainerType.SAILOR ], + [BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.SAILOR ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.SUPER_RARE]: [], @@ -1735,7 +1735,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.LAKE]: { - [BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN ], + [BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN, TrainerType.PARASOL_LADY ], [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ], [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.SUPER_RARE]: [], @@ -1790,7 +1790,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.DESERT]: { - [BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST ], + [BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST, TrainerType.BACKPACKER ], [BiomePoolTier.UNCOMMON]: [], [BiomePoolTier.RARE]: [], [BiomePoolTier.SUPER_RARE]: [], @@ -1812,8 +1812,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.MEADOW]: { - [BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY ], - [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ], + [BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY, TrainerType.BEAUTY ], + [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER, TrainerType.BAKER ], [BiomePoolTier.RARE]: [], [BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [], @@ -1879,7 +1879,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { }, [Biome.RUINS]: { [BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC, TrainerType.SCIENTIST ], - [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT ], + [BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT, TrainerType.HEX_MANIAC ], [BiomePoolTier.RARE]: [], [BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [], @@ -7165,14 +7165,18 @@ export function initBiomes() { [ Biome.MOUNTAIN, BiomePoolTier.COMMON ], [ Biome.CAVE, BiomePoolTier.COMMON ], [ Biome.BADLANDS, BiomePoolTier.COMMON ], - [ Biome.JUNGLE, BiomePoolTier.COMMON ] + [ Biome.JUNGLE, BiomePoolTier.COMMON ], + [ Biome.DESERT, BiomePoolTier.COMMON ] ] ], [ TrainerType.BAKER, [ - [ Biome.SLUM, BiomePoolTier.UNCOMMON ] + [ Biome.SLUM, BiomePoolTier.UNCOMMON ], + [ Biome.MEADOW, BiomePoolTier.UNCOMMON ] ] ], [ TrainerType.BEAUTY, [ + [ Biome.METROPOLIS, BiomePoolTier.COMMON ], + [ Biome.MEADOW, BiomePoolTier.COMMON ], [ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ] ]], [ TrainerType.BIKER, [ @@ -7247,7 +7251,8 @@ export function initBiomes() { ] ], [ TrainerType.PARASOL_LADY, [ - [ Biome.BEACH, BiomePoolTier.COMMON ], + [ Biome.SWAMP, BiomePoolTier.COMMON ], + [ Biome.LAKE, BiomePoolTier.COMMON ], [ Biome.MEADOW, BiomePoolTier.COMMON ] ] ], @@ -7313,6 +7318,7 @@ export function initBiomes() { ] ], [ TrainerType.HEX_MANIAC, [ + [ Biome.RUINS, BiomePoolTier.UNCOMMON ], [ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ] ] ], diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 3884aa05b13..ffe5cdfe04c 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -23,6 +23,7 @@ import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; import { Gender } from "#app/data/gender"; import { signatureSpecies } from "./balance/signature-species"; +import { Abilities } from "#enums/abilities"; /** Minimum BST for Pokemon generated onto the Elite Four's teams */ const ELITE_FOUR_MINIMUM_BST = 460; @@ -1811,12 +1812,92 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.BAKER]: new TrainerConfig(++t) .setEncounterBgm(TrainerType.CLERK) .setMoneyMultiplier(1.35) - .setSpeciesFilter(s => s.isOfType(PokemonType.GRASS) || s.isOfType(PokemonType.FIRE)), - [TrainerType.BEAUTY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY), + .setSpeciesFilter( + s => + [s.ability1, s.ability2, s.abilityHidden].some( + a => + !!a && + [ + Abilities.WHITE_SMOKE, + Abilities.GLUTTONY, + Abilities.HONEY_GATHER, + Abilities.HARVEST, + Abilities.CHEEK_POUCH, + Abilities.SWEET_VEIL, + Abilities.RIPEN, + Abilities.PURIFYING_SALT, + Abilities.WELL_BAKED_BODY, + Abilities.SUPERSWEET_SYRUP, + Abilities.HOSPITALITY, + ].includes(a), + ) || + s + .getLevelMoves() + .some(plm => + [Moves.SOFT_BOILED, Moves.SPORE, Moves.MILK_DRINK, Moves.OVERHEAT, Moves.TEATIME].includes(plm[1]), + ), + ), // Mons with baking related abilities or who learn Overheat, Teatime, Milk Drink, Spore, or Soft-Boiled by level + [TrainerType.BEAUTY]: new TrainerConfig(++t) + .setMoneyMultiplier(1.55) + .setEncounterBgm(TrainerType.PARASOL_LADY) + .setPartyTemplates( + trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, + trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG, + trainerPartyTemplates.THREE_AVG_SAME, + trainerPartyTemplates.THREE_AVG, + trainerPartyTemplates.FOUR_WEAK, + trainerPartyTemplates.ONE_STRONG, + ) + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [ + Species.MEOWTH, + Species.GOLDEEN, + Species.MAREEP, + Species.MARILL, + Species.SKITTY, + Species.GLAMEOW, + Species.PURRLOIN, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.SMOOCHUM, + Species.ROSELIA, + Species.LUVDISC, + Species.BLITZLE, + Species.SEWADDLE, + Species.PETILIL, + Species.MINCCINO, + Species.GOTHITA, + Species.SPRITZEE, + Species.FLITTLE, + ], + [TrainerPoolTier.RARE]: [ + Species.FEEBAS, + Species.FURFROU, + Species.SALANDIT, + Species.BRUXISH, + Species.HATENNA, + Species.SNOM, + Species.ALOLA_VULPIX, + ], + [TrainerPoolTier.SUPER_RARE]: [Species.CLAMPERL, Species.AMAURA, Species.SYLVEON, Species.GOOMY, Species.POPPLIO], + }), [TrainerType.BIKER]: new TrainerConfig(++t) .setMoneyMultiplier(1.4) .setEncounterBgm(TrainerType.ROUGHNECK) - .setSpeciesFilter(s => s.isOfType(PokemonType.POISON)), + .setSpeciesPools({ + [TrainerPoolTier.COMMON]: [Species.EKANS, Species.KOFFING, Species.CROAGUNK, Species.VENIPEDE, Species.SCRAGGY], + [TrainerPoolTier.UNCOMMON]: [ + Species.GRIMER, + Species.VOLTORB, + Species.TEDDIURSA, + Species.MAGBY, + Species.SKORUPI, + Species.SANDILE, + Species.PAWNIARD, + Species.SHROODLE, + ], + [TrainerPoolTier.RARE]: [Species.VAROOM, Species.CYCLIZAR], + }), [TrainerType.BLACK_BELT]: new TrainerConfig(++t) .setHasGenders("Battle Girl", TrainerType.PSYCHIC) .setHasDouble("Crush Kin") @@ -1918,9 +1999,15 @@ export const trainerConfigs: TrainerConfigs = { .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.COMMON]: [Species.DODUO, Species.PICHU, Species.TAILLOW, Species.STARLY, Species.PONYTA], + [TrainerPoolTier.UNCOMMON]: [ + Species.ELECTRIKE, + Species.SHINX, + Species.BLITZLE, + Species.DUCKLETT, + Species.WATTREL, + ], + [TrainerPoolTier.RARE]: [Species.YANMA, Species.NINJASK, Species.WHIRLIPEDE, Species.EMOLGA, Species.SKIDDO], [TrainerPoolTier.SUPER_RARE]: [Species.ACCELGOR, Species.DREEPY], }), [TrainerType.DANCER]: new TrainerConfig(++t) @@ -1936,7 +2023,7 @@ export const trainerConfigs: TrainerConfigs = { [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], + [TrainerPoolTier.SUPER_RARE]: [Species.QUAXLY, Species.JANGMO_O], }), [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK), [TrainerType.DOCTOR]: new TrainerConfig(++t) @@ -2074,7 +2161,7 @@ export const trainerConfigs: TrainerConfigs = { trainerPartyTemplates.THREE_AVG, trainerPartyTemplates.TWO_STRONG, ) - .setSpeciesFilter(s => s.isOfType(PokemonType.GHOST)), + .setSpeciesFilter(s => s.isOfType(PokemonType.GHOST) || s.isOfType(PokemonType.PSYCHIC)), [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm("lass"), [TrainerType.OFFICER]: new TrainerConfig(++t) .setMoneyMultiplier(1.55) @@ -2104,7 +2191,28 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.PARASOL_LADY]: new TrainerConfig(++t) .setMoneyMultiplier(1.55) .setEncounterBgm(TrainerType.PARASOL_LADY) - .setSpeciesFilter(s => s.isOfType(PokemonType.WATER)), + .setPartyTemplates( + trainerPartyTemplates.TWO_AVG_SAME_ONE_AVG, + trainerPartyTemplates.TWO_AVG_SAME_ONE_STRONG, + trainerPartyTemplates.TWO_AVG, + trainerPartyTemplates.FOUR_WEAK, + trainerPartyTemplates.ONE_STRONG, + ) + .setSpeciesFilter( + s => + [s.ability1, s.ability2, s.abilityHidden].some( + a => + !!a && + [ + Abilities.DRIZZLE, + Abilities.SWIFT_SWIM, + Abilities.HYDRATION, + Abilities.RAIN_DISH, + Abilities.DRY_SKIN, + Abilities.WIND_POWER, + ].includes(a), + ) || s.getLevelMoves().some(plm => plm[1] === Moves.RAIN_DANCE), + ), // Mons with rain abilities or who learn Rain Dance by level [TrainerType.PILOT]: new TrainerConfig(++t) .setEncounterBgm(TrainerType.CLERK) .setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1), From 87b78e6b706924d435f57924c991d9705b93972b Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 22 Mar 2025 15:47:41 -0400 Subject: [PATCH 12/14] [Balance] [Move] Made more moves callable with Metronome, Assist, Sleep Talk, and Copycat (#5549) Update invalid-moves.ts --- src/data/moves/invalid-moves.ts | 104 -------------------------------- 1 file changed, 104 deletions(-) diff --git a/src/data/moves/invalid-moves.ts b/src/data/moves/invalid-moves.ts index 50f815b9e58..64052902d9d 100644 --- a/src/data/moves/invalid-moves.ts +++ b/src/data/moves/invalid-moves.ts @@ -3,144 +3,47 @@ import { Moves } from "#enums/moves"; /** Set of moves that cannot be called by {@linkcode Moves.METRONOME Metronome} */ export const invalidMetronomeMoves: ReadonlySet = new Set([ Moves.AFTER_YOU, - Moves.APPLE_ACID, - Moves.ARMOR_CANNON, Moves.ASSIST, - Moves.ASTRAL_BARRAGE, - Moves.AURA_WHEEL, Moves.BANEFUL_BUNKER, Moves.BEAK_BLAST, - Moves.BEHEMOTH_BASH, - Moves.BEHEMOTH_BLADE, Moves.BELCH, Moves.BESTOW, - Moves.BLAZING_TORQUE, - Moves.BODY_PRESS, - Moves.BRANCH_POKE, - Moves.BREAKING_SWIPE, - Moves.CELEBRATE, - Moves.CHATTER, - Moves.CHILLING_WATER, - Moves.CHILLY_RECEPTION, - Moves.CLANGOROUS_SOUL, - Moves.COLLISION_COURSE, - Moves.COMBAT_TORQUE, Moves.COMEUPPANCE, Moves.COPYCAT, Moves.COUNTER, - Moves.COVET, Moves.CRAFTY_SHIELD, - Moves.DECORATE, Moves.DESTINY_BOND, Moves.DETECT, - Moves.DIAMOND_STORM, - Moves.DOODLE, - Moves.DOUBLE_IRON_BASH, - Moves.DOUBLE_SHOCK, - Moves.DRAGON_ASCENT, - Moves.DRAGON_ENERGY, - Moves.DRUM_BEATING, - Moves.DYNAMAX_CANNON, - Moves.ELECTRO_DRIFT, Moves.ENDURE, - Moves.ETERNABEAM, - Moves.FALSE_SURRENDER, Moves.FEINT, - Moves.FIERY_WRATH, - Moves.FILLET_AWAY, Moves.FLEUR_CANNON, Moves.FOCUS_PUNCH, Moves.FOLLOW_ME, - Moves.FREEZE_SHOCK, - Moves.FREEZING_GLARE, - Moves.GLACIAL_LANCE, - Moves.GRAV_APPLE, Moves.HELPING_HAND, - Moves.HOLD_HANDS, - Moves.HYPER_DRILL, - Moves.HYPERSPACE_FURY, - Moves.HYPERSPACE_HOLE, - Moves.ICE_BURN, Moves.INSTRUCT, - Moves.JET_PUNCH, - Moves.JUNGLE_HEALING, Moves.KINGS_SHIELD, - Moves.LIFE_DEW, - Moves.LIGHT_OF_RUIN, - Moves.MAKE_IT_RAIN, - Moves.MAGICAL_TORQUE, Moves.MAT_BLOCK, Moves.ME_FIRST, - Moves.METEOR_ASSAULT, Moves.METRONOME, Moves.MIMIC, - Moves.MIND_BLOWN, Moves.MIRROR_COAT, Moves.MIRROR_MOVE, - Moves.MOONGEIST_BEAM, - Moves.NATURE_POWER, - Moves.NATURES_MADNESS, - Moves.NOXIOUS_TORQUE, Moves.OBSTRUCT, - Moves.ORDER_UP, - Moves.ORIGIN_PULSE, - Moves.OVERDRIVE, - Moves.PHOTON_GEYSER, - Moves.PLASMA_FISTS, - Moves.POPULATION_BOMB, - Moves.POUNCE, - Moves.POWER_SHIFT, - Moves.PRECIPICE_BLADES, Moves.PROTECT, - Moves.PYRO_BALL, Moves.QUASH, Moves.QUICK_GUARD, - Moves.RAGE_FIST, Moves.RAGE_POWDER, - Moves.RAGING_BULL, - Moves.RAGING_FURY, - Moves.RELIC_SONG, Moves.REVIVAL_BLESSING, - Moves.RUINATION, - Moves.SALT_CURE, - Moves.SECRET_SWORD, - Moves.SHED_TAIL, Moves.SHELL_TRAP, Moves.SILK_TRAP, Moves.SKETCH, Moves.SLEEP_TALK, - Moves.SNAP_TRAP, - Moves.SNARL, Moves.SNATCH, Moves.SNORE, - Moves.SNOWSCAPE, - Moves.SPECTRAL_THIEF, - Moves.SPICY_EXTRACT, Moves.SPIKY_SHIELD, - Moves.SPIRIT_BREAK, Moves.SPOTLIGHT, - Moves.STEAM_ERUPTION, - Moves.STEEL_BEAM, - Moves.STRANGE_STEAM, Moves.STRUGGLE, - Moves.SUNSTEEL_STRIKE, - Moves.SURGING_STRIKES, - Moves.SWITCHEROO, - Moves.TECHNO_BLAST, - Moves.TERA_STARSTORM, - Moves.THIEF, - Moves.THOUSAND_ARROWS, - Moves.THOUSAND_WAVES, - Moves.THUNDER_CAGE, - Moves.THUNDEROUS_KICK, - Moves.TIDY_UP, - Moves.TRAILBLAZE, Moves.TRANSFORM, - Moves.TRICK, - Moves.TWIN_BEAM, - Moves.V_CREATE, - Moves.WICKED_BLOW, - Moves.WICKED_TORQUE, Moves.WIDE_GUARD, ]); @@ -157,7 +60,6 @@ export const invalidAssistMoves: ReadonlySet = new Set([ Moves.CIRCLE_THROW, Moves.COPYCAT, Moves.COUNTER, - Moves.COVET, Moves.DESTINY_BOND, Moves.DETECT, Moves.DIG, @@ -192,7 +94,6 @@ export const invalidAssistMoves: ReadonlySet = new Set([ Moves.SPOTLIGHT, Moves.STRUGGLE, Moves.SWITCHEROO, - Moves.THIEF, Moves.TRANSFORM, Moves.TRICK, Moves.WHIRLWIND, @@ -208,7 +109,6 @@ export const invalidSleepTalkMoves: ReadonlySet = new Set([ Moves.COPYCAT, Moves.DIG, Moves.DIVE, - Moves.DYNAMAX_CANNON, Moves.FREEZE_SHOCK, Moves.FLY, Moves.FOCUS_PUNCH, @@ -238,15 +138,12 @@ export const invalidCopycatMoves: ReadonlySet = new Set([ Moves.ASSIST, Moves.BANEFUL_BUNKER, Moves.BEAK_BLAST, - Moves.BEHEMOTH_BASH, - Moves.BEHEMOTH_BLADE, Moves.BESTOW, Moves.CELEBRATE, Moves.CHATTER, Moves.CIRCLE_THROW, Moves.COPYCAT, Moves.COUNTER, - Moves.COVET, Moves.DESTINY_BOND, Moves.DETECT, Moves.DRAGON_TAIL, @@ -274,7 +171,6 @@ export const invalidCopycatMoves: ReadonlySet = new Set([ Moves.SPOTLIGHT, Moves.STRUGGLE, Moves.SWITCHEROO, - Moves.THIEF, Moves.TRANSFORM, Moves.TRICK, Moves.WHIRLWIND, From d0a9672e91de1c7fcf87d1f81eede4faa7dc6a86 Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 22 Mar 2025 16:18:08 -0400 Subject: [PATCH 13/14] [Balance] [Move] Add Fleur Cannon as a Metronome callableove (#5551) * Update invalid-moves.ts * forgot fleur cannon --- src/data/moves/invalid-moves.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/data/moves/invalid-moves.ts b/src/data/moves/invalid-moves.ts index 64052902d9d..7284831528a 100644 --- a/src/data/moves/invalid-moves.ts +++ b/src/data/moves/invalid-moves.ts @@ -16,7 +16,6 @@ export const invalidMetronomeMoves: ReadonlySet = new Set([ Moves.DETECT, Moves.ENDURE, Moves.FEINT, - Moves.FLEUR_CANNON, Moves.FOCUS_PUNCH, Moves.FOLLOW_ME, Moves.HELPING_HAND, From 4b8f1df8cd4bc98b985f05931befa11183e0443d Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 22 Mar 2025 14:46:58 -0700 Subject: [PATCH 14/14] [Bug] Add list of uncallable moves for Mirror Move (#5552) * Add list of uncallable moves for Mirror Move * Mirror Move now respects the uncallable moves list --------- Co-authored-by: damocleas --- src/data/moves/invalid-moves.ts | 66 +++++++++++++++++++++++++++++++++ src/data/moves/move.ts | 7 ++-- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/data/moves/invalid-moves.ts b/src/data/moves/invalid-moves.ts index 7284831528a..5cd45de7939 100644 --- a/src/data/moves/invalid-moves.ts +++ b/src/data/moves/invalid-moves.ts @@ -174,3 +174,69 @@ export const invalidCopycatMoves: ReadonlySet = new Set([ Moves.TRICK, Moves.WHIRLWIND, ]); + +export const invalidMirrorMoveMoves: ReadonlySet = new Set([ + Moves.ACUPRESSURE, + Moves.AFTER_YOU, + Moves.AROMATIC_MIST, + Moves.BEAK_BLAST, + Moves.BELCH, + Moves.CHILLY_RECEPTION, + Moves.COACHING, + Moves.CONVERSION_2, + Moves.COUNTER, + Moves.CRAFTY_SHIELD, + Moves.CURSE, + Moves.DECORATE, + Moves.DOODLE, + Moves.DOOM_DESIRE, + Moves.DRAGON_CHEER, + Moves.ELECTRIC_TERRAIN, + Moves.FINAL_GAMBIT, + Moves.FLORAL_HEALING, + Moves.FLOWER_SHIELD, + Moves.FOCUS_PUNCH, + Moves.FUTURE_SIGHT, + Moves.GEAR_UP, + Moves.GRASSY_TERRAIN, + Moves.GRAVITY, + Moves.GUARD_SPLIT, + Moves.HAIL, + Moves.HAZE, + Moves.HEAL_PULSE, + Moves.HELPING_HAND, + Moves.HOLD_HANDS, + Moves.INSTRUCT, + Moves.ION_DELUGE, + Moves.MAGNETIC_FLUX, + Moves.MAT_BLOCK, + Moves.ME_FIRST, + Moves.MIMIC, + Moves.MIRROR_COAT, + Moves.MIRROR_MOVE, + Moves.MIST, + Moves.MISTY_TERRAIN, + Moves.MUD_SPORT, + Moves.PERISH_SONG, + Moves.POWER_SPLIT, + Moves.PSYCH_UP, + Moves.PSYCHIC_TERRAIN, + Moves.PURIFY, + Moves.QUICK_GUARD, + Moves.RAIN_DANCE, + Moves.REFLECT_TYPE, + Moves.ROLE_PLAY, + Moves.ROTOTILLER, + Moves.SANDSTORM, + Moves.SHELL_TRAP, + Moves.SKETCH, + Moves.SNOWSCAPE, + Moves.SPIT_UP, + Moves.SPOTLIGHT, + Moves.STRUGGLE, + Moves.SUNNY_DAY, + Moves.TEATIME, + Moves.TRANSFORM, + Moves.WATER_SPORT, + Moves.WIDE_GUARD, +]); diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 3d80b6b3f4c..c7b5b4aec6b 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -125,7 +125,7 @@ import { MoveTarget } from "#enums/MoveTarget"; import { MoveFlags } from "#enums/MoveFlags"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MultiHitType } from "#enums/MultiHitType"; -import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidSleepTalkMoves } from "./invalid-moves"; +import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves"; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; @@ -6966,7 +6966,8 @@ export class CopyMoveAttr extends CallMoveAttr { getCondition(): MoveConditionFunc { return (user, target, move) => { if (this.mirrorMove) { - return target.getMoveHistory().length !== 0; + const lastMove = target.getLastXMoves()[0]?.move; + return !!lastMove && !this.invalidMoves.has(lastMove); } else { const lastMove = globalScene.currentBattle.lastMove; return lastMove !== undefined && !this.invalidMoves.has(lastMove); @@ -8562,7 +8563,7 @@ export function initMoves() { new SelfStatusMove(Moves.METRONOME, PokemonType.NORMAL, -1, 10, -1, 0, 1) .attr(RandomMoveAttr, invalidMetronomeMoves), new StatusMove(Moves.MIRROR_MOVE, PokemonType.FLYING, -1, 20, -1, 0, 1) - .attr(CopyMoveAttr, true), + .attr(CopyMoveAttr, true, invalidMirrorMoveMoves), new AttackMove(Moves.SELF_DESTRUCT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1) .attr(SacrificialAttr) .makesContact(false)