Merge branch 'beta' into substitute

This commit is contained in:
innerthunder 2024-08-09 12:16:38 -07:00
commit 8b176f9967
77 changed files with 1051 additions and 1727 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

View File

@ -486,7 +486,8 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
const fetchAnimAndResolve = (move: Moves) => {
scene.cachedFetch(`./battle-anims/${moveName}.json`)
.then(response => {
if (!response.ok) {
const contentType = response.headers.get("content-type");
if (!response.ok || contentType?.indexOf("application/json") === -1) {
console.error(`Could not load animation file for move '${moveName}'`, response.status, response.statusText);
populateMoveAnim(move, moveAnims.get(defaultMoveAnim));
return resolve();

View File

@ -2826,6 +2826,11 @@ export class InvertStatsAttr extends MoveEffectAttr {
}
export class ResetStatsAttr extends MoveEffectAttr {
private targetAllPokemon: boolean;
constructor(targetAllPokemon: boolean) {
super();
this.targetAllPokemon = targetAllPokemon;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args)) {
return false;
@ -2835,16 +2840,24 @@ export class ResetStatsAttr extends MoveEffectAttr {
return false;
}
for (let s = 0; s < target.summonData.battleStats.length; s++) {
target.summonData.battleStats[s] = 0;
}
target.updateInfo();
user.updateInfo();
if (this.targetAllPokemon) { // Target all pokemon on the field when Freezy Frost or Haze are used
const activePokemon = user.scene.getField(true);
activePokemon.forEach(p => this.resetStats(p));
target.scene.queueMessage(i18next.t("moveTriggers:statEliminated"));
} else { // Affects only the single target when Clear Smog is used
this.resetStats(target);
target.scene.queueMessage(i18next.t("moveTriggers:resetStats", {pokemonName: getPokemonNameWithAffix(target)}));
}
return true;
}
resetStats(pokemon: Pokemon) {
for (let s = 0; s < pokemon.summonData.battleStats.length; s++) {
pokemon.summonData.battleStats[s] = 0;
}
pokemon.updateInfo();
}
}
/**
@ -6576,10 +6589,9 @@ export function initMoves() {
new StatusMove(Moves.LIGHT_SCREEN, Type.PSYCHIC, -1, 30, -1, 0, 1)
.attr(AddArenaTagAttr, ArenaTagType.LIGHT_SCREEN, 5, true)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.HAZE, Type.ICE, -1, 30, -1, 0, 1)
new SelfStatusMove(Moves.HAZE, Type.ICE, -1, 30, -1, 0, 1)
.ignoresSubstitute()
.target(MoveTarget.BOTH_SIDES)
.attr(ResetStatsAttr),
.attr(ResetStatsAttr, true),
new StatusMove(Moves.REFLECT, Type.PSYCHIC, -1, 20, -1, 0, 1)
.attr(AddArenaTagAttr, ArenaTagType.REFLECT, 5, true)
.target(MoveTarget.USER_SIDE),
@ -7687,7 +7699,7 @@ export function initMoves() {
new AttackMove(Moves.CHIP_AWAY, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 5)
.attr(IgnoreOpponentStatChangesAttr),
new AttackMove(Moves.CLEAR_SMOG, Type.POISON, MoveCategory.SPECIAL, 50, -1, 15, -1, 0, 5)
.attr(ResetStatsAttr),
.attr(ResetStatsAttr, false),
new AttackMove(Moves.STORED_POWER, Type.PSYCHIC, MoveCategory.SPECIAL, 20, 100, 10, -1, 0, 5)
.attr(StatChangeCountPowerAttr),
new StatusMove(Moves.QUICK_GUARD, Type.FIGHTING, -1, 15, -1, 3, 5)
@ -8408,7 +8420,7 @@ export function initMoves() {
.makesContact(false)
.attr(AddBattlerTagAttr, BattlerTagType.SEEDED),
new AttackMove(Moves.FREEZY_FROST, Type.ICE, MoveCategory.SPECIAL, 100, 90, 10, -1, 0, 7)
.attr(ResetStatsAttr),
.attr(ResetStatsAttr, true),
new AttackMove(Moves.SPARKLY_SWIRL, Type.FAIRY, MoveCategory.SPECIAL, 120, 85, 5, -1, 0, 7)
.attr(PartyStatusCureAttr, null, Abilities.NONE),
new AttackMove(Moves.VEEVEE_VOLLEY, Type.NORMAL, MoveCategory.PHYSICAL, -1, -1, 20, -1, 0, 7)

View File

@ -2631,7 +2631,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.CHIKORITA]: [
[ 1, Moves.TACKLE ],
[ 1, Moves.GROWL ],
[ 6, Moves.RAZOR_LEAF ],
[ 5, Moves.RAZOR_LEAF ], //Custom, moved from 6 to 5
[ 9, Moves.POISON_POWDER ],
[ 12, Moves.SYNTHESIS ],
[ 17, Moves.REFLECT ],
@ -2681,8 +2681,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.CYNDAQUIL]: [
[ 1, Moves.TACKLE ],
[ 1, Moves.LEER ],
[ 6, Moves.SMOKESCREEN ],
[ 10, Moves.EMBER ],
[ 5, Moves.EMBER ], //Custom, moved to 5
[ 10, Moves.SMOKESCREEN ], //Custom, moved to 10
[ 13, Moves.QUICK_ATTACK ],
[ 19, Moves.FLAME_WHEEL ],
[ 22, Moves.DEFENSE_CURL ],
@ -2736,7 +2736,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.TOTODILE]: [
[ 1, Moves.SCRATCH ],
[ 1, Moves.LEER ],
[ 6, Moves.WATER_GUN ],
[ 5, Moves.WATER_GUN ], //Custom, moved from 6 to 5
[ 9, Moves.BITE ],
[ 13, Moves.SCARY_FACE ],
[ 19, Moves.ICE_FANG ],
@ -6723,7 +6723,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.TURTWIG]: [
[ 1, Moves.TACKLE ],
[ 5, Moves.WITHDRAW ],
[ 9, Moves.ABSORB ],
[ 5, Moves.ABSORB ], //Custom, moved from 9 to 5
[ 13, Moves.RAZOR_LEAF ],
[ 17, Moves.CURSE ],
[ 21, Moves.BITE ],
@ -6768,7 +6768,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.CHIMCHAR]: [
[ 1, Moves.SCRATCH ],
[ 1, Moves.LEER ],
[ 7, Moves.EMBER ],
[ 5, Moves.EMBER ], //Custom, moved from 7 to 5
[ 9, Moves.TAUNT ],
[ 15, Moves.FURY_SWIPES ],
[ 17, Moves.FLAME_WHEEL ],
@ -6817,7 +6817,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.PIPLUP]: [
[ 1, Moves.POUND ],
[ 4, Moves.GROWL ],
[ 8, Moves.WATER_GUN ],
[ 5, Moves.WATER_GUN ], //Custom, moved from 8 to 5
[ 11, Moves.CHARM ],
[ 15, Moves.PECK ],
[ 18, Moves.BUBBLE_BEAM ],
@ -8591,7 +8591,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.SNIVY]: [
[ 1, Moves.TACKLE ],
[ 4, Moves.LEER ],
[ 7, Moves.VINE_WHIP ],
[ 5, Moves.VINE_WHIP ], //Custom, moved from 7 to 5
[ 10, Moves.WRAP ],
[ 13, Moves.GROWTH ],
[ 16, Moves.MAGICAL_LEAF ],
@ -8639,7 +8639,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.TEPIG]: [
[ 1, Moves.TACKLE ],
[ 3, Moves.TAIL_WHIP ],
[ 7, Moves.EMBER ],
[ 5, Moves.EMBER ], //Custom, moved from 7 to 5
[ 9, Moves.ENDURE ],
[ 13, Moves.DEFENSE_CURL ],
[ 15, Moves.FLAME_CHARGE ],
@ -8693,7 +8693,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.OSHAWOTT]: [
[ 1, Moves.TACKLE ],
[ 5, Moves.TAIL_WHIP ],
[ 7, Moves.WATER_GUN ],
[ 5, Moves.WATER_GUN ], //Custom, moved from 7 to 5
[ 11, Moves.SOAK ],
[ 13, Moves.FOCUS_ENERGY ],
[ 17, Moves.RAZOR_SHELL ],
@ -13850,11 +13850,11 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[ 99, Moves.CLOSE_COMBAT ],
],
[Species.POIPOLE]: [
[ RELEARN_MOVE, Moves.DRAGON_PULSE ], //Custom, made relearn
[ 1, Moves.GROWL ],
[ 1, Moves.ACID ],
[ 1, Moves.PECK ],
[ 1, Moves.HELPING_HAND ],
[ 1, Moves.DRAGON_PULSE ],
[ 7, Moves.FURY_ATTACK ],
[ 14, Moves.FELL_STINGER ],
[ 21, Moves.CHARM ],
@ -13969,7 +13969,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.GROOKEY]: [
[ 1, Moves.SCRATCH ],
[ 1, Moves.GROWL ],
[ 6, Moves.BRANCH_POKE ],
[ 5, Moves.BRANCH_POKE ], //Custom, moved from 6 to 5
[ 8, Moves.TAUNT ],
[ 12, Moves.RAZOR_LEAF ],
[ 17, Moves.SCREECH ],
@ -14014,7 +14014,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.SCORBUNNY]: [
[ 1, Moves.TACKLE ],
[ 1, Moves.GROWL ],
[ 6, Moves.EMBER ],
[ 5, Moves.EMBER ], //Custom, moved from 6 to 5
[ 8, Moves.QUICK_ATTACK ],
[ 12, Moves.DOUBLE_KICK ],
[ 17, Moves.FLAME_CHARGE ],
@ -14056,7 +14056,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[Species.SOBBLE]: [
[ 1, Moves.POUND ],
[ 1, Moves.GROWL ],
[ 6, Moves.WATER_GUN ],
[ 5, Moves.WATER_GUN ], //Custom, moved from 6 to 5
[ 8, Moves.BIND ],
[ 12, Moves.WATER_PULSE ],
[ 17, Moves.TEARFUL_LOOK ],

View File

@ -115,11 +115,11 @@ export function getRandomStatusEffect(statusEffectA: StatusEffect, statusEffectB
* @param statusA The first Status
* @param statusB The second Status
*/
export function getRandomStatus(statusA: Status, statusB: Status): Status {
if (statusA === undefined || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) {
export function getRandomStatus(statusA: Status | null, statusB: Status | null): Status | null {
if (!statusA || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) {
return statusB;
}
if (statusB === undefined || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) {
if (!statusB || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) {
return statusA;
}

View File

@ -3690,7 +3690,7 @@ export class PlayerPokemon extends Pokemon {
if (!this.isFainted()) {
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
this.hp = Math.min(this.hp, this.stats[Stat.HP]);
this.status = getRandomStatus(this.status!, pokemon.status!); // Get a random valid status between the two // TODO: are the bangs correct?
this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two
} else if (!pokemon.isFainted()) {
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
this.hp = Math.max(this.hp, 1);

View File

@ -93,6 +93,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("shiny_star_small", "ui", "shiny_small.png");
this.loadImage("shiny_star_small_1", "ui", "shiny_small_1.png");
this.loadImage("shiny_star_small_2", "ui", "shiny_small_2.png");
this.loadImage("favorite", "ui", "favorite.png");
this.loadImage("passive_bg", "ui", "passive_bg.png");
this.loadAtlas("shiny_icons", "ui");
this.loadImage("ha_capsule", "ui", "ha_capsule.png");

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ribbon",
"hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!",
"invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!",
"resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!",
"statEliminated": "All stat changes were eliminated!",
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Toggle IVs",
"manageMoves": "Manage Moves",
"manageNature": "Manage Nature",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Use Candies",
"selectNature": "Select nature.",
"selectMoveSwapOut": "Select a move to swap out.",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Band",
"hasWon": "Hat Klassik-Modus gewonnen",
"hasNotWon": "Hat Klassik-Modus nicht gewonnen",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "Das Heilopfer von {{pokemonName}} erreicht sein Ziel!",
"invertStats": "Alle Statusveränderungen von {{pokemonName}} wurden invertiert!",
"resetStats": "Die Statusveränderungen von {{pokemonName}} wurden aufgehoben!",
"statEliminated": "Alle Statusveränderungen wurden aufgehoben!",
"faintCountdown": "{{pokemonName}} geht nach {{turnCount}} Runden K.O.!",
"copyType": "{{pokemonName}} hat den Typ von {{targetPokemonName}} angenommen!",
"suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "DVs anzeigen/verbergen",
"manageMoves": "Attacken ändern",
"manageNature": "Wesen ändern",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Bonbons verwenden",
"selectNature": "Wähle das neue Wesen.",
"selectMoveSwapOut": "Wähle die zu ersetzende Attacke.",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ribbon",
"hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!",
"invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!",
"resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!",
"statEliminated": "All stat changes were eliminated!",
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Toggle IVs",
"manageMoves": "Manage Moves",
"manageNature": "Manage Nature",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Use Candies",
"selectNature": "Select nature.",
"selectMoveSwapOut": "Select a move to swap out.",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ribbon",
"hasWon": "Ya ha ganado",
"hasNotWon": "Aún no ha ganado",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!",
"invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!",
"resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!",
"statEliminated": "¡Los cambios en estadísticas fueron eliminados!",
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type\nchanged to match {{targetPokemonName}}'s!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Mostrar IVs",
"manageMoves": "Cambiar movs.",
"manageNature": "Cambiar natur.",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Usar Caramelos",
"selectNature": "Elige Natur.",
"selectMoveSwapOut": "Elige el movimiento que sustituir.",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ruban",
"hasWon": "Ruban - Oui",
"hasNotWon": "Ruban - Non",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "Le Vœu Soin est exaucé et profite\nà {{pokemonName}} !",
"invertStats": "Les changements de stats\nde {{pokemonName}} sont inversés !",
"resetStats": "Les changements de stats\nde {{pokemonName}} ont tous été annulés !",
"statEliminated": "Les changements de stats ont tous été annulés !",
"faintCountdown": "{{pokemonName}}\nsera K.O. dans {{turnCount}} tours !",
"copyType": "{{pokemonName}} prend le type\nde {{targetPokemonName}} !",
"suppressAbilities": "Le talent de {{pokemonName}}\na été rendu inactif !",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Voir les IV",
"manageMoves": "Modifier les Capacités",
"manageNature": "Modifier la Nature",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Utiliser des Bonbons",
"selectNature": "Sélectionnez une nature.",
"selectMoveSwapOut": "Sélectionnez la capacité à échanger.",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ribbon",
"hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}} riceve i benefici\neffetti di Curardore!",
"invertStats": "Le modifiche alle statistiche di {{pokemonName}}\nvengono invertite!",
"resetStats": "Tutte le modifiche alle statistiche sono state annullate!",
"statEliminated": "All stat changes were eliminated!",
"faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.",
"copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!",
"suppressAbilities": "Labilità di {{pokemonName}}\nperde ogni efficacia!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Vedi/Nascondi IV",
"manageMoves": "Gestisci mosse",
"manageNature": "Gestisci natura",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Usa caramelle",
"selectNature": "Seleziona natura.",
"selectMoveSwapOut": "Seleziona una mossa da scambiare.",

View File

@ -1,159 +1,159 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battle: SimpleTranslationEntries = {
"bossAppeared": "{{bossName}}が あらわれた!",
"trainerAppeared": "{{trainerName}}が\nしょうぶを しかけてきた!",
"trainerAppearedDouble": "{{trainerName}}が\nしょうぶを しかけてきた!",
"trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を くりだした!",
"singleWildAppeared": "あっ! やせいの\n{{pokemonName}}が とびだしてきた!",
"multiWildAppeared": "あっ! やせいの {{pokemonName1}}と\n{{pokemonName2}}が とびだしてきた!",
"playerComeBack": "{{pokemonName}}! もどれ!",
"trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を ひっこめた!",
"bossAppeared": "{{bossName}}が 現れた!",
"trainerAppeared": "{{trainerName}}が\n勝負を しかけてきた!",
"trainerAppearedDouble": "{{trainerName}}が\n勝負を しかけてきた!",
"trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!",
"singleWildAppeared": "あっ! 野生の {{pokemonName}}が 飛び出してきた!",
"multiWildAppeared": "あっ! 野生の {{pokemonName1}}と\n{{pokemonName2}}が 飛び出してきた!",
"playerComeBack": "{{pokemonName}}! 戻れ!",
"trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を 引っ込めた!",
"playerGo": "ゆけっ! {{pokemonName}}",
"trainerGo": "{{trainerName}}は\n{{pokemonName}}を くりだした!",
"switchQuestion": "{{pokemonName}}を\nいれかえますか?",
"trainerDefeated": "{{trainerName}}\nとの しょうぶに かった!",
"moneyWon": "しょうきんとして\n₽{{moneyAmount}} てにいれた!",
"moneyPickedUp": "₽{{moneyAmount}}を ひろった!",
"pokemonCaught": "{{pokemonName}}を\nつかまえたぞ!",
"addedAsAStarter": "{{pokemonName}} has been\nadded as a starter!",
"partyFull": "てもちがいっぱいです。\n{{pokemonName}}をいれるために ポケモンを ひとり てばなしますか?",
"trainerGo": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!",
"switchQuestion": "{{pokemonName}}を\n入れ替えますか?",
"trainerDefeated": "{{trainerName}} との 勝負に 勝った!",
"moneyWon": "賞金として ₽{{moneyAmount}}を 手に入れた!",
"moneyPickedUp": "₽{{moneyAmount}}を った!",
"pokemonCaught": "{{pokemonName}}を 捕まえたぞ!",
"addedAsAStarter": "今から {{pokemonName}}は 最初のパートナーとして 選べられる!",
"partyFull": "手持ちが いっぱいです。\n{{pokemonName}}を入れる ために ポケモンを 一つ 逃がすか?",
"pokemon": "ポケモン",
"sendOutPokemon": "がんばれ! {{pokemonName}}",
"hitResultCriticalHit": "きゅうしょに あたった!",
"hitResultSuperEffective": "こうかは ばつぐんだ!",
"hitResultNotVeryEffective": "こうかは いまひとつの ようだ……",
"hitResultNoEffect": "{{pokemonName}}には こうかが ないようだ…",
"hitResultOneHitKO": "いちげき ひっさつ",
"attackFailed": "しかし うまく きまらなかった!!",
"attackMissed": "{{pokemonNameWithAffix}}にはたらなかった!",
"attackHitsCount": "{{count}}かい たった!",
"rewardGain": "{{modifierName}}を\nてにいれた!",
"expGain": "{{pokemonName}}は\n{{exp}}けいけんちを もらった!",
"levelUp": "{{pokemonName}}は\nレベル{{level}} に あがった!",
"learnMove": "{{pokemonName}}は あたらしく\n{{moveName}}を おぼえた!",
"learnMovePrompt": "{{pokemonName}}は あたらしく\n{{moveName}}を おぼえたい……",
"learnMoveLimitReached": "しかし {{pokemonName}}は わざを 4つ\nおぼえるので せいいっぱいだ!",
"learnMoveReplaceQuestion": "{{moveName}}の かわりに\nほかの わざを わすれさせますか?",
"learnMoveStopTeaching": "それでは…… {{moveName}}を\nおぼえるのを あきらめますか?",
"learnMoveNotLearned": "{{pokemonName}}は {{moveName}}を\nおぼえずに おわった!",
"learnMoveForgetQuestion": "どの わざを\nわすれさせたい?",
"learnMoveForgetSuccess": "{{pokemonName}}は {{moveName}}の\nつかいかたを きれいに わすれた!",
"sendOutPokemon": "頑張れ! {{pokemonName}}",
"hitResultCriticalHit": "急所に 当たった!",
"hitResultSuperEffective": "効果は バツグンだ!",
"hitResultNotVeryEffective": "効果は 今ひとつの ようだ……",
"hitResultNoEffect": "{{pokemonName}}には 効果が ないようだ…",
"hitResultOneHitKO": "一撃必殺",
"attackFailed": "しかし うまく 決まらなかった!!",
"attackMissed": "{{pokemonNameWithAffix}}には 当たらなかった!",
"attackHitsCount": "{{count}}かい たった!",
"rewardGain": "{{modifierName}}を 手に入れた!",
"expGain": "{{pokemonName}}は\n{{exp}}経験値を もらった!",
"levelUp": "{{pokemonName}}は\nレベル{{level}}に 上がった!",
"learnMove": "{{pokemonName}}は 新しく\n{{moveName}}を 覚えた!",
"learnMovePrompt": "{{pokemonName}}は 新しく\n{{moveName}}を 覚えたい……",
"learnMoveLimitReached": "しかし {{pokemonName}}は 技を 4つ\n覚えるので せいいっぱいだ!",
"learnMoveReplaceQuestion": "{{moveName}}の 代わりに\n他の 技を れさせますか?",
"learnMoveStopTeaching": "それでは {{moveName}}を\n覚えるのを 諦めますか?",
"learnMoveNotLearned": "{{pokemonName}}は {{moveName}}を\n覚えずに わった!",
"learnMoveForgetQuestion": "どの 技を\n忘れさせたい?",
"learnMoveForgetSuccess": "{{pokemonName}}は {{moveName}}の\n使い方を きれいに れた!",
"countdownPoof": "@d{32}1 @d{15}2の @d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}ポカン!",
"learnMoveAnd": "そして…",
"levelCapUp": "レベルキャップの\n{{levelCap}}にがった!",
"moveNotImplemented": "{{moveName}}は まだじっそうされておらず、せんたくできません。",
"moveNoPP": "しかし わざの\nのこりポイントが なかった!",
"moveDisabled": "かなしばりで\n{{moveName}}が せない!",
"noPokeballForce": "みえない ちからの せいで\nボールを げられない!",
"noPokeballTrainer": "ひとのものを\nとったら どろぼう",
"noPokeballMulti": "あいての ポケモンが ひとつしか\n いないまえに ボールが つかえない!",
"noPokeballStrong": "あいての ポケモンが つよすぎて つかまえられない!\nまずは よわらせよう!",
"noEscapeForce": "みえない ちからの せいで\nにげることが できない!",
"noEscapeTrainer": "ダメだ! しょうぶのさいちゅうに\nあいてに せなかを みせられない!",
"noEscapePokemon": "{{pokemonName}}の {{moveName}}で {{escapeVerb}}!",
"runAwaySuccess": " うまく にげきれた!",
"runAwayCannotEscape": "にげることが できない!",
"escapeVerbSwitch": "いれかえることが できない",
"escapeVerbFlee": "にげることが できない",
"notDisabled": "{{pokemonName}}の かなしばりが とけた!\nまた {{moveName}}が つかえられる!",
"turnEndHpRestore": "{{pokemonName}}の たいりょくが かいふくした!",
"hpIsFull": "{{pokemonName}}の\nHPが まんたんだ!",
"skipItemQuestion": "ほんとに アイテムを とらない",
"levelCapUp": "レベルキャップの\n{{levelCap}}に 上がった!",
"moveNotImplemented": "{{moveName}}は まだ 実装されておらず 選択できません。",
"moveNoPP": "しかし 技の\n残りポイントが なかった!",
"moveDisabled": "かなしばりで\n{{moveName}}が せない!",
"noPokeballForce": "見えない 力の せいで\nボールが げられない!",
"noPokeballTrainer": "人の ものを 取ったら 泥棒",
"noPokeballMulti": "相手の ポケモンが 一つしか\nいない 前に ボールが 使えない!",
"noPokeballStrong": "相手の ポケモンが 強すぎて 捕まえられない!\nまずは 弱めよう!",
"noEscapeForce": "見えない 力の せいで\n逃げることが できない!",
"noEscapeTrainer": "ダメだ! 勝負の最中に\n相手に 背中を せられない!",
"noEscapePokemon": "{{pokemonName}}の {{moveName}}で {{escapeVerb}}!",
"runAwaySuccess": " うまく 逃げ切れた!",
"runAwayCannotEscape": "逃げることが できない!",
"escapeVerbSwitch": "入れ替えることが できない",
"escapeVerbFlee": "逃げることが できない",
"notDisabled": "{{pokemonName}}の かなしばりが 溶けた!\nまた {{moveName}}が 使えられる!",
"turnEndHpRestore": "{{pokemonName}}の 体力が 回復した!",
"hpIsFull": "{{pokemonName}}の\n体力が 満タンだ!",
"skipItemQuestion": "本当に アイテムを 取らずに 進みますか",
"eggHatching": "おや?",
"ivScannerUseQuestion": "{{pokemonName}}を\nこたいちスキャナーで そうさする?",
"wildPokemonWithAffix": "やせいの {{pokemonName}}",
"foePokemonWithAffix": "あいての {{pokemonName}}",
"useMove": "{{pokemonNameWithAffix}}の {{moveName}}",
"drainMessage": "{{pokemonName}}から\nたいりょくを すいとった!",
"regainHealth": "{{pokemonName}}は\nたいりょくを かいふくした!",
"stealEatBerry": "{{pokemonName}}は {{targetName}}の\n{{berryName}}を うばって たべた!",
"ppHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で {{moveName}}のPPを かいふくした!",
"hpHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で たいりょくを かいふくした!",
"fainted": "{{pokemonNameWithAffix}}は たおれた!",
"ivScannerUseQuestion": "{{pokemonName}}を\n個体値スキャナーで 操作しますか?",
"wildPokemonWithAffix": "野生の {{pokemonName}}",
"foePokemonWithAffix": "相手の {{pokemonName}}",
"useMove": "{{pokemonNameWithAffix}}の {{moveName}}",
"drainMessage": "{{pokemonName}}から\n体力を 吸い取った!",
"regainHealth": "{{pokemonName}}は\n体力を 回復した!",
"stealEatBerry": "{{pokemonName}}は {{targetName}}の\n{{berryName}}を うばって 食べた!",
"ppHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で {{moveName}}のPPを 回復した!",
"hpHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で 体力を 回復した!",
"fainted": "{{pokemonNameWithAffix}}は 倒れた!",
"statsAnd": "と ",
"stats": "のうりょく",
"statRose_one": "{{pokemonNameWithAffix}}の {{stats}}が がった!",
"statRose_other": "{{pokemonNameWithAffix}}の {{stats}}が がった!",
"statSharplyRose_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと あがった!",
"statSharplyRose_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと あがった!",
"statRoseDrastically_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと あがった!",
"statRoseDrastically_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと あがった!",
"statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}の {{stats}}が もう あがらない!",
"statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}の {{stats}}が もう あがらない!",
"statFell_one": "{{pokemonNameWithAffix}}の {{stats}}が さがった!",
"statFell_other": "{{pokemonNameWithAffix}}の {{stats}}が さがった!",
"statHarshlyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくっと さがった!",
"statHarshlyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくっと さがった!",
"statSeverelyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと さがった!",
"statSeverelyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと さがった!",
"statWontGoAnyLower_one": "{{pokemonNameWithAffix}}の {{stats}}が もう さがらない!",
"statWontGoAnyLower_other": "{{pokemonNameWithAffix}}の {{stats}}が もう さがらない!",
"transformedIntoType": "{{pokemonName}}は\n{{type}}タイプに へんしんした!",
"retryBattle": "このせんとうの はじまりから やりなおす",
"stats": "能力",
"statRose_one": "{{pokemonNameWithAffix}}の {{stats}}が がった!",
"statRose_other": "{{pokemonNameWithAffix}}の {{stats}}が がった!",
"statSharplyRose_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと 上がった!",
"statSharplyRose_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと 上がった!",
"statRoseDrastically_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと 上がった!",
"statRoseDrastically_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと 上がった!",
"statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}の {{stats}}が もう 上がらない!",
"statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}の {{stats}}が もう 上がらない!",
"statFell_one": "{{pokemonNameWithAffix}}の {{stats}}が 下がった!",
"statFell_other": "{{pokemonNameWithAffix}}の {{stats}}が 下がった!",
"statHarshlyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくっと 下がった!",
"statHarshlyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくっと 下がった!",
"statSeverelyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと 下がった!",
"statSeverelyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと 下がった!",
"statWontGoAnyLower_one": "{{pokemonNameWithAffix}}の {{stats}}が もう 下がらない!",
"statWontGoAnyLower_other": "{{pokemonNameWithAffix}}の {{stats}}が もう 下がらない!",
"transformedIntoType": "{{pokemonName}}は\n{{type}}タイプに 変身した!",
"retryBattle": "このバトルの 始まりから やり直しますか",
"unlockedSomething": "{{unlockedThing}}\nを アンロックした",
"congratulations": "おめでとうございます!!",
"beatModeFirstTime": "はじめて {{speciesName}}が {{gameMode}}モードを クリアした!\n{{newModifier}}を てにいれた!",
"ppReduced": "{{targetName}}の {{moveName}}を {{reduction}}けずった!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}は こうげきの はんどうで うごけない!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}は もう にげられない!",
"battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}は\n{{moveName}}の こうかが とけた!",
"battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}は ひるんで わざが だせない!",
"battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}は こんらん した!",
"battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}の こんらんが とけた!",
"battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}は すでに こんらん している!",
"battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}は こんらん している!",
"battlerTagsConfusedLapseHurtItself": "わけも わからず じぶんを こうげきした!",
"beatModeFirstTime": "初めて {{speciesName}}が {{gameMode}}モードを クリアした!\n{{newModifier}}を 手に入れた!",
"ppReduced": "{{targetName}}の {{moveName}}を {{reduction}}削った!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}は 攻撃の 反動で 動けない!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}は もう 逃げられない!",
"battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}は\n{{moveName}}の 効果が 解けた!",
"battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}は ひるんで 技が出せない!",
"battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}は 混乱 した!",
"battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}の 混乱が 解けた!",
"battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}は すでに 混乱している!",
"battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}は 混乱している!",
"battlerTagsConfusedLapseHurtItself": "わけも わからず 自分を 攻撃した!",
"battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}}を みちづれに できない!",
"battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}}は あいてを みちづれに した!",
"battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロに なった!",
"battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}}は 相手を みちづれに した!",
"battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロに なった!",
"battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}}は すでに メロメロだ!",
"battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロだ!",
"battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は\nメロメロで わざが せなかった!",
"battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}は メロメロじょうたいが なおった!",
"battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}}に たねを うえつけた!",
"battlerTagsSeededLapse": "やどりぎが {{pokemonNameWithAffix}}の たいりょくを うばう!",
"battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}は ヘドロえきを すいとった!",
"battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}は あくむを みはじめた!",
"battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}は すでに うなされている!",
"battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}は あくむに うなされている!",
"battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}}は アンコールをうけた!",
"battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}の アンコールじょうたいが とけた!",
"battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}は {{pokemonName}}を\nてだすけする たいせいに はいった!",
"battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}は ねから\n ようぶんを すいとった!",
"battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}は ねを はった!",
"battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}は みずのリングを まとった!",
"battlerTagsAquaRingLapse": "{{pokemonName}}は {{moveName}}で\nたいりょくを かいふくした!",
"battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} の ねむけを さそった!",
"battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}は {{moveName}}の ダメージを けた!",
"battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に しめつけられた!",
"battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に まきつかれた!",
"battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}は うずの なかに とじこめられた!",
"battlerTagsClampOnTrap": "{{pokemonName}}は {{sourcePokemonNameWithAffix}}の\nからに はさまれた!",
"battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}は {{moveName}}に らわれた!",
"battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}は マグマの\n うずに とじこめられた!",
"battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}は トラバサミに らわれた!",
"battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}は {{pokemonNameWithAffix}}に とじこめられた!",
"battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は\nメロメロで わざが せなかった!",
"battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}は メロメロ状態が 治った!",
"battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}}に 種を 植(う)えつけた!",
"battlerTagsSeededLapse": "やどりぎが {{pokemonNameWithAffix}}の 体力を うばう!",
"battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}は ヘドロえきを 吸い取った!",
"battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}は あくむを 見始めた!",
"battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}は すでに うなされている!",
"battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}は あくむに うなされている!",
"battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}}は アンコールを 受けた!",
"battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}の アンコール状態が 解けた!",
"battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}は {{pokemonName}}を\nてだすけする 体制に った!",
"battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}は 根から\n養分ようぶん 吸い取った!",
"battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}は 根を 張った!",
"battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}は 水のリングを まとった!",
"battlerTagsAquaRingLapse": "{{pokemonName}}は {{moveName}}で\n体力を 回復した!",
"battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} の ねむけを 誘(さそ)った!",
"battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}は {{moveName}}の ダメージを けた!",
"battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に 締め付けられた!",
"battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に 巻き付かれた!",
"battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}は 渦(うず)の中に 閉じ込められた!",
"battlerTagsClampOnTrap": "{{pokemonName}}は {{sourcePokemonNameWithAffix}}の\nからに まれた!",
"battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}は {{moveName}}に らわれた!",
"battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}は マグマの\n うず 閉じ込められた!",
"battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}は トラバサミに らわれた!",
"battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}は {{pokemonNameWithAffix}}に 閉じ込められた!",
"battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonNameWithAffix}}に まとわりつかれた!",
"battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}は\nまもりの たいせいに はいった!",
"battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}は\nこうげきから みを まもった!",
"battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}は\nこらえる たいせいに はいった!",
"battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}は\nこうげきを こらえた!",
"battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}は\nこうげきを こらえた!",
"battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}の ほろびのカウントが {{turnCount}}になった!",
"battlerTagsCenterOfAttentionOnAdd": "{{pokemonNameWithAffix}}は ちゅうもくの まとになった!",
"battlerTagsTruantLapse": "{{pokemonNameWithAffix}}は なまけている!",
"battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}は ちょうしが あがらない!",
"battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}は ちょうしを とりもどした!",
"battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}の {{statName}}が\nあがっている じょうたいに なった!",
"battlerTagsHighestStatBoostOnRemove": "{{pokemonNameWithAffix}}の {{abilityName}}の こうかが なくなった!",
"battlerTagsMagnetRisenOnAdd": "{{pokemonNameWithAffix}}は でんじりょくで うかびあがった!",
"battlerTagsMagnetRisenOnRemove": "{{pokemonNameWithAffix}}は でんじりょくが なくなった!",
"battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}は はりきっている!",
"battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}は おちついた。",
"battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}は\nまもりの 体制に 入った!",
"battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}は\n攻撃から 身を守った!",
"battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}は\nこらえる 体制に 入った!",
"battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}は\n攻撃を こらえた!",
"battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}は\n攻撃を こらえた!",
"battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}の ほろびのカウントが {{turnCount}}になった!",
"battlerTagsCenterOfAttentionOnAdd": "{{pokemonNameWithAffix}}は 注目の 的になった!",
"battlerTagsTruantLapse": "{{pokemonNameWithAffix}}は 怠(なま)けている!",
"battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}は 調子が 上がらない!",
"battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}は 調子を 取り戻した!",
"battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}の {{statName}}が\n上がっている 状態に なった!",
"battlerTagsHighestStatBoostOnRemove": "{{pokemonNameWithAffix}}の {{abilityName}}の 効果が なくなった!",
"battlerTagsMagnetRisenOnAdd": "{{pokemonNameWithAffix}}は 電磁力(でんじりょく)で 浮かび上がった!",
"battlerTagsMagnetRisenOnRemove": "{{pokemonNameWithAffix}}は 電磁力(でんじりょく)が なくなった!",
"battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}は 張り切っている!",
"battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}は 落ち着いた。",
"battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}}は しおづけに なった!",
"battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}}は {{moveName}}の\n ダメージを けている",
"battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}は じぶんの たいりょくを けずって\n{{pokemonName}}に のろいを かけた!",
"battlerTagsCursedLapse": "{{pokemonNameWithAffix}}は のろわれている!",
"battlerTagsStockpilingOnAdd": "{{pokemonNameWithAffix}}は {{stockpiledCount}}つ たくわえた!"
"battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}}は {{moveName}}の\n ダメージを けている",
"battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}は 自分の 体力を 削って\n{{pokemonName}}に のろいを かけた!",
"battlerTagsCursedLapse": "{{pokemonNameWithAffix}}は のろわれている!",
"battlerTagsStockpilingOnAdd": "{{pokemonNameWithAffix}}は {{stockpiledCount}}つ たくわえた!"
} as const;

View File

@ -3,16 +3,31 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const filterBar: SimpleTranslationEntries = {
"genFilter": "Gen",
"typeFilter": "Type",
"caughtFilter": "Caught",
"unlocksFilter": "Unlocks",
"winFilter": "Win",
"miscFilter": "Misc",
"sortFilter": "Sort",
"all": "All",
"normal": "Normal",
"normal": "Not Shiny",
"uncaught": "Uncaught",
"passive": "Passive",
"passiveUnlocked": "Passive Unlocked",
"passiveLocked": "Passive Locked",
"hasWon": "Yes",
"hasNotWon": "No",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Ribbon",
"hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "No.",
"sortByCost": "Cost",
"sortByCandies": "Candy Count",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}の\nねがいごとが かなった",
"invertStats": "{{pokemonName}}の\nのうりょくへんかが ぎゃくてんした",
"resetStats": "{{pokemonName}}の\nのうりょくへんかが もとにもどった",
"statEliminated": "All stat changes were eliminated!",
"faintCountdown": "{{pokemonName}}は\n{{turnCount}}ターンごに ほろびてしまう!",
"copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった",
"suppressAbilities": "{{pokemonName}}の とくせいが きかなくなった!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "個体値を ひょうじ",
"manageMoves": "わざを ならびかえ",
"manageNature": "せいかくを ならびかえ",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "アメを つかう",
"selectNature": "せいかくをえらんでください",
"selectMoveSwapOut": "交換する技を選択してください",

View File

@ -13,9 +13,12 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "패시브",
"passiveUnlocked": "패시브 해금",
"passiveLocked": "패시브 잠김",
"costReduction": "코스트 줄이기",
"costReductionUnlocked": "코스트 절감됨",
"costReductionLocked": "코스트 절감 없음",
"costReduction": "코스트 감소",
"costReductionUnlocked": "코스트 감소됨",
"costReductionLocked": "코스트 감소 없음",
"favorite": "즐겨찾기",
"isFavorite": "즐겨찾기 등록됨",
"notFavorite": "즐겨찾기 제외됨",
"ribbon": "클리어 여부",
"hasWon": "클리어 완료",
"hasNotWon": "클리어 안함",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}의\n치유소원이 이루어졌다!",
"invertStats": "{{pokemonName}}[[는]]\n능력 변화가 뒤집혔다!",
"resetStats": "{{pokemonName}}의 모든 상태가\n원래대로 되돌아왔다!",
"statEliminated": "모든 상태가 원래대로 되돌아왔다!",
"faintCountdown": "{{pokemonName}}[[는]]\n{{turnCount}}턴 후에 쓰러져 버린다!",
"copyType": "{{pokemonName}}[[는]]\n{{targetPokemonName}}[[와]] 같은 타입이 되었다!",
"suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "개체값 토글",
"manageMoves": "기술 관리",
"manageNature": "성격 관리",
"addToFavorites": "즐겨찾기에 추가",
"removeFromFavorites": "즐겨찾기에서 제외",
"useCandies": "사탕 사용",
"selectNature": "교체할 성격을 선택해주세요.",
"selectMoveSwapOut": "교체할 기술을 선택해주세요.",

View File

@ -171,7 +171,7 @@ export const PGMachv: AchievementTranslationEntries = {
},
"UNEVOLVED_CLASSIC_VICTORY": {
name: "Tire as Crianças da Sala",
description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído.."
description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído."
},
"MONO_GEN_ONE": {
@ -445,8 +445,8 @@ export const PGFachv: AchievementTranslationEntries = {
description: "Vença o jogo no modo clássico",
},
"UNEVOLVED_CLASSIC_VICTORY": {
name: "Bring Your Child To Work Day",
description: "Beat the game in Classic Mode with at least one unevolved party member."
name: "Tire as Crianças da Sala",
description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído."
},
"MONO_GEN_ONE": {

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Redução de Custo",
"costReductionUnlocked": "Redução de Custo Desbloq.",
"costReductionLocked": "Redução de Custo Bloq.",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "Fita",
"hasWon": "Fita - Sim",
"hasNotWon": "Fita - Não",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "O Healing Wish de {{pokemonName}}\nfoi concedido!",
"invertStats": "As mudanças de atributo de {{pokemonName}}\nforam revertidas!",
"resetStats": "As mudanças de atributo de {{pokemonName}}\nforam eliminadas!",
"statEliminated": "Todas as mudanças de atributo foram eliminadas!",
"faintCountdown": "{{pokemonName}}\nirá desmaiar em {{turnCount}} turnos.",
"copyType": "O tipo de {{pokemonName}}\nmudou para combinar com {{targetPokemonName}}!",
"suppressAbilities": "A habilidade de {{pokemonName}}\nfoi suprimida!",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "Mostrar IVs",
"manageMoves": "Mudar Movimentos",
"manageNature": "Mudar Natureza",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "Usar Doces",
"selectNature": "Escolha uma natureza.",
"selectMoveSwapOut": "Escolha um movimento para substituir.",

View File

@ -20,18 +20,18 @@ export const titles: SimpleTranslationEntries = {
"plasma_boss": "Chefe da Equipe Plasma",
"flare_boss": "Chefe da Equipe Flare",
"rocket_admin": "Team Rocket Admin",
"rocket_admin_female": "Team Rocket Admin",
"magma_admin": "Team Magma Admin",
"magma_admin_female": "Team Magma Admin",
"aqua_admin": "Team Aqua Admin",
"aqua_admin_female": "Team Aqua Admin",
"galactic_commander": "Team Galactic Commander",
"galactic_commander_female": "Team Galactic Commander",
"plasma_sage": "Team Plasma Sage",
"plasma_admin": "Team Plasma Admin",
"flare_admin": "Team Flare Admin",
"flare_admin_female": "Team Flare Admin",
"rocket_admin": "Admin da Equipe Rocket",
"rocket_admin_female": "Admin da Equipe Rocket",
"magma_admin": "Admin da Equipe Magma",
"magma_admin_female": "Admin da Equipe Magma",
"aqua_admin": "Admin da Equipe Aqua",
"aqua_admin_female": "Admin da Equipe Aqua",
"galactic_commander": "Comandante da Equipe Galáctica",
"galactic_commander_female": "Comandante da Equipe Galáctica",
"plasma_sage": "Sábio da Equipe Plasma",
"plasma_admin": "Admin da Equipe Plasma",
"flare_admin": "Admin da Equipe Flare",
"flare_admin_female": "Admin da Equipe Flare",
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
} as const;
@ -138,24 +138,24 @@ export const trainerClasses: SimpleTranslationEntries = {
"worker_female": "Operária",
"workers": "Operários",
"youngster": "Jovem",
"rocket_grunt": "Recruta da Equipe Rocket",
"rocket_grunt_female": "Recruta da Equipe Rocket",
"rocket_grunts": "Recrutas da Equipe Rocket",
"magma_grunt": "Recruta da Equipe Magma",
"magma_grunt_female": "Recruta da Equipe Magma",
"magma_grunts": "Recrutas da Equipe Magma",
"aqua_grunt": "Recruta da Equipe Aqua",
"aqua_grunt_female": "Recruta da Equipe Aqua",
"aqua_grunts": "Recrutas da Equipe Aqua",
"galactic_grunt": "Recruta da Equipe Galáctica",
"galactic_grunt_female": "Recruta da Equipe Galáctica",
"galactic_grunts": "Recrutas da Equipe Galáctica",
"plasma_grunt": "Recruta da Equipe Plasma",
"plasma_grunt_female": "Recruta da Equipe Plasma",
"plasma_grunts": "Recrutas da Equipe Plasma",
"flare_grunt": "Recruta da Equipe Flare",
"flare_grunt_female": "Recruta da Equipe Flare",
"flare_grunts": "Recrutas da Equipe Flare",
"rocket_grunt": "Capanga da Equipe Rocket",
"rocket_grunt_female": "Capanga da Equipe Rocket",
"rocket_grunts": "Capangas da Equipe Rocket",
"magma_grunt": "Capanga da Equipe Magma",
"magma_grunt_female": "Capanga da Equipe Magma",
"magma_grunts": "Capangas da Equipe Magma",
"aqua_grunt": "Capanga da Equipe Aqua",
"aqua_grunt_female": "Capanga da Equipe Aqua",
"aqua_grunts": "Capangas da Equipe Aqua",
"galactic_grunt": "Capanga da Equipe Galáctica",
"galactic_grunt_female": "Capanga da Equipe Galáctica",
"galactic_grunts": "Capangas da Equipe Galáctica",
"plasma_grunt": "Capanga da Equipe Plasma",
"plasma_grunt_female": "Capanga da Equipe Plasma",
"plasma_grunts": "Capangas da Equipe Plasma",
"flare_grunt": "Capanga da Equipe Flare",
"flare_grunt_female": "Capanga da Equipe Flare",
"flare_grunts": "Capangas da Equipe Flare",
} as const;
// Names of special trainers like gym leaders, elite four, and the champion

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "费用降低",
"costReductionUnlocked": "已降费",
"costReductionLocked": "未降费",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "缎带",
"hasWon": "有缎带",
"hasNotWon": "无缎带",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}的\n治愈之愿实现了",
"invertStats": "{{pokemonName}}的\n能力变化颠倒过来了",
"resetStats": "{{pokemonName}}的\n能力变化复原了",
"statEliminated": "所有能力都复原了!",
"faintCountdown": "{{pokemonName}}\n将在{{turnCount}}回合后灭亡!",
"copyType": "{{pokemonName}}\n变成了{{targetPokemonName}}的属性!",
"suppressAbilities": "{{pokemonName}}的特性\n变得无效了",

View File

@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "显示个体",
"manageMoves": "管理招式",
"manageNature": "管理性格",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "使用糖果",
"selectNature": "选择性格",
"selectMoveSwapOut": "选择要替换的招式。",

View File

@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = {
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"favorite": "Favorite",
"isFavorite": "Favorite - Yes",
"notFavorite": "Favorite - No",
"ribbon": "緞帶",
"hasWon": "有緞帶",
"hasNotWon": "無緞帶",

View File

@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}}的\n治癒之願實現了",
"invertStats": "{{pokemonName}}的\n能力變化顛倒過來了",
"resetStats": "{{pokemonName}}的\n能力變化復原了",
"statEliminated": "所有能力都復原了!",
"faintCountdown": "{{pokemonName}}\n將在{{turnCount}}回合後滅亡!",
"copyType": "{{pokemonName}}變成了{{targetPokemonName}}的屬性!",
"suppressAbilities": "{{pokemonName}}的特性\n變得無效了",

View File

@ -29,6 +29,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "查看個體值",
"manageMoves": "管理技能",
"manageNature": "管理性格",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"useCandies": "使用糖果",
"selectNature": "選擇性格",
"selectMoveSwapOut": "選擇想要替換走的招式",

View File

@ -622,6 +622,11 @@ export class SelectStarterPhase extends Phase {
if (starter.pokerus) {
starterPokemon.pokerus = true;
}
if (starter.nickname) {
starterPokemon.nickname = starter.nickname;
}
if (this.scene.gameMode.isSplicedOnly) {
starterPokemon.generateFusionSpecies(true);
}

View File

@ -198,6 +198,8 @@ export interface StarterAttributes {
form?: integer;
female?: boolean;
shiny?: boolean;
favorite?: boolean;
nickname?: string;
}
export interface StarterPreferences {

View File

@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Abilities - Hustle", () => {
let phaserGame: Phaser.Game;
@ -44,7 +44,7 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getBattleStat");
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
expect(pikachu.getBattleStat).toHaveReturnedWith(atk * 1.5);

View File

@ -12,7 +12,7 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -192,7 +192,7 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, false);
await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase);
const enemyPokemon = game.scene.getEnemyPokemon()!;

View File

@ -11,7 +11,7 @@ import { Abilities } from "#enums/abilities";
import { WeatherType } from "#app/data/weather.js";
import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { BattlerTagType } from "#enums/battler-tag-type";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000; // 20 sec timeout
@ -258,7 +258,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK));
await mockHitCheck(game, false);
await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase);

View File

@ -10,7 +10,7 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -129,7 +129,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(BerryPhase, false);
@ -172,7 +172,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase, false);
@ -368,7 +368,7 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
@ -397,7 +397,7 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
@ -423,7 +423,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
@ -451,7 +451,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
@ -481,7 +481,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);
@ -508,7 +508,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(MoveEffectPhase);
expect(leadPokemon.turnData.hitCount).toBe(2);
@ -532,7 +532,7 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP));
await mockHitCheck(game, true);
await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase);

View File

@ -12,7 +12,7 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -192,7 +192,7 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, false);
await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase);
const enemyPokemon = game.scene.getEnemyPokemon()!;

View File

@ -11,7 +11,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { mockTurnOrder } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle.js";
@ -57,7 +56,7 @@ describe("Abilities - Serene Grace", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Check chance of Air Slash without Serene Grace
@ -90,7 +89,7 @@ describe("Abilities - Serene Grace", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Check chance of Air Slash with Serene Grace

View File

@ -11,7 +11,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { mockTurnOrder } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle.js";
@ -58,7 +57,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -97,7 +96,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -136,7 +135,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -177,7 +176,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;

View File

@ -12,7 +12,6 @@ import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { BattlerIndex } from "#app/battle.js";
import { mockTurnOrder } from "../utils/testUtils";
describe("Abilities - Shield Dust", () => {
@ -58,7 +57,7 @@ describe("Abilities - Shield Dust", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Shield Dust negates secondary effect

View File

@ -8,7 +8,7 @@ import { getMovePosition } from "#test/utils/gameManagerUtils";
import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { Abilities } from "#app/enums/abilities.js";
import { BattlerIndex } from "#app/battle.js";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Abilities - Sweet Veil", () => {
let phaserGame: Phaser.Game;
@ -80,11 +80,11 @@ describe("Abilities - Sweet Veil", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
// First pokemon move
await mockHitCheck(game, true);
await game.move.forceHit();
// Second pokemon move
await game.phaseInterceptor.to(MovePhase, false);
await mockHitCheck(game, true);
await game.move.forceHit();
expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true);

View File

@ -12,7 +12,6 @@ import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import { BattlerIndex } from "#app/battle.js";
import { mockTurnOrder } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -58,7 +57,8 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(DamagePhase, false);
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
@ -86,7 +86,8 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(QuietFormChangePhase);
await game.phaseInterceptor.to(TurnInitPhase, false);
expect(game.scene.getParty()[0].hp).not.toBe(100);
@ -111,7 +112,8 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(DamagePhase, false);
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;

View File

@ -8,7 +8,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockTurnOrder } from "#test/utils/testUtils";
describe("Items - Leek", () => {
let phaserGame: Phaser.Game;
@ -44,7 +43,7 @@ describe("Items - Leek", () => {
game.doAttack(0);
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase);

View File

@ -8,7 +8,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockTurnOrder } from "#test/utils/testUtils";
describe("Items - Scope Lens", () => {
let phaserGame: Phaser.Game;
@ -43,7 +42,8 @@ describe("Items - Scope Lens", () => {
]);
game.doAttack(0);
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase);

View File

@ -0,0 +1,82 @@
import { BattleStat } from "#app/data/battle-stat";
import { MoveEndPhase, TurnInitPhase } from "#app/phases";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { allMoves } from "#app/data/move.js";
describe("Moves - Freezy Frost", () => {
describe("integration tests", () => {
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.battleType("single");
game.override.enemySpecies(Species.RATTATA);
game.override.enemyLevel(100);
game.override.enemyMoveset(SPLASH_ONLY);
game.override.enemyAbility(Abilities.NONE);
game.override.startingLevel(100);
game.override.moveset([Moves.FREEZY_FROST, Moves.SWORDS_DANCE, Moves.CHARM, Moves.SPLASH]);
vi.spyOn(allMoves[Moves.FREEZY_FROST], "accuracy", "get").mockReturnValue(100);
game.override.ability(Abilities.NONE);
});
it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, player uses Freezy Frost to clear all stat changes", { timeout: 10000 }, async () => {
await game.startBattle([Species.RATTATA]);
const user = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0);
game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE));
await game.phaseInterceptor.to(TurnInitPhase);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
await game.phaseInterceptor.to(TurnInitPhase);
const userAtkBefore = user.summonData.battleStats[BattleStat.ATK];
const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK];
expect(userAtkBefore).toBe(2);
expect(enemyAtkBefore).toBe(-2);
game.doAttack(getMovePosition(game.scene, 0, Moves.FREEZY_FROST));
await game.phaseInterceptor.to(TurnInitPhase);
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0);
});
it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, enemy uses Freezy Frost to clear all stat changes", { timeout: 10000 }, async () => {
game.override.enemyMoveset([Moves.FREEZY_FROST, Moves.FREEZY_FROST, Moves.FREEZY_FROST, Moves.FREEZY_FROST]);
await game.startBattle([Species.SHUCKLE]); // Shuckle for slower Swords Dance on first turn so Freezy Frost doesn't affect it.
const user = game.scene.getPlayerPokemon()!;
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE));
await game.phaseInterceptor.to(TurnInitPhase);
const userAtkBefore = user.summonData.battleStats[BattleStat.ATK];
expect(userAtkBefore).toBe(2);
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEndPhase);
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
});
});
});

View File

@ -8,7 +8,6 @@ import { allMoves } from "#app/data/move";
import { BattlerIndex } from "#app/battle";
import { Species } from "#enums/species";
import { Moves } from "#enums/moves";
import { mockTurnOrder } from "#test/utils/testUtils";
describe("Moves - Fusion Flare and Fusion Bolt", () => {
let phaserGame: Phaser.Game;
@ -56,7 +55,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -82,7 +81,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -108,7 +107,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(0);
// Force first enemy to act (and fail) in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -140,7 +139,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -170,7 +169,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.PLAYER);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -222,7 +221,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -284,7 +283,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.PLAYER);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);

View File

@ -6,7 +6,7 @@ import { MoveResult } from "#app/field/pokemon.js";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -75,7 +75,7 @@ describe("Moves - Gastro Acid", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER));
// Force player to be slower to enable Core Enforcer to proc its suppression effect
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("TurnInitPhase");

View File

@ -0,0 +1,80 @@
import { BattleStat } from "#app/data/battle-stat";
import { MoveEndPhase, TurnInitPhase } from "#app/phases";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Moves - Haze", () => {
describe("integration tests", () => {
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.battleType("single");
game.override.enemySpecies(Species.RATTATA);
game.override.enemyLevel(100);
game.override.enemyMoveset(SPLASH_ONLY);
game.override.enemyAbility(Abilities.NONE);
game.override.startingLevel(100);
game.override.moveset([Moves.HAZE, Moves.SWORDS_DANCE, Moves.CHARM, Moves.SPLASH]);
game.override.ability(Abilities.NONE);
});
it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, player uses Haze to clear all stat changes", { timeout: 10000 }, async () => {
await game.startBattle([Species.RATTATA]);
const user = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0);
game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE));
await game.phaseInterceptor.to(TurnInitPhase);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
await game.phaseInterceptor.to(TurnInitPhase);
const userAtkBefore = user.summonData.battleStats[BattleStat.ATK];
const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK];
expect(userAtkBefore).toBe(2);
expect(enemyAtkBefore).toBe(-2);
game.doAttack(getMovePosition(game.scene, 0, Moves.HAZE));
await game.phaseInterceptor.to(TurnInitPhase);
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0);
});
it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, enemy uses Haze to clear all stat changes", { timeout: 10000 }, async () => {
game.override.enemyMoveset([Moves.HAZE, Moves.HAZE, Moves.HAZE, Moves.HAZE]);
await game.startBattle([Species.SHUCKLE]); // Shuckle for slower Swords Dance on first turn so Haze doesn't affect it.
const user = game.scene.getPlayerPokemon()!;
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE));
await game.phaseInterceptor.to(TurnInitPhase);
const userAtkBefore = user.summonData.battleStats[BattleStat.ATK];
expect(userAtkBefore).toBe(2);
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEndPhase);
expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0);
});
});
});

View File

@ -33,6 +33,7 @@ describe("Moves - Hyper Beam", () => {
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.enemyMoveset(Array(4).fill(Moves.SPLASH));
game.override.enemyLevel(100);
game.override.moveset([Moves.HYPER_BEAM, Moves.TACKLE]);
vi.spyOn(allMoves[Moves.HYPER_BEAM], "accuracy", "get").mockReturnValue(100);

View File

@ -1,12 +1,12 @@
import { BattleStat } from "#app/data/battle-stat.js";
import { MoveEffectPhase, MoveEndPhase, StatChangePhase } from "#app/phases";
import { MoveEndPhase, StatChangePhase } from "#app/phases";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -91,11 +91,8 @@ describe("Moves - Make It Rain", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Make Make It Rain miss the first target
const moveEffectPhase = game.scene.getCurrentPhase() as MoveEffectPhase;
vi.spyOn(moveEffectPhase, "hitCheck").mockReturnValueOnce(false);
await game.move.forceMiss(true);
await game.phaseInterceptor.to(MoveEndPhase);

View File

@ -2,7 +2,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import Phaser from "phaser";
import GameManager from "#test/utils/gameManager";
import { Species } from "#app/enums/species.js";
import { mockTurnOrder, SPLASH_ONLY } from "../utils/testUtils";
import { SPLASH_ONLY } from "../utils/testUtils";
import { Moves } from "#app/enums/moves.js";
import { getMovePosition } from "../utils/gameManagerUtils";
import { MoveEffectPhase } from "#app/phases.js";
@ -39,7 +39,7 @@ describe("Internals", () => {
const enemy = game.scene.getEnemyPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION));
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.toNextTurn();
expect(enemy.hp).toBe(enemy.getMaxHp());

View File

@ -7,6 +7,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import { BattlerIndex } from "#app/battle.js";
const TIMEOUT = 20 * 1000;
@ -49,6 +50,7 @@ describe("Moves - Purify", () => {
enemyPokemon.status = new Status(StatusEffect.BURN);
game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY));
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEndPhase);
expect(enemyPokemon.status).toBeNull();
@ -68,6 +70,7 @@ describe("Moves - Purify", () => {
const playerInitialHp = playerPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY));
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEndPhase);
expect(playerPokemon.hp).toBe(playerInitialHp);

View File

@ -28,6 +28,8 @@ import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.j
import overrides from "#app/overrides.js";
import { removeEnemyHeldItems } from "./testUtils";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js";
import { MoveHelper } from "./moveHelper";
import { vi } from "vitest";
/**
* Class to manage the game state and transitions between phases.
@ -39,6 +41,7 @@ export default class GameManager {
public textInterceptor: TextInterceptor;
public inputsHandler: InputsHandler;
public readonly override: OverridesHelper;
public readonly move: MoveHelper;
/**
* Creates an instance of GameManager.
@ -55,6 +58,7 @@ export default class GameManager {
this.textInterceptor = new TextInterceptor(this.scene);
this.gameWrapper.setScene(this.scene);
this.override = new OverridesHelper(this);
this.move = new MoveHelper(this);
}
/**
@ -354,4 +358,19 @@ export default class GameManager {
partyHandler.processInput(Button.ACTION); // send out (or whatever option is at the top)
});
}
/**
* Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder}
* Used to modify the turn order.
* @param {BattlerIndex[]} order The turn order to set
* @example
* ```ts
* await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]);
* ```
*/
async setTurnOrder(order: BattlerIndex[]): Promise<void> {
await this.phaseInterceptor.to(TurnStartPhase, false);
vi.spyOn(this.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order);
}
}

View File

@ -0,0 +1,12 @@
import GameManager from "./gameManager";
/**
* Base class for defining all game helpers.
*/
export abstract class GameManagerHelper {
protected readonly game: GameManager;
constructor(game: GameManager) {
this.game = game;
}
}

View File

@ -242,6 +242,7 @@ function createFetchResponse(data) {
return {
ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
};
@ -251,6 +252,7 @@ function createFetchBadResponse(data) {
return {
ok: false,
status: 404,
headers: new Headers(),
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
};

View File

@ -23,10 +23,13 @@ export const MockFetch = (input, init) => {
}
}
return Promise.resolve({
const response: Partial<Response> = {
ok: true,
status: 200,
json: responseHandler,
text: responseText,
});
headers: new Headers({}),
};
return Promise.resolve(response);
};

View File

@ -0,0 +1,35 @@
import { vi } from "vitest";
import { MoveEffectPhase } from "#app/phases.js";
import { GameManagerHelper } from "./gameManagerHelper";
/**
* Helper to handle a Pokemon's move
*/
export class MoveHelper extends GameManagerHelper {
/**
* Intercepts `MoveEffectPhase` and mocks the hitCheck's
* return value to `true` {@linkcode MoveEffectPhase.hitCheck}.
* Used to force a move to hit.
*/
async forceHit(): Promise<void> {
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
}
/**
* Intercepts `MoveEffectPhase` and mocks the hitCheck's
* return value to `false` {@linkcode MoveEffectPhase.hitCheck}.
* Used to force a move to miss.
* @param firstTargetOnly Whether the move should force miss on the first target only, in the case of multi-target moves.
*/
async forceMiss(firstTargetOnly: boolean = false): Promise<void> {
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
const hitCheck = vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck");
if (firstTargetOnly) {
hitCheck.mockReturnValueOnce(false);
} else {
hitCheck.mockReturnValue(false);
}
}
}

View File

@ -8,19 +8,13 @@ import * as GameMode from "#app/game-mode";
import { GameModes, getGameMode } from "#app/game-mode";
import { ModifierOverride } from "#app/modifier/modifier-type.js";
import Overrides from "#app/overrides";
import GameManager from "#test/utils/gameManager";
import { vi } from "vitest";
import { GameManagerHelper } from "./gameManagerHelper";
/**
* Helper to handle overrides in tests
*/
export class OverridesHelper {
private readonly game: GameManager;
constructor(game: GameManager) {
this.game = game;
}
export class OverridesHelper extends GameManagerHelper {
/**
* Override the starting biome
* @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line

View File

@ -2,8 +2,6 @@ import { Moves } from "#app/enums/moves.js";
import i18next, { type ParseKeys } from "i18next";
import { vi } from "vitest";
import GameManager from "./gameManager";
import { BattlerIndex } from "#app/battle.js";
import { MoveEffectPhase, TurnStartPhase } from "#app/phases.js";
/** Ready to use array of Moves.SPLASH x4 */
export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH];
@ -38,35 +36,3 @@ export function removeEnemyHeldItems(game: GameManager): void {
game.scene.clearEnemyModifiers();
console.log("Enemy held items removed");
}
/**
* Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder}
* Used to modify the turn order.
* @param {GameManager} game The GameManager instance
* @param {BattlerIndex[]} order The turn order to set
* @example
* ```ts
* await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]);
* ```
*/
export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): Promise<void> {
await game.phaseInterceptor.to(TurnStartPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order);
}
/**
* Intercepts `MoveEffectPhase` and mocks the hitCheck's return value {@linkcode MoveEffectPhase.hitCheck}.
* Used to force a move to either hit or miss.
* Note that this uses `mockReturnValue()`, meaning it will also apply to a
* succeeding `MoveEffectPhase` immediately following the first one
* (in the case of a multi-target move)
*
* @param {GameManager} game The GameManager instance
* @param shouldHit Whether the move should hit
*/
export async function mockHitCheck(game: GameManager, shouldHit: boolean): Promise<void> {
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(shouldHit);
}

View File

@ -36,17 +36,13 @@ export default class RenameFormUiHandler extends FormModalUiHandler {
show(args: any[]): boolean {
if (super.show(args)) {
const config = args[0] as ModalConfig;
if (args[1] && typeof (args[1] as PlayerPokemon).getNameToRender === "function") {
this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender();
} else {
this.inputs[0].text = args[1];
}
this.submitAction = (_) => {
this.sanitizeInputs();
// const onFail = () => {
// this.scene.ui.setModeWithoutClear(Mode.RENAME_POKEMON, Object.assign(config));
// this.scene.ui.playError();
// };
// if (!this.inputs[0].text) {
// return onFail();
// }
const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text)));
config.buttonActions[0](sanitizedName);
return true;

View File

@ -10,6 +10,7 @@ export class StarterContainer extends Phaser.GameObjects.Container {
public label: Phaser.GameObjects.Text;
public starterPassiveBgs: Phaser.GameObjects.Image;
public hiddenAbilityIcon: Phaser.GameObjects.Image;
public favoriteIcon: Phaser.GameObjects.Image;
public classicWinIcon: Phaser.GameObjects.Image;
public candyUpgradeIcon: Phaser.GameObjects.Image;
public candyUpgradeOverlayIcon: Phaser.GameObjects.Image;
@ -66,8 +67,16 @@ export class StarterContainer extends Phaser.GameObjects.Container {
this.add(abilityIcon);
this.hiddenAbilityIcon = abilityIcon;
// favorite icon
const favoriteIcon = this.scene.add.image(0, 7, "favorite");
favoriteIcon.setOrigin(0, 0);
favoriteIcon.setScale(0.5);
favoriteIcon.setVisible(false);
this.add(favoriteIcon);
this.favoriteIcon = favoriteIcon;
// classic win icon
const classicWinIcon = this.scene.add.image(2, 12, "champion_ribbon");
const classicWinIcon = this.scene.add.image(0, 12, "champion_ribbon");
classicWinIcon.setOrigin(0, 0);
classicWinIcon.setScale(0.5);
classicWinIcon.setVisible(false);

View File

@ -55,6 +55,7 @@ export interface Starter {
nature: Nature;
moveset?: StarterMoveset;
pokerus: boolean;
nickname?: string;
}
interface LanguageSetting {
@ -461,6 +462,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.filterBar.addFilter(DropDownColumn.UNLOCKS, i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.RADIAL));
// misc filter
const favoriteLabels = [
new DropDownLabel(i18next.t("filterBar:favorite"), undefined, DropDownState.OFF),
new DropDownLabel(i18next.t("filterBar:isFavorite"), undefined, DropDownState.ON),
new DropDownLabel(i18next.t("filterBar:notFavorite"), undefined, DropDownState.EXCLUDE),
];
const winLabels = [
new DropDownLabel(i18next.t("filterBar:ribbon"), undefined, DropDownState.OFF),
new DropDownLabel(i18next.t("filterBar:hasWon"), undefined, DropDownState.ON),
@ -476,6 +482,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
new DropDownLabel(i18next.t("filterBar:hasPokerus"), undefined, DropDownState.ON),
];
const miscOptions = [
new DropDownOption(this.scene, "FAVORITE", favoriteLabels),
new DropDownOption(this.scene, "WIN", winLabels),
new DropDownOption(this.scene, "HIDDEN_ABILITY", hiddenAbilityLabels),
new DropDownOption(this.scene, "POKERUS", pokerusLabels),
@ -928,6 +935,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.allSpecies.forEach((species, s) => {
const icon = this.starterContainers[s].icon;
const dexEntry = this.scene.gameData.dexData[species.speciesId];
this.starterPreferences[species.speciesId] = this.starterPreferences[species.speciesId] ?? {};
if (dexEntry.caughtAttr) {
icon.clearTint();
@ -1542,6 +1550,56 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
}
}
// if container.favorite is false, show the favorite option
const isFavorite = starterAttributes?.favorite ?? false;
if (!isFavorite) {
options.push({
label: i18next.t("starterSelectUiHandler:addToFavorites"),
handler: () => {
starterAttributes.favorite = true;
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
ui.setMode(Mode.STARTER_SELECT);
return true;
}
});
} else {
options.push({
label: i18next.t("starterSelectUiHandler:removeFromFavorites"),
handler: () => {
starterAttributes.favorite = false;
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
ui.setMode(Mode.STARTER_SELECT);
return true;
}
});
}
options.push({
label: i18next.t("menu:rename"),
handler: () => {
ui.playSelect();
let nickname = starterAttributes.nickname ? String(starterAttributes.nickname) : "";
nickname = decodeURIComponent(escape(atob(nickname)));
ui.setModeWithoutClear(Mode.RENAME_POKEMON, {
buttonActions: [
(sanitizedName: string) => {
ui.playSelect();
starterAttributes.nickname = sanitizedName;
const name = decodeURIComponent(escape(atob(starterAttributes.nickname)));
if (name.length > 0) {
this.pokemonNameText.setText(name);
} else {
this.pokemonNameText.setText(species.name);
}
ui.setMode(Mode.STARTER_SELECT);
},
() => {
ui.setMode(Mode.STARTER_SELECT);
}
]
}, nickname);
return true;
}
});
const showUseCandies = () => { // this lets you use your candies
const options: any[] = []; // TODO: add proper type
if (!(passiveAttr & PassiveAttr.UNLOCKED)) {
@ -2230,6 +2288,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0;
const isCostReduced = this.scene.gameData.starterData[container.species.speciesId].valueReduction > 0;
const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false;
const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0;
const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0;
const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined;
@ -2273,6 +2333,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
});
const fitsFavorite = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
if (misc.val === "FAVORITE" && misc.state === DropDownState.ON) {
return isFavorite;
}
if (misc.val === "FAVORITE" && misc.state === DropDownState.EXCLUDE) {
return !isFavorite;
}
if (misc.val === "FAVORITE" && misc.state === DropDownState.OFF) {
return true;
}
});
const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
if (container.species.speciesId < 10) {
}
@ -2305,7 +2377,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
});
if (fitsGen && fitsType && fitsCaught && fitsPassive && fitsCostReduction && fitsWin && fitsHA && fitsPokerus) {
if (fitsGen && fitsType && fitsCaught && fitsPassive && fitsCostReduction && fitsFavorite && fitsWin && fitsHA && fitsPokerus) {
this.filteredStarterContainers.push(container);
}
});
@ -2398,6 +2470,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
container.starterPassiveBgs.setVisible(!!this.scene.gameData.starterData[speciesId].passiveAttr);
container.hiddenAbilityIcon.setVisible(!!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4));
container.classicWinIcon.setVisible(this.scene.gameData.starterData[speciesId].classicWinCount > 0);
container.favoriteIcon.setVisible(this.starterPreferences[speciesId]?.favorite ?? false);
// 'Candy Icon' mode
if (this.scene.candyUpgradeDisplay === 0) {
@ -2573,7 +2646,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (species && (this.speciesStarterDexEntry?.seenAttr || this.speciesStarterDexEntry?.caughtAttr)) {
this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4));
if (starterAttributes?.nickname) {
const name = decodeURIComponent(escape(atob(starterAttributes.nickname)));
this.pokemonNameText.setText(name);
} else {
this.pokemonNameText.setText(species.name);
}
if (this.speciesStarterDexEntry?.caughtAttr) {
const colorScheme = starterColors[species.speciesId];
@ -3215,7 +3293,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
nature: thisObj.starterNatures[i] as Nature,
moveset: thisObj.starterMovesets[i],
pokerus: thisObj.pokerusSpecies.includes(starterSpecies)
pokerus: thisObj.pokerusSpecies.includes(starterSpecies),
nickname: thisObj.starterPreferences[starterSpecies.speciesId]?.nickname,
};
}));
};