From a7b3344c6d58f14f609b4c74737c0d732d6041c3 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 14 Sep 2024 05:21:31 -0700 Subject: [PATCH 1/8] Fix missing key in "No Effect" message (#4244) --- 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 8a305f36d73..43a7090bff5 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2615,7 +2615,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (result === HitResult.IMMUNE) { this.scene.queueMessage(i18next.t("battle:hitResultImmune", { pokemonName: getPokemonNameWithAffix(this) })); } else { - this.scene.queueMessage(i18next.t("battle:hitResultNoEffect")); + this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) })); } } return result; From 39a1963941332b77056b928711a2f5e414b3646f Mon Sep 17 00:00:00 2001 From: Lugiad Date: Sat, 14 Sep 2024 18:33:41 +0200 Subject: [PATCH 2/8] [Localization] French Translations tiny settings batch (#4250) * Update settings.json * Update move.json --- src/locales/fr/move.json | 4 ++-- src/locales/fr/settings.json | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/locales/fr/move.json b/src/locales/fr/move.json index a48e17b3fd9..957895b5db9 100644 --- a/src/locales/fr/move.json +++ b/src/locales/fr/move.json @@ -364,8 +364,8 @@ "effect": "Le lanceur creuse au premier tour et frappe au second." }, "toxic": { - "name": "Fil Toxique", - "effect": "Tisse un fil imprégné de venin. Empoisonne la cible et baisse sa Vitesse." + "name": "Toxik", + "effect": "Le lanceur empoisonne gravement la cible. Les dégâts dus au poison augmentent à chaque tour." }, "confusion": { "name": "Choc Mental", diff --git a/src/locales/fr/settings.json b/src/locales/fr/settings.json index c752b336b6e..e310f5d5733 100644 --- a/src/locales/fr/settings.json +++ b/src/locales/fr/settings.json @@ -11,6 +11,10 @@ "expGainsSpeed": "Vit. barre d’Exp", "expPartyDisplay": "Afficher Exp équipe", "skipSeenDialogues": "Passer dialogues connus", + "eggSkip": "Animation d’éclosion", + "never": "Jamais", + "always": "Toujours", + "ask": "Demander", "battleStyle": "Style de combat", "enableRetries": "Activer les réessais", "hideIvs": "Masquer Scanner d’IV", From bdc7c95c1cfc0e9a3177cfadde2c1170e92f0268 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 14 Sep 2024 09:35:36 -0700 Subject: [PATCH 3/8] [Misc][AI] Fix KO filter not accounting for move conditions (#4245) * Only filter KO moves that won't fail * Add Last Resort enemy command test --- src/field/pokemon.ts | 5 ++++- src/test/enemy_command.test.ts | 41 +++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 43a7090bff5..faae3b06ba0 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4410,7 +4410,10 @@ export class EnemyPokemon extends Pokemon { const isCritical = move.hasAttr(CritOnlyAttr) || !!this.getTag(BattlerTagType.ALWAYS_CRIT); return move.category !== MoveCategory.STATUS - && moveTargets.some(p => p.getAttackDamage(this, move, !p.battleData.abilityRevealed, false, isCritical).damage >= p.hp); + && moveTargets.some(p => { + const doesNotFail = move.applyConditions(this, p, move) || [Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP].includes(move.id); + return doesNotFail && p.getAttackDamage(this, move, !p.battleData.abilityRevealed, false, isCritical).damage >= p.hp; + }); }, this); if (koMoves.length > 0) { diff --git a/src/test/enemy_command.test.ts b/src/test/enemy_command.test.ts index 39b77845ea9..9a2caa56dfc 100644 --- a/src/test/enemy_command.test.ts +++ b/src/test/enemy_command.test.ts @@ -6,7 +6,7 @@ import { AiType, EnemyPokemon } from "#app/field/pokemon"; import { randSeedInt } from "#app/utils"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const TIMEOUT = 20 * 1000; const NUM_TRIALS = 300; @@ -36,22 +36,26 @@ describe("Enemy Commands - Move Selection", () => { phaserGame = new Phaser.Game({ type: Phaser.HEADLESS, }); - game = new GameManager(phaserGame); - game.override.ability(Abilities.BALL_FETCH); }); afterEach(() => { game.phaseInterceptor.restoreOg(); }); + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .ability(Abilities.BALL_FETCH) + .enemyAbility(Abilities.BALL_FETCH); + }); + it( "should never use Status moves if an attack can KO", async () => { game.override .enemySpecies(Species.ETERNATUS) .enemyMoveset([Moves.ETERNABEAM, Moves.SLUDGE_BOMB, Moves.DRAGON_DANCE, Moves.COSMIC_POWER]) - .enemyAbility(Abilities.BALL_FETCH) - .ability(Abilities.BALL_FETCH) .startingLevel(1) .enemyLevel(100); @@ -72,4 +76,31 @@ describe("Enemy Commands - Move Selection", () => { }); }, TIMEOUT ); + + it( + "should not select Last Resort if it would fail, even if the move KOs otherwise", + async () => { + game.override + .enemySpecies(Species.KANGASKHAN) + .enemyMoveset([Moves.LAST_RESORT, Moves.GIGA_IMPACT, Moves.SPLASH, Moves.SWORDS_DANCE]) + .startingLevel(1) + .enemyLevel(100); + + await game.classicMode.startBattle([Species.MAGIKARP]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + enemyPokemon.aiType = AiType.SMART_RANDOM; + + const moveChoices: MoveChoiceSet = {}; + const enemyMoveset = enemyPokemon.getMoveset(); + enemyMoveset.forEach(mv => moveChoices[mv!.moveId] = 0); + getEnemyMoveChoices(enemyPokemon, moveChoices); + + enemyMoveset.forEach(mv => { + if (mv?.getMove().category === MoveCategory.STATUS || mv?.moveId === Moves.LAST_RESORT) { + expect(moveChoices[mv.moveId]).toBe(0); + } + }); + }, TIMEOUT + ); }); From 763c1922fbad172e6c3d2b178aae9be5679b3267 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Sat, 14 Sep 2024 09:35:46 -0700 Subject: [PATCH 4/8] [Bug] Fix exp gains speed not applying properly (#4243) * update battle-info.ts * add: ExpGainsSpeed enum * address PR comments * add test coverage (exp gains speed) --------- Co-authored-by: Mr.WaterT Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/battle-scene.ts | 3 +- src/enums/exp-gains-speed.ts | 22 ++++++++++ src/phases/show-party-exp-bar-phase.ts | 3 +- src/test/ui/battle_info.test.ts | 55 ++++++++++++++++++++++++ src/test/utils/gameManager.ts | 3 +- src/test/utils/helpers/settingsHelper.ts | 10 +++++ src/test/utils/phaseInterceptor.ts | 4 +- src/ui/battle-info.ts | 9 +++- 8 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/enums/exp-gains-speed.ts create mode 100644 src/test/ui/battle_info.test.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 9a7221d3fb3..516662617f1 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -105,6 +105,7 @@ import HeldModifierConfig from "#app/interfaces/held-modifier-config"; import { ExpPhase } from "#app/phases/exp-phase"; import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; +import { ExpGainsSpeed } from "./enums/exp-gains-speed"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -180,7 +181,7 @@ export default class BattleScene extends SceneBase { public experimentalSprites: boolean = false; public musicPreference: integer = 0; public moveAnimations: boolean = true; - public expGainsSpeed: integer = 0; + public expGainsSpeed: ExpGainsSpeed = ExpGainsSpeed.DEFAULT; public skipSeenDialogues: boolean = false; /** * Determines if the egg hatching animation should be skipped diff --git a/src/enums/exp-gains-speed.ts b/src/enums/exp-gains-speed.ts new file mode 100644 index 00000000000..964c4f99c70 --- /dev/null +++ b/src/enums/exp-gains-speed.ts @@ -0,0 +1,22 @@ +/** + * Defines the speed of gaining experience. + * + * @remarks + * The `expGainSpeed` can have several modes: + * - `0` - Default: The normal speed. + * - `1` - Fast: Fast speed. + * - `2` - Faster: Faster speed. + * - `3` - Skip: Skip gaining exp animation. + * + * @default 0 - Uses the default normal speed. + */ +export enum ExpGainsSpeed { + /** The normal speed. */ + DEFAULT, + /** Fast speed. */ + FAST, + /** Faster speed. */ + FASTER, + /** Skip gaining exp animation. */ + SKIP +} diff --git a/src/phases/show-party-exp-bar-phase.ts b/src/phases/show-party-exp-bar-phase.ts index 9e019b202a5..f1783e7715f 100644 --- a/src/phases/show-party-exp-bar-phase.ts +++ b/src/phases/show-party-exp-bar-phase.ts @@ -1,4 +1,5 @@ import BattleScene from "#app/battle-scene"; +import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; import { ExpNotification } from "#app/enums/exp-notification"; import { ExpBoosterModifier } from "#app/modifier/modifier"; import * as Utils from "#app/utils"; @@ -44,7 +45,7 @@ export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase { } else { this.end(); } - } else if (this.scene.expGainsSpeed < 3) { + } else if (this.scene.expGainsSpeed < ExpGainsSpeed.SKIP) { this.scene.partyExpBar.showPokemonExp(pokemon, exp.value, false, newLevel).then(() => { setTimeout(() => this.end(), 500 / Math.pow(2, this.scene.expGainsSpeed)); }); diff --git a/src/test/ui/battle_info.test.ts b/src/test/ui/battle_info.test.ts new file mode 100644 index 00000000000..4d511b75e6f --- /dev/null +++ b/src/test/ui/battle_info.test.ts @@ -0,0 +1,55 @@ +import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; +import { Species } from "#app/enums/species"; +import { ExpPhase } from "#app/phases/exp-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("../data/exp", ({}) => { + return { + getLevelRelExp: vi.fn(() => 1), //consistent levelRelExp + }; +}); + +describe("UI - Battle Info", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.GUILLOTINE, Moves.SPLASH]) + .battleType("single") + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH) + .enemySpecies(Species.CATERPIE); + }); + + it.each([ExpGainsSpeed.FAST, ExpGainsSpeed.FASTER, ExpGainsSpeed.SKIP])( + "should increase exp gains animation by 2^%i", + async (expGainsSpeed) => { + game.settings.expGainsSpeed(expGainsSpeed); + vi.spyOn(Math, "pow"); + + await game.classicMode.startBattle([Species.CHARIZARD]); + + game.move.select(Moves.SPLASH); + await game.doKillOpponents(); + await game.phaseInterceptor.to(ExpPhase, true); + + expect(Math.pow).not.toHaveBeenCalledWith(2, expGainsSpeed); + } + ); +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index a10ed70b97e..452956ab466 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -54,6 +54,7 @@ import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; import { expect } from "vitest"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { isNullOrUndefined } from "#app/utils"; +import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; /** * Class to manage the game state and transitions between phases. @@ -148,7 +149,7 @@ export default class GameManager { this.scene.gameSpeed = 5; this.scene.moveAnimations = false; this.scene.showLevelUpStats = false; - this.scene.expGainsSpeed = 3; + this.scene.expGainsSpeed = ExpGainsSpeed.SKIP; this.scene.expParty = ExpNotification.SKIP; this.scene.hpBarSpeed = 3; this.scene.enableTutorials = false; diff --git a/src/test/utils/helpers/settingsHelper.ts b/src/test/utils/helpers/settingsHelper.ts index 8fca2a34d47..c611a705107 100644 --- a/src/test/utils/helpers/settingsHelper.ts +++ b/src/test/utils/helpers/settingsHelper.ts @@ -1,6 +1,7 @@ import { PlayerGender } from "#app/enums/player-gender"; import { BattleStyle } from "#app/enums/battle-style"; import { GameManagerHelper } from "./gameManagerHelper"; +import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; /** * Helper to handle settings for tests @@ -38,6 +39,15 @@ export class SettingsHelper extends GameManagerHelper { this.log(`Gender set to: ${PlayerGender[gender]} (=${gender})` ); } + /** + * Change the exp gains speed + * @param speed the {@linkcode ExpGainsSpeed} to set + */ + expGainsSpeed(speed: ExpGainsSpeed) { + this.game.scene.expGainsSpeed = speed; + this.log(`Exp Gains Speed set to: ${ExpGainsSpeed[speed]} (=${speed})` ); + } + private log(...params: any[]) { console.log("Settings:", ...params); } diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index cdf0ad41057..46bb757c867 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -60,6 +60,7 @@ export interface PromptHandler { expireFn?: () => void; awaitingActionInput?: boolean; } +import { ExpPhase } from "#app/phases/exp-phase"; export default class PhaseInterceptor { public scene; @@ -127,7 +128,8 @@ export default class PhaseInterceptor { [MysteryEncounterRewardsPhase, this.startPhase], [PostMysteryEncounterPhase, this.startPhase], [ModifierRewardPhase, this.startPhase], - [PartyExpPhase, this.startPhase] + [PartyExpPhase, this.startPhase], + [ExpPhase, this.startPhase], ]; private endBySetMode = [ diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index c7b82dc826e..8e7e5bc4060 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -11,8 +11,11 @@ import { Stat } from "#enums/stat"; import BattleFlyout from "./battle-flyout"; import { WindowVariant, addWindow } from "./ui-theme"; import i18next from "i18next"; +import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; export default class BattleInfo extends Phaser.GameObjects.Container { + public static readonly EXP_GAINS_DURATION_BASE = 1650; + private baseY: number; private player: boolean; @@ -702,7 +705,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { instant = true; } const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")(1 - (Math.max(this.lastLevel - 100, 0) / 150)); - const duration = this.visible && !instant ? (((levelExp - this.lastLevelExp) / relLevelExp) * 1650) * durationMultiplier * levelDurationMultiplier : 0; + let duration = this.visible && !instant ? (((levelExp - this.lastLevelExp) / relLevelExp) * BattleInfo.EXP_GAINS_DURATION_BASE) * durationMultiplier * levelDurationMultiplier : 0; + const speed = (this.scene as BattleScene).expGainsSpeed; + if (speed && speed >= ExpGainsSpeed.DEFAULT) { + duration = speed >= ExpGainsSpeed.SKIP ? ExpGainsSpeed.DEFAULT : duration / Math.pow(2, speed); + } if (ratio === 1) { this.lastLevelExp = 0; this.lastLevel++; From 9f8e9de9676ae965af8e5d5275375cb03a58f3ff Mon Sep 17 00:00:00 2001 From: DanStevensonx <114961842+DanStevensonx@users.noreply.github.com> Date: Sun, 15 Sep 2024 01:12:05 +0200 Subject: [PATCH 5/8] Update menu.json (#4258) Added a line-break to the server connection error in Spanish --- src/locales/es/menu.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/es/menu.json b/src/locales/es/menu.json index ef1ae93dd82..a35025819fa 100644 --- a/src/locales/es/menu.json +++ b/src/locales/es/menu.json @@ -51,7 +51,7 @@ "renamePokemon": "Renombrar Pokémon.", "rename": "Renombrar", "nickname": "Apodo", - "errorServerDown": "¡Ups! Ha habido un problema al contactar con el servidor.\n\nPuedes mantener esta ventana abierta, el juego se reconectará automáticamente.", + "errorServerDown": "¡Ups! Ha habido un problema al contactar con el servidor.\n\nPuedes mantener esta ventana abierta,\nel juego se reconectará automáticamente.", "noSaves": "No tienes ninguna partida guardada registrada!", "tooManySaves": "¡Tienes demasiadas partidas guardadas registradas!" } From aecdcd34f55520c7d7226ded792901fec312fe76 Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Sun, 15 Sep 2024 01:12:55 +0200 Subject: [PATCH 6/8] [BUG] Fix a couple of bugs regarding MEs and their localization (#4261) * Fixed SURF and FLY not beeing localized in "lost at sea" Fixed Mysterious Challenger Title not beeing correct Fixed Winstrate Names not beeing localized * Revert the winstrate fix. It breaks other trainer battles for some reason... * A new way of giving the winstrates localized names (and for the future all named trainers that dont use a "initFor" method) * Updated test (with ok from ImperialSympathizer) * Made the expected value simpler * FLY and SURF can be localized much simpler --- .../encounters/lost-at-sea-encounter.ts | 5 ++-- .../mysterious-challengers-encounter.ts | 1 + src/data/trainer-config.ts | 27 +++++++++++++++---- .../encounters/lost-at-sea-encounter.test.ts | 6 ++--- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts index 0f0538d7542..16568d8cb7d 100644 --- a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts +++ b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts @@ -10,6 +10,7 @@ import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encount import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import {PokemonMove} from "#app/field/pokemon"; const OPTION_1_REQUIRED_MOVE = Moves.SURF; const OPTION_2_REQUIRED_MOVE = Moves.FLY; @@ -44,8 +45,8 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with const encounter = scene.currentBattle.mysteryEncounter!; encounter.setDialogueToken("damagePercentage", String(DAMAGE_PERCENTAGE)); - encounter.setDialogueToken("option1RequiredMove", Moves[OPTION_1_REQUIRED_MOVE]); - encounter.setDialogueToken("option2RequiredMove", Moves[OPTION_2_REQUIRED_MOVE]); + encounter.setDialogueToken("option1RequiredMove", new PokemonMove(OPTION_1_REQUIRED_MOVE).getName()); + encounter.setDialogueToken("option2RequiredMove", new PokemonMove(OPTION_2_REQUIRED_MOVE).getName()); return true; }) diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index 230f5242a36..71a44bd6852 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -87,6 +87,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = ); const e4Template = trainerPartyTemplates.ELITE_FOUR; const brutalConfig = trainerConfigs[brutalTrainerType].clone(); + brutalConfig.title = trainerConfigs[brutalTrainerType].title; brutalConfig.setPartyTemplates(e4Template); // @ts-ignore brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 0323c6d43c4..8b96e3cefb8 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -255,7 +255,9 @@ export class TrainerConfig { name = i18next.t("trainerNames:rival"); } } + this.name = name; + return this; } @@ -899,6 +901,20 @@ export class TrainerConfig { return this; } + /** + * Sets a localized name for the trainer. This should only be used for trainers that dont use a "initFor" function and are considered "named" trainers + * @param name - The name of the trainer. + * @returns {TrainerConfig} The updated TrainerConfig instance. + */ + setLocalizedName(name: string): TrainerConfig { + // Check if the internationalization (i18n) system is initialized. + if (!getIsInitialized()) { + initI18n(); + } + this.name = i18next.t(`trainerNames:${name.toLowerCase()}`); + return this; + } + /** * Retrieves the title for the trainer based on the provided trainer slot and variant. * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. @@ -2270,21 +2286,22 @@ export const trainerConfigs: TrainerConfigs = { } p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.VICTOR]: new TrainerConfig(++t).setName("Victor").setTitle("The Winstrates") + [TrainerType.VICTOR]: new TrainerConfig(++t).setTitle("The Winstrates").setLocalizedName("Victor") .setMoneyMultiplier(1) // The Winstrate trainers have total money multiplier of 6 .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), - [TrainerType.VICTORIA]: new TrainerConfig(++t).setName("Victoria").setTitle("The Winstrates") + [TrainerType.VICTORIA]: new TrainerConfig(++t).setTitle("The Winstrates").setLocalizedName("Victoria") .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG), - [TrainerType.VIVI]: new TrainerConfig(++t).setName("Vivi").setTitle("The Winstrates") + [TrainerType.VIVI]: new TrainerConfig(++t).setTitle("The Winstrates").setLocalizedName("Vivi") .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.TWO_AVG_ONE_STRONG), - [TrainerType.VICKY]: new TrainerConfig(++t).setName("Vicky").setTitle("The Winstrates") + [TrainerType.VICKY]: new TrainerConfig(++t).setTitle("The Winstrates").setLocalizedName("Vicky") .setMoneyMultiplier(1) .setPartyTemplates(trainerPartyTemplates.ONE_AVG), - [TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates") + [TrainerType.VITO]: new TrainerConfig(++t).setTitle("The Winstrates").setLocalizedName("Vito") .setMoneyMultiplier(2) .setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG))), [TrainerType.BUG_TYPE_SUPERFAN]: new TrainerConfig(++t).setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER) .setPartyTemplates(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE)) }; + diff --git a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts index 5d43172f6c0..82670e32daa 100644 --- a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts @@ -3,7 +3,6 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encount import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Biome } from "#app/enums/biome"; -import { Moves } from "#app/enums/moves"; import { MysteryEncounterType } from "#app/enums/mystery-encounter-type"; import { Species } from "#app/enums/species"; import GameManager from "#app/test/utils/gameManager"; @@ -16,6 +15,7 @@ import BattleScene from "#app/battle-scene"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; import { PartyExpPhase } from "#app/phases/party-exp-phase"; + const namespace = "mysteryEncounter:lostAtSea"; /** Blastoise for surf. Pidgeot for fly. Abra for none. */ const defaultParty = [Species.BLASTOISE, Species.PIDGEOT, Species.ABRA]; @@ -102,8 +102,8 @@ describe("Lost at Sea - Mystery Encounter", () => { const onInitResult = onInit!(scene); expect(LostAtSeaEncounter.dialogueTokens?.damagePercentage).toBe("25"); - expect(LostAtSeaEncounter.dialogueTokens?.option1RequiredMove).toBe(Moves[Moves.SURF]); - expect(LostAtSeaEncounter.dialogueTokens?.option2RequiredMove).toBe(Moves[Moves.FLY]); + expect(LostAtSeaEncounter.dialogueTokens?.option1RequiredMove).toBe("Surf"); + expect(LostAtSeaEncounter.dialogueTokens?.option2RequiredMove).toBe("Fly"); expect(onInitResult).toBe(true); }); From d8dbc471af17fe1643c7d857579b4ebd9e7e1e11 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 14 Sep 2024 16:13:32 -0700 Subject: [PATCH 7/8] [Bug][Beta] Fix Pokemon info flyout being offset on switchout after double battle (#4260) --- src/field/pokemon.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index faae3b06ba0..088d11abf90 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -592,8 +592,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Resetting properties should not be shown on the field this.setVisible(false); - // Reset field position - this.setFieldPosition(FieldPosition.CENTER); + // Remove the offset from having a Substitute active if (this.isOffsetBySubstitute()) { this.x -= this.getSubstituteOffset()[0]; this.y -= this.getSubstituteOffset()[1]; From 79fa80cfd8a20a45308311c478a2be7b48c71246 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 14 Sep 2024 16:14:37 -0700 Subject: [PATCH 8/8] [Bug][Beta] Fix error in message sequencing on critical hits (#4259) --- src/field/pokemon.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 088d11abf90..453bce71503 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2620,10 +2620,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return result; } - if (isCritical) { - this.scene.queueMessage(i18next.t("battle:hitResultCriticalHit")); - } - // In case of fatal damage, this tag would have gotten cleared before we could lapse it. const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND); @@ -2666,6 +2662,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } + if (isCritical) { + this.scene.queueMessage(i18next.t("battle:hitResultCriticalHit")); + } + // want to include is.Fainted() in case multi hit move ends early, still want to render message if (source.turnData.hitsLeft === 1 || this.isFainted()) { switch (result) {