Merge branch 'beta' into WorkingDiscardFunction

This commit is contained in:
Mikhail Shueb 2025-07-12 15:01:37 +01:00 committed by GitHub
commit 93a7ad2942
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 1002 additions and 670 deletions

View File

@ -1,6 +1,6 @@
# Localization 101
PokéRogue's localization team puts immense effort into making the game accessible around the world, supporting over 12 different languages at the time of writing this document. \
PokéRogue's localization team puts immense effort into making the game accessible around the world, supporting over 12 different languages at the time of writing this document.
As a developer, it's important to help maintain global accessibility by effectively coordinating with the Translation Team on any new features or enhancements.
This document aims to cover everything you need to know to help keep the integration process for localization smooth and simple.
@ -28,7 +28,6 @@ The parent repo (the "superproject") houses a cloned version of the 2nd reposito
>
> ![Image showing Visual Studio Code's Source Control tab. A separate dropdown can be seen for each individual submodule.](https://github.com/user-attachments/assets/8b4d3f64-aec1-4474-91df-03dc1252a2fa "Making commits on submodules without even changing directories!")
From the perspective of the main project, the locales submodule is fairly simple to work with.
## Fetching Changes from Submodules
The following command will initialize your branch's locales repository and update its HEAD:
@ -36,10 +35,10 @@ The following command will initialize your branch's locales repository and updat
git submodule update --init --recursive
```
> [!INFO]
> This is run _automatically_ after cloning, merging or changing branches, so you should rarely have to run it manually.
> [!TIP]
> This command is run _automatically_ after cloning, merging or changing branches, so you should rarely have to run it manually.
> [!WARNING]
> [!IMPORTANT]
> If you run into issues with the `locales` submodule, try deleting the `.git/modules/public` and `public/locales` folders before re-running the command.
## How Are Translations Integrated?
@ -66,7 +65,7 @@ The basic process for fetching translated text goes roughly as follows:
```
# Submitting Locales Changes
If you have a feature or enhancement that requires additions or changes to in-game text, you will need to make a fork of the `pokerogue-locales` repo and submit your text changes as a pull request _in addition_ to your pull request to the main project. \
If you have a feature or enhancement that requires additions or changes to in-game text, you will need to make a fork of the `pokerogue-locales` repo and submit your text changes as a pull request _in addition_ to your pull request to the main project.
Since these two PRs aren't _technically_ linked, it's important to coordinate with the Translation Team to ensure that both PRs are integrated safely into the project.
> [!CAUTION]
@ -78,8 +77,8 @@ One perk of submodules is you don't actually _need_ to clone the locales reposit
Given `pokerogue-locales` is a full-fledged `git` repository _inside_ `pokerogue`, making changes is roughly the same as normal, merely using `public/locales` as your root directory.
> [!IMPORTANT]
> Make sure to checkout or rebase onto `upstream/HEAD` **BEFORE** creating a PR! \
> [!WARNING]
> Make sure to checkout or rebase onto `upstream/HEAD` **BEFORE** creating a PR!
> The checked-out commit is based on the superproject's SHA-1 by default, so hastily making changes may see you basing your commits on last week's `HEAD`.
## Requirements for Adding Translated Text
@ -88,7 +87,7 @@ When your new feature or enhancement requires adding a new locales key **without
If this feature requires new text, the text should be integrated into the code with a new `i18next` key pointing to where you plan to add it into the locales repository.
2. You then make another pull request — this time to the `pokerogue-locales` repository — adding a new entry with text for each key you added to your main PR.
- You must add the corresponding **English keys** while making the PR; the Translation Team can take care of the rest[^2].
- For any feature pulled from the mainline Pokémon games (e.g. a Move or Ability implementation), it's best practice to include a source link for any added text. \
- For any feature pulled from the mainline Pokémon games (e.g. a Move or Ability implementation), it's best practice to include a source link for any added text.
[Poké Corpus](https://abcboy101.github.io/poke-corpus/) is a great resource for finding text from the mainline games; otherwise, a video/picture showing the text being displayed should suffice.
- You should also [notify the current Head of Translation](#notifying-translation) to ensure a fast response.
3. At this point, you may begin [testing locales integration in your main PR](#documenting-locales-changes).

Binary file not shown.

Binary file not shown.

BIN
public/fonts/pokemon-bw.ttf Normal file

Binary file not shown.

View File

@ -880,6 +880,10 @@ export abstract class BattleAnim {
targetSprite.pipelineData["tone"] = [0.0, 0.0, 0.0, 0.0];
targetSprite.setAngle(0);
// Remove animation event listeners to enable sprites to be freed.
userSprite.off("animationupdate");
targetSprite.off("animationupdate");
/**
* This and `targetSpriteToShow` are used to restore context lost
* from the `isOppAnim` swap. Using these references instead of `this.user`

View File

@ -1,5 +1,7 @@
export enum GachaType {
MOVE,
LEGENDARY,
SHINY
}
export const GachaType = Object.freeze({
MOVE: 0,
LEGENDARY: 1,
SHINY: 2
});
export type GachaType = typeof GachaType[keyof typeof GachaType];

View File

@ -4,7 +4,7 @@ import CacheBustedLoaderPlugin from "#app/plugins/cache-busted-loader-plugin";
import { SceneBase } from "#app/scene-base";
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
import { isMobile } from "#app/touch-controls";
import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils/common";
import { localPing, getEnumValues, hasAllLocalizedSprites } from "#app/utils/common";
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
import { initBiomes } from "#app/data/balance/biomes";
import { initEggMoves } from "#app/data/balance/egg-moves";
@ -273,7 +273,7 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("egg_icons", "egg");
this.loadAtlas("egg_shard", "egg");
this.loadAtlas("egg_lightrays", "egg");
for (const gt of getEnumKeys(GachaType)) {
for (const gt of Object.keys(GachaType)) {
const key = gt.toLowerCase();
this.loadImage(`gacha_${key}`, "egg");
this.loadAtlas(`gacha_underlay_${key}`, "egg");

View File

@ -65,28 +65,27 @@ const fonts: Array<LoadingFontFaceProperty> = [
unicodeRange: rangesByLanguage.chinese,
}),
extraOptions: { sizeAdjust: "70%", format: "woff2" },
only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru"],
only: ["zh"],
},
{
face: new FontFace("pkmnems", "url(./fonts/unifont-15.1.05.subset.woff2)", {
unicodeRange: rangesByLanguage.chinese,
}),
extraOptions: { format: "woff2" },
only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru"],
only: ["zh"],
},
// japanese
{
face: new FontFace("emerald", "url(./fonts/Galmuri11.subset.woff2)", {
face: new FontFace("emerald", "url(./fonts/pokemon-bw.ttf)", {
unicodeRange: rangesByLanguage.japanese,
}),
extraOptions: { sizeAdjust: "66%" },
only: ["ja"],
only: ["en", "es", "fr", "it", "de", "pt", "ko", "ja", "ca", "da", "tr", "ro", "ru"],
},
{
face: new FontFace("pkmnems", "url(./fonts/Galmuri9.subset.woff2)", {
face: new FontFace("pkmnems", "url(./fonts/pokemon-bw.ttf)", {
unicodeRange: rangesByLanguage.japanese,
}),
only: ["ja"],
only: ["en", "es", "fr", "it", "de", "pt", "ko", "ja", "ca", "da", "tr", "ro", "ru"],
},
];

View File

@ -81,7 +81,7 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.headerBg = addWindow(0, 0, WIDTH - 2, 24);
this.headerText = addTextObject(0, 0, "", TextStyle.SETTINGS_LABEL)
this.headerText = addTextObject(0, 0, "", TextStyle.HEADER_LABEL)
.setOrigin(0)
.setPositionRelative(this.headerBg, 8, 4);
this.headerActionButton = new Phaser.GameObjects.Sprite(globalScene, 0, 0, "keyboard", "ACTION.png")

View File

@ -115,7 +115,7 @@ export default class BallUiHandler extends UiHandler {
updateCounts() {
this.countsText.setText(
Object.values(globalScene.pokeballCounts)
.map(c => `x${c}`)
.map(c => `×${c}`)
.join("\n"),
);
}

View File

@ -96,7 +96,6 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
const levelUpStatsLabelsContent = addTextObject(globalScene.game.canvas.width / 6 - 73, -94, "", TextStyle.WINDOW, {
maxLines: 6,
});
levelUpStatsLabelsContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
let levelUpStatsLabelText = "";
for (const s of PERMANENT_STATS) {
@ -123,7 +122,6 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
TextStyle.WINDOW,
{ maxLines: 6 },
);
levelUpStatsIncrContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
levelUpStatsContainer.add(levelUpStatsIncrContent);
this.levelUpStatsIncrContent = levelUpStatsIncrContent;
@ -135,7 +133,6 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
TextStyle.WINDOW,
{ maxLines: 6, lineSpacing: 5 },
);
levelUpStatsValuesContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
levelUpStatsValuesContent.setOrigin(1, 0);
levelUpStatsValuesContent.setAlign("right");
levelUpStatsContainer.add(levelUpStatsValuesContent);

View File

@ -82,7 +82,7 @@ export default class GameChallengesUiHandler extends UiHandler {
headerBg.setName("window-header-bg");
headerBg.setOrigin(0, 0);
const headerText = addTextObject(0, 0, i18next.t("challenges:title"), TextStyle.SETTINGS_LABEL);
const headerText = addTextObject(0, 0, i18next.t("challenges:title"), TextStyle.HEADER_LABEL);
headerText.setName("text-header");
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);

View File

@ -53,7 +53,12 @@ export default class CommandUiHandler extends UiHandler {
this.commandsContainer.add(this.teraButton);
for (let c = 0; c < commands.length; c++) {
const commandText = addTextObject(c % 2 === 0 ? 0 : 55.8, c < 2 ? 0 : 16, commands[c], TextStyle.WINDOW);
const commandText = addTextObject(
c % 2 === 0 ? 0 : 55.8,
c < 2 ? 0 : 16,
commands[c],
TextStyle.WINDOW_BATTLE_COMMAND,
);
commandText.setName(commands[c]);
this.commandsContainer.add(commandText);
}

View File

@ -1,7 +1,7 @@
import { UiMode } from "#enums/ui-mode";
import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text";
import MessageUiHandler from "./message-ui-handler";
import { getEnumValues, getEnumKeys, fixedInt, randSeedShuffle } from "#app/utils/common";
import { fixedInt, randSeedShuffle, getEnumValues } from "#app/utils/common";
import type { IEggOptions } from "../data/egg";
import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg";
import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
@ -38,6 +38,9 @@ export default class EggGachaUiHandler extends MessageUiHandler {
private summaryFinished: boolean;
private defaultText: string;
/** The tween chain playing the egg drop animation sequence */
private eggDropTweenChain?: Phaser.Tweens.TweenChain;
private scale = 0.1666666667;
private legendaryExpiration = addTextObject(0, 0, "", TextStyle.WINDOW_ALT);
@ -55,18 +58,124 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.defaultText = i18next.t("egg:selectMachine");
}
private setupGachaType(key: keyof typeof GachaType, gachaType: GachaType): void {
const gachaTypeKey = key.toLowerCase();
const gachaContainer = globalScene.add.container(180 * gachaType, 18);
const gacha = globalScene.add.sprite(0, 0, `gacha_${gachaTypeKey}`).setOrigin(0);
const gachaUnderlay = globalScene.add.sprite(115, 80, `gacha_underlay_${gachaTypeKey}`).setOrigin(0);
const gachaEggs = globalScene.add.sprite(0, 0, "gacha_eggs").setOrigin(0);
const gachaGlass = globalScene.add.sprite(0, 0, "gacha_glass").setOrigin(0);
const gachaInfoContainer = globalScene.add.container(160, 46);
const currentLanguage = i18next.resolvedLanguage ?? "en";
let gachaTextStyle = TextStyle.WINDOW_ALT;
let gachaX = 4;
let gachaY = 0;
let pokemonIconX = -20;
let pokemonIconY = 6;
if (["de", "es-ES", "es-MX", "fr", "ko", "pt-BR", "ja", "ru"].includes(currentLanguage)) {
gachaTextStyle = TextStyle.SMALLER_WINDOW_ALT;
gachaX = 2;
gachaY = 2;
}
let legendaryLabelX = gachaX;
let legendaryLabelY = gachaY;
if (["de", "es-ES", "es-MX"].includes(currentLanguage)) {
pokemonIconX = -25;
pokemonIconY = 10;
legendaryLabelX = -6;
legendaryLabelY = 0;
}
const gachaUpLabel = addTextObject(gachaX, gachaY, i18next.t("egg:legendaryUPGacha"), gachaTextStyle).setOrigin(0);
gachaInfoContainer.add(gachaUpLabel);
switch (gachaType as GachaType) {
case GachaType.LEGENDARY:
{
if (["de", "es-ES"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center");
}
let xOffset = 0;
const pokemonIcon = globalScene.add.sprite(pokemonIconX, pokemonIconY, "pokemon_icons_0");
// Intentionally left as "array includes" instead of an equality check to allow for future languages to reuse
if (["pt-BR"].includes(currentLanguage)) {
xOffset = 2;
pokemonIcon.setX(pokemonIconX - 2);
}
gachaUpLabel.setX(legendaryLabelX - xOffset).setY(legendaryLabelY);
pokemonIcon.setScale(0.5).setOrigin(0, 0.5);
gachaInfoContainer.add(pokemonIcon);
}
break;
case GachaType.MOVE:
if (["de", "es-ES", "fr", "pt-BR", "ru"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center").setY(0);
}
gachaUpLabel.setText(i18next.t("egg:moveUPGacha")).setX(0).setOrigin(0.5, 0);
break;
case GachaType.SHINY:
if (["de", "fr", "ko", "ru"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center").setY(0);
}
gachaUpLabel.setText(i18next.t("egg:shinyUPGacha")).setX(0).setOrigin(0.5, 0);
break;
}
const gachaKnob = globalScene.add.sprite(191, 89, "gacha_knob");
const gachaHatch = globalScene.add.sprite(115, 73, "gacha_hatch");
gachaHatch.setOrigin(0).setAlpha(0.9);
gachaGlass.setAlpha(0.5);
gachaContainer.add([gachaEggs, gachaUnderlay, gacha, gachaGlass, gachaKnob, gachaHatch, gachaInfoContainer]);
gachaHatch.on("animationupdate", (_anim, frame) =>
gachaUnderlay.setFrame(frame.textureFrame === "4.png" ? "open_hatch" : "default"),
);
this.gachaContainers.push(gachaContainer);
this.gachaKnobs.push(gachaKnob);
this.gachaHatches.push(gachaHatch);
this.gachaInfoContainers.push(gachaInfoContainer);
this.eggGachaContainer.add(gachaContainer);
if (gachaType === GachaType.LEGENDARY) {
// Expiration timer for the legendary gacha
this.legendaryExpiration
.setText(this.getLegendaryGachaTimeLeft())
.setFontSize("64px")
.setPositionRelative(
gacha,
gacha.width / 2 - this.legendaryExpiration.displayWidth / 2 + 0.3,
gacha.height / 2 + 12.5,
);
gachaContainer.add(this.legendaryExpiration);
this.updateLegendaryGacha();
}
}
setup() {
this.gachaCursor = 0;
this.scale = getTextStyleOptions(TextStyle.WINDOW, globalScene.uiTheme).scale;
const ui = this.getUi();
this.eggGachaContainer = globalScene.add.container(0, -globalScene.game.canvas.height / 6);
this.eggGachaContainer.setVisible(false);
this.eggGachaContainer = globalScene.add.container(0, -globalScene.game.canvas.height / 6).setVisible(false);
ui.add(this.eggGachaContainer);
const bg = globalScene.add.nineslice(0, 0, "default_bg", undefined, 320, 180, 0, 0, 16, 0);
bg.setOrigin(0, 0);
const bg = globalScene.add.nineslice(0, 0, "default_bg", undefined, 320, 180, 0, 0, 16, 0).setOrigin(0);
this.eggGachaContainer.add(bg);
@ -86,144 +195,10 @@ export default class EggGachaUiHandler extends MessageUiHandler {
});
}
getEnumValues(GachaType).forEach((gachaType, g) => {
const gachaTypeKey = GachaType[gachaType].toString().toLowerCase();
const gachaContainer = globalScene.add.container(180 * g, 18);
const gacha = globalScene.add.sprite(0, 0, `gacha_${gachaTypeKey}`);
gacha.setOrigin(0, 0);
const gachaUnderlay = globalScene.add.sprite(115, 80, `gacha_underlay_${gachaTypeKey}`);
gachaUnderlay.setOrigin(0, 0);
const gachaEggs = globalScene.add.sprite(0, 0, "gacha_eggs");
gachaEggs.setOrigin(0, 0);
const gachaGlass = globalScene.add.sprite(0, 0, "gacha_glass");
gachaGlass.setOrigin(0, 0);
const gachaInfoContainer = globalScene.add.container(160, 46);
const currentLanguage = i18next.resolvedLanguage ?? "en";
let gachaTextStyle = TextStyle.WINDOW_ALT;
let gachaX = 4;
let gachaY = 0;
let pokemonIconX = -20;
let pokemonIconY = 6;
if (["de", "es-ES", "es-MX", "fr", "ko", "pt-BR", "ru"].includes(currentLanguage)) {
gachaTextStyle = TextStyle.SMALLER_WINDOW_ALT;
gachaX = 2;
gachaY = 2;
for (const [gachaTypeKey, gachaType] of Object.entries(GachaType)) {
this.setupGachaType(gachaTypeKey as keyof typeof GachaType, gachaType);
}
let legendaryLabelX = gachaX;
let legendaryLabelY = gachaY;
if (["de", "es-ES", "es-MX"].includes(currentLanguage)) {
pokemonIconX = -25;
pokemonIconY = 10;
legendaryLabelX = -6;
legendaryLabelY = 0;
}
const gachaUpLabel = addTextObject(gachaX, gachaY, i18next.t("egg:legendaryUPGacha"), gachaTextStyle);
gachaUpLabel.setOrigin(0, 0);
gachaInfoContainer.add(gachaUpLabel);
switch (gachaType as GachaType) {
case GachaType.LEGENDARY: {
if (["de", "es-ES"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center");
gachaUpLabel.setY(0);
}
if (["pt-BR"].includes(currentLanguage)) {
gachaUpLabel.setX(legendaryLabelX - 2);
} else {
gachaUpLabel.setX(legendaryLabelX);
}
gachaUpLabel.setY(legendaryLabelY);
const pokemonIcon = globalScene.add.sprite(pokemonIconX, pokemonIconY, "pokemon_icons_0");
if (["pt-BR"].includes(currentLanguage)) {
pokemonIcon.setX(pokemonIconX - 2);
}
pokemonIcon.setScale(0.5);
pokemonIcon.setOrigin(0, 0.5);
gachaInfoContainer.add(pokemonIcon);
break;
}
case GachaType.MOVE:
if (["de", "es-ES", "fr", "pt-BR", "ru"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center");
gachaUpLabel.setY(0);
}
gachaUpLabel.setText(i18next.t("egg:moveUPGacha"));
gachaUpLabel.setX(0);
gachaUpLabel.setOrigin(0.5, 0);
break;
case GachaType.SHINY:
if (["de", "fr", "ko", "ru"].includes(currentLanguage)) {
gachaUpLabel.setAlign("center");
gachaUpLabel.setY(0);
}
gachaUpLabel.setText(i18next.t("egg:shinyUPGacha"));
gachaUpLabel.setX(0);
gachaUpLabel.setOrigin(0.5, 0);
break;
}
const gachaKnob = globalScene.add.sprite(191, 89, "gacha_knob");
const gachaHatch = globalScene.add.sprite(115, 73, "gacha_hatch");
gachaHatch.setOrigin(0, 0);
gachaContainer.add(gachaEggs);
gachaContainer.add(gachaUnderlay);
gachaContainer.add(gacha);
gachaContainer.add(gachaGlass);
gachaContainer.add(gachaKnob);
gachaContainer.add(gachaHatch);
gachaContainer.add(gachaInfoContainer);
gachaGlass.setAlpha(0.5);
gachaHatch.setAlpha(0.9);
gachaHatch.on("animationupdate", (_anim, frame) =>
gachaUnderlay.setFrame(frame.textureFrame === "4.png" ? "open_hatch" : "default"),
);
this.gachaContainers.push(gachaContainer);
this.gachaKnobs.push(gachaKnob);
this.gachaHatches.push(gachaHatch);
this.gachaInfoContainers.push(gachaInfoContainer);
this.eggGachaContainer.add(gachaContainer);
// Expiration timer for the legendary gacha
if (gachaType === GachaType.LEGENDARY) {
this.legendaryExpiration
.setText(this.getLegendaryGachaTimeLeft())
.setFontSize("64px")
.setPositionRelative(
gacha,
gacha.width / 2 - this.legendaryExpiration.displayWidth / 2 + 0.3,
gacha.height / 2 + 12.5,
);
gachaContainer.add(this.legendaryExpiration);
}
this.updateGachaInfo(g);
});
this.eggGachaOptionsContainer = globalScene.add.container();
this.eggGachaOptionsContainer = globalScene.add.container(globalScene.game.canvas.width / 6, 148);
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
// Increase egg box width on certain languages
let eggGachaOptionSelectWidth = 0;
switch (i18next.resolvedLanguage) {
case "ru":
@ -233,9 +208,11 @@ export default class EggGachaUiHandler extends MessageUiHandler {
eggGachaOptionSelectWidth = 96;
}
this.eggGachaOptionSelectBg = addWindow(0, 0, eggGachaOptionSelectWidth, 16 + 576 * this.scale);
this.eggGachaOptionSelectBg.setOrigin(1, 1);
this.eggGachaOptionsContainer.add(this.eggGachaOptionSelectBg);
this.eggGachaOptionSelectBg = addWindow(0, 0, eggGachaOptionSelectWidth, 16 + 576 * this.scale).setOrigin(1);
this.eggGachaOptionsContainer = globalScene.add
.container(globalScene.game.canvas.width / 6, 148)
.add(this.eggGachaOptionSelectBg);
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
const multiplierOne = "x1";
const multiplierTen = "x10";
@ -275,25 +252,24 @@ export default class EggGachaUiHandler extends MessageUiHandler {
desc[0] += ["zh", "ko"].includes(resolvedLanguage.substring(0, 2)) ? " " : " ";
}
if (option.multiplier === multiplierOne) {
desc[0] = " " + desc[0];
desc[0] += " ";
}
return ` ${option.multiplier.padEnd(5)}${desc.join(" ")}`;
})
.join("\n");
const optionText = addTextObject(0, 0, `${pullOptionsText}\n${i18next.t("menu:cancel")}`, TextStyle.WINDOW);
optionText.setLineSpacing(28);
optionText.setFontSize("80px");
const optionText = addTextObject(0, 0, `${pullOptionsText}\n${i18next.t("menu:cancel")}`, TextStyle.WINDOW)
.setLineSpacing(28)
.setFontSize("80px")
.setPositionRelative(this.eggGachaOptionSelectBg, 16, 9);
this.eggGachaOptionsContainer.add(optionText);
optionText.setPositionRelative(this.eggGachaOptionSelectBg, 16, 9);
pullOptions.forEach((option, i) => {
const icon = globalScene.add.sprite(0, 0, "items", option.icon);
icon.setScale(3 * this.scale);
icon.setPositionRelative(this.eggGachaOptionSelectBg, 20, 9 + (48 + i * 96) * this.scale);
const icon = globalScene.add
.sprite(0, 0, "items", option.icon)
.setScale(3 * this.scale)
.setPositionRelative(this.eggGachaOptionSelectBg, 20, 9 + (48 + i * 96) * this.scale);
this.eggGachaOptionsContainer.add(icon);
});
@ -302,48 +278,40 @@ export default class EggGachaUiHandler extends MessageUiHandler {
for (const voucher of getEnumValues(VoucherType)) {
const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * voucher, 0);
const bg = addWindow(0, 0, 56, 22);
bg.setOrigin(1, 0);
const bg = addWindow(0, 0, 56, 22).setOrigin(1, 0);
container.add(bg);
const countLabel = addTextObject(-48, 3, "0", TextStyle.WINDOW);
countLabel.setOrigin(0, 0);
const countLabel = addTextObject(-48, 3, "0", TextStyle.WINDOW).setOrigin(0);
container.add(countLabel);
this.voucherCountLabels.push(countLabel);
const iconImage = getVoucherTypeIcon(voucher);
const icon = globalScene.add.sprite(-19, 2, "items", iconImage);
icon.setOrigin(0, 0);
icon.setScale(0.5);
const icon = globalScene.add.sprite(-19, 2, "items", iconImage).setOrigin(0).setScale(0.5);
container.add(icon);
this.eggGachaContainer.add(container);
}
this.eggGachaOverlay = globalScene.add.rectangle(0, 0, bg.displayWidth, bg.displayHeight, 0x000000);
this.eggGachaOverlay.setOrigin(0, 0);
this.eggGachaOverlay.setAlpha(0);
this.eggGachaOverlay = globalScene.add
.rectangle(0, 0, bg.displayWidth, bg.displayHeight, 0x000000)
.setOrigin(0)
.setAlpha(0);
this.eggGachaContainer.add(this.eggGachaOverlay);
this.eggGachaSummaryContainer = globalScene.add.container(0, 0);
this.eggGachaSummaryContainer.setVisible(false);
this.eggGachaSummaryContainer = globalScene.add.container().setVisible(false);
this.eggGachaContainer.add(this.eggGachaSummaryContainer);
const gachaMessageBoxContainer = globalScene.add.container(0, 148);
const gachaMessageBox = addWindow(0, 0, 320, 32);
gachaMessageBox.setOrigin(0, 0);
gachaMessageBoxContainer.add(gachaMessageBox);
const gachaMessageBox = addWindow(0, 0, 320, 32).setOrigin(0);
const gachaMessageBoxContainer = globalScene.add.container(0, 148).add(gachaMessageBox);
this.eggGachaMessageBox = gachaMessageBox;
const gachaMessageText = addTextObject(8, 8, "", TextStyle.WINDOW, {
maxLines: 2,
});
gachaMessageText.setOrigin(0, 0);
}).setOrigin(0);
gachaMessageBoxContainer.add(gachaMessageText);
this.message = gachaMessageText;
@ -363,18 +331,17 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.setGachaCursor(1);
for (let g = 0; g < this.gachaContainers.length; g++) {
this.updateGachaInfo(g);
}
this.updateLegendaryGacha();
this.updateVoucherCounts();
this.getUi().bringToTop(this.eggGachaContainer);
this.eggGachaContainer.setVisible(true);
this.eggGachaContainer.setActive(true).setVisible(true);
handleTutorial(Tutorial.Egg_Gacha);
this.legendaryExpiration.setText(this.getLegendaryGachaTimeLeft());
this.legendaryGachaTimer();
return true;
@ -387,105 +354,116 @@ export default class EggGachaUiHandler extends MessageUiHandler {
return fixedInt(delay);
}
pull(pullCount = 0, count = 0, eggs?: Egg[]): void {
if (Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE && !count) {
pullCount = Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE;
}
this.eggGachaOptionsContainer.setVisible(false);
this.setTransitioning(true);
const doPull = () => {
if (this.transitionCancelled) {
return this.showSummary(eggs!);
}
const egg = globalScene.add.sprite(127, 75, "egg", `egg_${eggs![count].getKey()}`);
egg.setScale(0.5);
this.gachaContainers[this.gachaCursor].add(egg);
this.gachaContainers[this.gachaCursor].moveTo(egg, 2);
const doPullAnim = () => {
globalScene.playSound("se/gacha_running", { loop: true });
globalScene.time.delayedCall(this.getDelayValue(count ? 500 : 1250), () => {
globalScene.playSound("se/gacha_dispense");
globalScene.time.delayedCall(this.getDelayValue(750), () => {
globalScene.sound.stopByKey("se/gacha_running");
globalScene.tweens.add({
targets: egg,
duration: this.getDelayValue(350),
y: 95,
ease: "Bounce.easeOut",
onComplete: () => {
globalScene.time.delayedCall(this.getDelayValue(125), () => {
globalScene.playSound("se/pb_catch");
this.gachaHatches[this.gachaCursor].play("open");
globalScene.tweens.add({
targets: egg,
duration: this.getDelayValue(350),
scale: 0.75,
ease: "Sine.easeIn",
});
globalScene.tweens.add({
targets: egg,
y: 110,
duration: this.getDelayValue(350),
ease: "Back.easeOut",
onComplete: () => {
this.gachaHatches[this.gachaCursor].play("close");
globalScene.tweens.add({
targets: egg,
y: 200,
duration: this.getDelayValue(350),
ease: "Cubic.easeIn",
onComplete: () => {
if (++count < pullCount) {
this.pull(pullCount, count, eggs);
} else {
this.showSummary(eggs!);
}
},
});
},
});
});
},
});
});
});
};
if (!count) {
private firstDropAnims(): Phaser.Types.Tweens.TweenBuilderConfig[] {
globalScene.playSound("se/gacha_dial");
globalScene.tweens.add({
return [
// Tween 1 animates the gacha knob turning left
{
targets: this.gachaKnobs[this.gachaCursor],
duration: this.getDelayValue(350),
angle: 90,
ease: "Cubic.easeInOut",
onComplete: () => {
globalScene.tweens.add({
},
// Tween 2 animates the gacha knob turning back
{
targets: this.gachaKnobs[this.gachaCursor],
duration: this.getDelayValue(350),
angle: 0,
ease: "Sine.easeInOut",
});
globalScene.time.delayedCall(this.getDelayValue(350), doPullAnim);
},
});
} else {
doPullAnim();
// Tween 3 is a dummy tween, used to force a delay, that commences the gacha running sound
{
targets: { dummy: 0 },
dummy: 1,
duration: this.getDelayValue(350),
onStart: () => {
globalScene.playSound("se/gacha_running", { loop: true });
},
},
// Tween 4 is another dummy tween that plays the gacha dispense sound
{
delay: this.getDelayValue(1250),
onStart: () => {
globalScene.playSound("se/gacha_dispense");
},
targets: { dummy: 0 },
dummy: 1,
duration: this.getDelayValue(750),
onComplete: () => {
globalScene.sound.stopByKey("se/gacha_running");
},
},
];
}
};
if (!pullCount) {
pullCount = 1;
private async doPullAnim(egg: Phaser.GameObjects.Sprite, count: number): Promise<void> {
let resolve: (value: void | PromiseLike<void>) => void;
const hatch = this.gachaHatches[this.gachaCursor];
/** The rate of animations and tweens that play for drops after the first */
const rate = count ? 1.25 : 1.0;
if (count) {
hatch.anims.timeScale = rate;
}
if (!count) {
count = 0;
const promise: Promise<void> = new Promise(res => {
resolve = res;
});
const tweens: Phaser.Types.Tweens.TweenBuilderConfig[] = count ? [] : this.firstDropAnims();
tweens.push(
// Tween 1 is responsible for animating the egg dropping from the gacha
{
targets: egg,
duration: this.getDelayValue(350 / rate),
y: 95,
ease: "Bounce.easeOut",
},
// Tween 2 plays the catch sound and moves the egg up a bit
{
onStart: () => {
globalScene.playSound("se/pb_catch");
this.gachaHatches[this.gachaCursor].play("open");
},
targets: egg,
delay: this.getDelayValue(125 / rate),
duration: this.getDelayValue(350 / rate),
props: {
scale: { value: 0.75, ease: "Sine.easeIn" },
y: { value: 110, ease: "Back.easeOut" },
},
},
// Tween 3 "closes" the gacha hatch and moves the egg up while enlarging it
{
onStart: () => {
this.gachaHatches[this.gachaCursor].play("close");
},
targets: egg,
y: 200,
duration: this.getDelayValue(350 / rate),
ease: "Cubic.easeIn",
},
);
this.eggDropTweenChain = globalScene.tweens.chain({
onComplete: () => {
this.eggDropTweenChain = undefined;
hatch.anims.timeScale = 1; // Reset the hatch animation time scale
resolve();
},
tweens,
});
return promise;
}
if (!eggs) {
eggs = [];
/**
* Pulls the specified number of eggs and returns them
* @param pullCount - The number of eggs to pull
* @returns An array of the pulled eggs
*/
private pullEggs(pullCount: number): Egg[] {
const eggs: Egg[] = [];
for (let i = 1; i <= pullCount; i++) {
const eggOptions: IEggOptions = {
pulled: true,
@ -496,7 +474,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
// if not, override the egg tier
if (i === pullCount) {
const guaranteedEggTier = this.getGuaranteedEggTierFromPullCount(pullCount);
if (!eggs.some(egg => egg.tier >= guaranteedEggTier) && guaranteedEggTier !== EggTier.COMMON) {
if (guaranteedEggTier !== EggTier.COMMON && !eggs.some(egg => egg.tier >= guaranteedEggTier)) {
eggOptions.tier = guaranteedEggTier;
}
}
@ -505,24 +483,59 @@ export default class EggGachaUiHandler extends MessageUiHandler {
eggs.push(egg);
}
// Shuffle the eggs in case the guaranteed one got added as last egg
eggs = randSeedShuffle<Egg>(eggs);
return randSeedShuffle(eggs);
}
(globalScene.currentBattle
/**
* Handle pulling eggs from the gacha machine; plays the animations, adds the eggs, and saves game data
* @param pullCount - The number of eggs to pull
*/
async pull(pullCount = 0): Promise<void> {
if (Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE) {
pullCount = Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE;
}
// Set the eggs
const eggs = this.pullEggs(pullCount);
this.eggGachaOptionsContainer.setVisible(false);
this.setTransitioning(true);
const saveSuccess = await (globalScene.currentBattle
? globalScene.gameData.saveAll(true, true, true)
: globalScene.gameData.saveSystem()
).then(success => {
if (!success) {
return globalScene.reset(true);
globalScene.reset(true);
return false;
}
doPull();
return true;
});
if (!saveSuccess) {
return;
}
doPull();
const gachaContainer = this.gachaContainers[this.gachaCursor];
for (let i = 0; i < pullCount; ++i) {
if (this.transitionCancelled) {
break;
}
const eggSprite = globalScene.add.sprite(127, 75, "egg", `egg_${eggs[i].getKey()}`).setScale(0.5);
gachaContainer.addAt(eggSprite, 2);
// biome-ignore lint/nursery/noAwaitInLoop: The point of this loop is to play the animations, one after another
await this.doPullAnim(eggSprite, i).finally(() => gachaContainer.remove(eggSprite, true));
}
getGuaranteedEggTierFromPullCount(pullCount: number): EggTier {
this.showSummary(eggs);
}
/**
* Get the guaranteed egg tier based on the pull count
* @param pullCount - The number of pulls made
* @returns The guaranteed egg tier for the given pull count
*/
private getGuaranteedEggTierFromPullCount(pullCount: number): EggTier {
switch (pullCount) {
case 10:
return EggTier.RARE;
@ -611,9 +624,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
duration: this.getDelayValue(250),
ease: "Cubic.easeIn",
onComplete: () => {
this.eggGachaSummaryContainer.setVisible(false);
this.eggGachaSummaryContainer.setAlpha(1);
this.eggGachaSummaryContainer.removeAll(true);
this.eggGachaSummaryContainer.setVisible(false).setAlpha(1).removeAll(true);
this.setTransitioning(false);
this.summaryFinished = false;
this.eggGachaOptionsContainer.setVisible(true);
@ -621,16 +632,14 @@ export default class EggGachaUiHandler extends MessageUiHandler {
});
}
updateGachaInfo(gachaType: GachaType): void {
const infoContainer = this.gachaInfoContainers[gachaType];
switch (gachaType as GachaType) {
case GachaType.LEGENDARY: {
/**
* Update the legendary gacha icon based on the current timestamp.
*/
private updateLegendaryGacha(): void {
const infoContainer = this.gachaInfoContainers[GachaType.LEGENDARY];
const species = getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(Date.now()));
const pokemonIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite;
pokemonIcon.setTexture(species.getIconAtlasKey(), species.getIconId(false));
break;
}
}
}
consumeVouchers(voucherType: VoucherType, count: number): void {
@ -684,117 +693,101 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.transitionCancelled = false;
}
processInput(button: Button): boolean {
/**
* Convert a cursor index to a voucher type and count
* @param cursor - The cursor index corresponding to the voucher type
* @returns The voucher type, vouchers used, and pulls given, or an empty array if the cursor is not on a voucher
*/
private static cursorToVoucher(cursor: number): [VoucherType, number, number] | undefined {
switch (cursor) {
case 0:
return [VoucherType.REGULAR, 1, 1];
case 1:
return [VoucherType.REGULAR, 10, 10];
case 2:
return [VoucherType.PLUS, 1, 5];
case 3:
return [VoucherType.PREMIUM, 1, 10];
case 4:
return [VoucherType.GOLDEN, 1, 25];
}
}
/**
* Process an action input received during voucher selection.
*
* @remarks
*
* Handles playing the error sound and showing the error message, but does not handle playing the success sound.
*
* @param cursor - The index of the voucher menu option
* @returns True if the success sound should be played, false if the error sound should be played, or undefined if the cursor is out of range.
*/
private handleVoucherSelectAction(cursor: number): boolean | undefined {
// Cursors that are out of range should not be processed
if (cursor < 0 || cursor > 5) {
return;
}
const ui = this.getUi();
const voucher = EggGachaUiHandler.cursorToVoucher(cursor);
if (!voucher) {
ui.revertMode();
return true;
}
const [voucherType, vouchersConsumed, pulls] = voucher;
let success = false;
let error = false;
let errorKey: string | undefined;
const freePulls = Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE;
if (this.transitioning) {
if (!this.transitionCancelled && (button === Button.ACTION || button === Button.CANCEL)) {
this.transitionCancelled = true;
success = true;
} else {
if (!freePulls && globalScene.gameData.eggs.length + pulls > 99) {
errorKey = "egg:tooManyEggs";
} else if (!freePulls && !globalScene.gameData.voucherCounts[voucherType]) {
errorKey = "egg:notEnoughVouchers";
}
if (errorKey) {
this.showError(i18next.t(errorKey));
return false;
}
} else {
if (this.eggGachaSummaryContainer.visible) {
if (this.summaryFinished && (button === Button.ACTION || button === Button.CANCEL)) {
this.hideSummary();
success = true;
if (!freePulls) {
this.consumeVouchers(voucherType, vouchersConsumed);
}
} else {
// TODO: Remove this dangling proimse if necessary when the UI's input event handling supports async functions
void this.pull(pulls);
return true;
}
/**
* Process an input received while the egg gacha UI is transitioning
*
* @param button - The button that was pressed
* @returns - `true` if the success sound should be played, otherwise `undefined`
*/
private processTransitionInput(button: Button): true | undefined {
if (!this.transitionCancelled && (button === Button.ACTION || button === Button.CANCEL)) {
this.transitionCancelled = true;
// When transition is cancelled, ensure the active chain playing the egg drop animation is sped up
// We cannot cancel it, as this would leave sprite positions at their current position in the animation
this.eggDropTweenChain?.setTimeScale(50);
return true;
}
}
/**
* Process an input received in the normal mode of the egg gacha UI (not transitoning, not summary)
* @param button - The button that was pressed
* @returns `true` if the success sound should be played, `false` if the error sound should be played, or `undefined` no input event occurred.
*/
private processNormalInput(button: Button): boolean | undefined {
const ui = this.getUi();
let success: boolean | undefined;
switch (button) {
case Button.ACTION:
switch (this.cursor) {
case 0:
if (
!globalScene.gameData.voucherCounts[VoucherType.REGULAR] &&
!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE
) {
error = true;
this.showError(i18next.t("egg:notEnoughVouchers"));
} else if (globalScene.gameData.eggs.length < 99 || Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
if (!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
this.consumeVouchers(VoucherType.REGULAR, 1);
}
this.pull();
success = true;
} else {
error = true;
this.showError(i18next.t("egg:tooManyEggs"));
}
break;
case 2:
if (!globalScene.gameData.voucherCounts[VoucherType.PLUS] && !Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
error = true;
this.showError(i18next.t("egg:notEnoughVouchers"));
} else if (globalScene.gameData.eggs.length < 95 || Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
if (!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
this.consumeVouchers(VoucherType.PLUS, 1);
}
this.pull(5);
success = true;
} else {
error = true;
this.showError(i18next.t("egg:tooManyEggs"));
}
break;
case 1:
case 3:
if (
(this.cursor === 1 &&
globalScene.gameData.voucherCounts[VoucherType.REGULAR] < 10 &&
!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) ||
(this.cursor === 3 &&
!globalScene.gameData.voucherCounts[VoucherType.PREMIUM] &&
!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE)
) {
error = true;
this.showError(i18next.t("egg:notEnoughVouchers"));
} else if (globalScene.gameData.eggs.length < 90 || Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
if (this.cursor === 3) {
if (!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
this.consumeVouchers(VoucherType.PREMIUM, 1);
}
} else {
if (!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
this.consumeVouchers(VoucherType.REGULAR, 10);
}
}
this.pull(10);
success = true;
} else {
error = true;
this.showError(i18next.t("egg:tooManyEggs"));
}
break;
case 4:
if (
!globalScene.gameData.voucherCounts[VoucherType.GOLDEN] &&
!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE
) {
error = true;
this.showError(i18next.t("egg:notEnoughVouchers"));
} else if (globalScene.gameData.eggs.length < 75 || Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
if (!Overrides.EGG_FREE_GACHA_PULLS_OVERRIDE) {
this.consumeVouchers(VoucherType.GOLDEN, 1);
}
this.pull(25);
success = true;
} else {
error = true;
this.showError(i18next.t("egg:tooManyEggs"));
}
break;
case 5:
ui.revertMode();
success = true;
break;
}
break;
return this.handleVoucherSelectAction(this.cursor);
case Button.CANCEL:
this.getUi().revertMode();
ui.revertMode();
success = true;
break;
case Button.UP:
@ -813,21 +806,52 @@ export default class EggGachaUiHandler extends MessageUiHandler {
}
break;
case Button.RIGHT:
if (this.gachaCursor < getEnumKeys(GachaType).length - 1) {
if (this.gachaCursor < Object.keys(GachaType).length - 1) {
success = this.setGachaCursor(this.gachaCursor + 1);
}
break;
}
// Return undefined here because we do not play error sound in case of failed directional movements
return success || undefined;
}
/**
* Handles an input event that occurs while the egg gacha summary is visible
* @param button - The button that was pressed
* @returns `true` if an input event occurred and the select sound should be played, otherwise `undefined`
*/
private processSummaryInput(button: Button): true | undefined {
if (this.summaryFinished && (button === Button.ACTION || button === Button.CANCEL)) {
this.hideSummary();
return true;
}
}
/**
*
* @param button - The button that was pressed
* @returns - Whether an input event occured.
*/
processInput(button: Button): boolean {
let success: boolean | undefined;
if (this.transitioning) {
success = this.processTransitionInput(button);
} else if (this.eggGachaSummaryContainer.visible) {
success = this.processSummaryInput(button);
} else {
success = this.processNormalInput(button);
}
if (success === undefined) {
return false;
}
if (success) {
ui.playSelect();
} else if (error) {
ui.playError();
this.getUi().playSelect();
} else {
this.getUi().playError();
}
return success || error;
return true;
}
setCursor(cursor: number): boolean {
@ -898,5 +922,6 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.playTimeTimer.destroy();
this.playTimeTimer = null;
}
this.eggGachaContainer.setActive(false);
}
}

View File

@ -49,11 +49,11 @@ export default class EggListUiHandler extends MessageUiHandler {
this.eggNameText = addTextObject(8, 68, "", TextStyle.SUMMARY).setOrigin(0);
this.eggDateText = addTextObject(8, 91, "", TextStyle.TOOLTIP_CONTENT);
this.eggDateText = addTextObject(8, 91, "", TextStyle.EGG_LIST);
this.eggHatchWavesText = addTextObject(8, 108, "", TextStyle.TOOLTIP_CONTENT).setWordWrapWidth(540);
this.eggHatchWavesText = addTextObject(8, 108, "", TextStyle.EGG_LIST).setWordWrapWidth(540);
this.eggGachaInfoText = addTextObject(8, 152, "", TextStyle.TOOLTIP_CONTENT).setWordWrapWidth(540);
this.eggGachaInfoText = addTextObject(8, 152, "", TextStyle.EGG_LIST).setWordWrapWidth(540);
this.eggListIconContainer = globalScene.add.container(113, 5);

View File

@ -60,7 +60,7 @@ export class FilterBar extends Phaser.GameObjects.Container {
this.columns.push(column);
const filterTypesLabel = addTextObject(0, 3, title, TextStyle.TOOLTIP_CONTENT);
const filterTypesLabel = addTextObject(0, 3, title, TextStyle.FILTER_BAR_MAIN);
this.labels.push(filterTypesLabel);
this.add(filterTypesLabel);
this.dropDowns.push(dropDown);

View File

@ -243,7 +243,7 @@ export default class GameStatsUiHandler extends UiHandler {
const headerBg = addWindow(0, 0, globalScene.game.canvas.width / 6 - 2, 24);
headerBg.setOrigin(0, 0);
const headerText = addTextObject(0, 0, i18next.t("gameStatsUiHandler:stats"), TextStyle.SETTINGS_LABEL);
const headerText = addTextObject(0, 0, i18next.t("gameStatsUiHandler:stats"), TextStyle.HEADER_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);

View File

@ -80,7 +80,6 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
},
},
);
this.desc.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
// limit the text rendering, required for scrolling later on
const maskPointOrigin = {

View File

@ -517,7 +517,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
descriptionTextObject.setMask(abilityDescriptionTextMask);
const descriptionLineCount = Math.floor(descriptionTextObject.displayHeight / 10);
const descriptionLineCount = Math.floor(descriptionTextObject.displayHeight / 9.2);
if (this.descriptionScrollTween) {
this.descriptionScrollTween.remove();
@ -614,6 +614,8 @@ export default class MysteryEncounterUiHandler extends UiHandler {
const tooltipTextObject = addBBCodeTextObject(6, 7, text, TextStyle.TOOLTIP_CONTENT, {
wordWrap: { width: 600 },
fontSize: "72px",
padding: { top: 8 },
lineSpacing: 1.25,
});
this.tooltipContainer.add(tooltipTextObject);
@ -627,7 +629,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
const textMask = tooltipTextMaskRect.createGeometryMask();
tooltipTextObject.setMask(textMask);
const tooltipLineCount = Math.floor(tooltipTextObject.displayHeight / 11.2);
const tooltipLineCount = Math.floor(tooltipTextObject.displayHeight / 10.2);
if (this.tooltipScrollTween) {
this.tooltipScrollTween.remove();

View File

@ -2069,7 +2069,7 @@ class PartyCancelButton extends Phaser.GameObjects.Container {
this.partyCancelPb = partyCancelPb;
const partyCancelText = addTextObject(-8, -7, i18next.t("partyUiHandler:cancel"), TextStyle.PARTY);
const partyCancelText = addTextObject(-10, -7, i18next.t("partyUiHandler:cancel"), TextStyle.PARTY_CANCEL_BUTTON);
this.add(partyCancelText);
}

View File

@ -2,7 +2,6 @@ import type { InfoToggle } from "../battle-scene";
import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme";
import { fixedInt } from "#app/utils/common";
import i18next from "i18next";
import { globalScene } from "#app/global-scene";
export interface PokedexInfoOverlaySettings {
@ -55,7 +54,6 @@ export default class PokedexInfoOverlay extends Phaser.GameObjects.Container imp
this.desc = addTextObject(BORDER, BORDER - 2, "", TextStyle.BATTLE_INFO, {
wordWrap: { width: (this.width - (BORDER - 2) * 2) * GLOBAL_SCALE },
});
this.desc.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
// limit the text rendering, required for scrolling later on
this.maskPointOriginX = options?.x || 0;

View File

@ -82,13 +82,21 @@ const languageSettings: { [key: string]: LanguageSetting } = {
instructionTextSize: "38px",
},
de: {
starterInfoTextSize: "48px",
starterInfoTextSize: "54px",
instructionTextSize: "35px",
starterInfoXPos: 33,
starterInfoXPos: 35,
},
"es-ES": {
starterInfoTextSize: "56px",
instructionTextSize: "35px",
starterInfoTextSize: "50px",
instructionTextSize: "38px",
starterInfoYOffset: 0.5,
starterInfoXPos: 38,
},
"es-MX": {
starterInfoTextSize: "50px",
instructionTextSize: "38px",
starterInfoYOffset: 0.5,
starterInfoXPos: 38,
},
fr: {
starterInfoTextSize: "54px",
@ -98,34 +106,53 @@ const languageSettings: { [key: string]: LanguageSetting } = {
starterInfoTextSize: "56px",
instructionTextSize: "38px",
},
pt_BR: {
starterInfoTextSize: "47px",
instructionTextSize: "38px",
"pt-BR": {
starterInfoTextSize: "48px",
instructionTextSize: "42px",
starterInfoYOffset: 0.5,
starterInfoXPos: 33,
},
zh: {
starterInfoTextSize: "47px",
instructionTextSize: "38px",
starterInfoYOffset: 1,
starterInfoXPos: 24,
},
pt: {
starterInfoTextSize: "48px",
instructionTextSize: "42px",
starterInfoXPos: 33,
starterInfoTextSize: "56px",
instructionTextSize: "36px",
starterInfoXPos: 26,
},
ko: {
starterInfoTextSize: "52px",
starterInfoTextSize: "60px",
instructionTextSize: "38px",
starterInfoYOffset: -0.5,
starterInfoXPos: 30,
},
ja: {
starterInfoTextSize: "51px",
instructionTextSize: "38px",
starterInfoTextSize: "48px",
instructionTextSize: "40px",
starterInfoYOffset: 1,
starterInfoXPos: 32,
},
"ca-ES": {
ca: {
starterInfoTextSize: "48px",
instructionTextSize: "38px",
starterInfoYOffset: 0.5,
starterInfoXPos: 29,
},
da: {
starterInfoTextSize: "56px",
instructionTextSize: "38px",
},
tr: {
starterInfoTextSize: "56px",
instructionTextSize: "38px",
},
ro: {
starterInfoTextSize: "56px",
instructionTextSize: "38px",
},
ru: {
starterInfoTextSize: "46px",
instructionTextSize: "38px",
starterInfoYOffset: 0.5,
starterInfoXPos: 26,
},
};
const valueReductionMax = 2;
@ -309,7 +336,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.shinyOverlay.setVisible(false);
this.starterSelectContainer.add(this.shinyOverlay);
this.pokemonNumberText = addTextObject(17, 1, "0000", TextStyle.SUMMARY);
this.pokemonNumberText = addTextObject(17, 1, "0000", TextStyle.SUMMARY_DEX_NUM);
this.pokemonNumberText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNumberText);
@ -328,7 +355,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.pokemonGrowthRateLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonGrowthRateLabelText);
this.pokemonGrowthRateText = addTextObject(34, 106, "", TextStyle.SUMMARY_PINK, { fontSize: "36px" });
this.pokemonGrowthRateText = addTextObject(34, 106, "", TextStyle.GROWTH_RATE_TYPE, { fontSize: "36px" });
this.pokemonGrowthRateText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonGrowthRateText);
@ -371,9 +398,15 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.pokemonLuckLabelText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonLuckLabelText);
this.pokemonLuckText = addTextObject(8 + this.pokemonLuckLabelText.displayWidth + 2, 89, "0", TextStyle.WINDOW, {
this.pokemonLuckText = addTextObject(
8 + this.pokemonLuckLabelText.displayWidth + 2,
89,
"0",
TextStyle.LUCK_VALUE,
{
fontSize: "56px",
});
},
);
this.pokemonLuckText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonLuckText);
@ -470,7 +503,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("pokedexUiHandler:candyUpgrade"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.candyUpgradeLabel.setName("text-candyUpgrade-label");
@ -491,7 +524,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("pokedexUiHandler:cycleShiny"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.shinyLabel.setName("text-shiny-label");
@ -510,7 +543,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("pokedexUiHandler:cycleForm"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.formLabel.setName("text-form-label");
@ -529,7 +562,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("pokedexUiHandler:cycleGender"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.genderLabel.setName("text-gender-label");
@ -548,7 +581,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("pokedexUiHandler:cycleVariant"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.variantLabel.setName("text-variant-label");
@ -557,9 +590,15 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.showBackSpriteIconElement.setName("show-backSprite-icon-element");
this.showBackSpriteIconElement.setScale(0.675);
this.showBackSpriteIconElement.setOrigin(0.0, 0.0);
this.showBackSpriteLabel = addTextObject(60, 7, i18next.t("pokedexUiHandler:showBackSprite"), TextStyle.PARTY, {
this.showBackSpriteLabel = addTextObject(
60,
7,
i18next.t("pokedexUiHandler:showBackSprite"),
TextStyle.INSTRUCTIONS_TEXT,
{
fontSize: instructionTextSize,
});
},
);
this.showBackSpriteLabel.setName("show-backSprite-label");
this.starterSelectContainer.add(this.showBackSpriteIconElement);
this.starterSelectContainer.add(this.showBackSpriteLabel);
@ -1899,14 +1938,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
if (!(passiveAttr & PassiveAttr.UNLOCKED)) {
const passiveCost = getPassiveCandyCount(speciesStarterCosts[this.starterId]);
options.push({
label: `x${passiveCost} ${i18next.t("pokedexUiHandler:unlockPassive")}`,
label: `×${passiveCost} ${i18next.t("pokedexUiHandler:unlockPassive")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= passiveCost) {
starterData.passiveAttr |= PassiveAttr.UNLOCKED | PassiveAttr.ENABLED;
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= passiveCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
globalScene.gameData.saveSystem().then(success => {
if (!success) {
return globalScene.reset(true);
@ -1931,14 +1970,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
if (valueReduction < valueReductionMax) {
const reductionCost = getValueReductionCandyCounts(speciesStarterCosts[this.starterId])[valueReduction];
options.push({
label: `x${reductionCost} ${i18next.t("pokedexUiHandler:reduceCost")}`,
label: `×${reductionCost} ${i18next.t("pokedexUiHandler:reduceCost")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= reductionCost) {
starterData.valueReduction++;
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= reductionCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
globalScene.gameData.saveSystem().then(success => {
if (!success) {
return globalScene.reset(true);
@ -1960,7 +1999,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
// Same species egg menu option.
const sameSpeciesEggCost = getSameSpeciesEggCandyCounts(speciesStarterCosts[this.starterId]);
options.push({
label: `x${sameSpeciesEggCost} ${i18next.t("pokedexUiHandler:sameSpeciesEgg")}`,
label: `×${sameSpeciesEggCost} ${i18next.t("pokedexUiHandler:sameSpeciesEgg")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= sameSpeciesEggCost) {
if (globalScene.gameData.eggs.length >= 99 && !Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
@ -1979,7 +2018,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= sameSpeciesEggCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
const egg = new Egg({
scene: globalScene,
@ -2480,9 +2519,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
const isFormSeen = this.isSeen();
this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default?
this.pokemonNumberText.setColor(this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, false));
this.pokemonNumberText.setColor(
this.getTextColor(shiny ? TextStyle.SUMMARY_DEX_NUM_GOLD : TextStyle.SUMMARY_DEX_NUM, false),
);
this.pokemonNumberText.setShadowColor(
this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, true),
this.getTextColor(shiny ? TextStyle.SUMMARY_DEX_NUM_GOLD : TextStyle.SUMMARY_DEX_NUM, true),
);
const assetLoadCancelled = new BooleanHolder(false);
@ -2634,7 +2675,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0])));
this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.pokemonCandyCountText.setText(
`x${species.speciesId === SpeciesId.PIKACHU ? 0 : globalScene.gameData.starterData[this.starterId].candyCount}`,
`×${species.speciesId === SpeciesId.PIKACHU ? 0 : globalScene.gameData.starterData[this.starterId].candyCount}`,
);
this.pokemonCandyContainer.setVisible(true);

View File

@ -471,7 +471,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
this.pokemonNameText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNameText);
this.pokemonFormText = addTextObject(6, 121, "", TextStyle.PARTY, {
this.pokemonFormText = addTextObject(6, 121, "", TextStyle.INSTRUCTIONS_TEXT, {
fontSize: textSettings.instructionTextSize,
});
this.pokemonFormText.setOrigin(0, 0);
@ -562,7 +562,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
this.goFilterIconElement2.setName("sprite-goFilter2-icon-element");
this.goFilterIconElement2.setScale(0.675);
this.goFilterIconElement2.setOrigin(0.0, 0.0);
this.goFilterLabel = addTextObject(30, 2, i18next.t("pokedexUiHandler:goFilters"), TextStyle.PARTY, {
this.goFilterLabel = addTextObject(30, 2, i18next.t("pokedexUiHandler:goFilters"), TextStyle.INSTRUCTIONS_TEXT, {
fontSize: instructionTextSize,
});
this.goFilterLabel.setName("text-goFilter-label");
@ -578,7 +578,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
20,
10,
i18next.t("pokedexUiHandler:toggleDecorations"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.toggleDecorationsLabel.setName("text-toggleDecorations-label");
@ -589,9 +589,15 @@ export default class PokedexUiHandler extends MessageUiHandler {
this.showFormTrayIconElement.setName("sprite-showFormTray-icon-element");
this.showFormTrayIconElement.setScale(0.675);
this.showFormTrayIconElement.setOrigin(0.0, 0.0);
this.showFormTrayLabel = addTextObject(16, 168, i18next.t("pokedexUiHandler:showForms"), TextStyle.PARTY, {
this.showFormTrayLabel = addTextObject(
16,
168,
i18next.t("pokedexUiHandler:showForms"),
TextStyle.INSTRUCTIONS_TEXT,
{
fontSize: instructionTextSize,
});
},
);
this.showFormTrayLabel.setName("text-showFormTray-label");
this.showFormTrayIconElement.setVisible(false);
this.showFormTrayLabel.setVisible(false);

View File

@ -49,13 +49,11 @@ export default class PokemonHatchInfoContainer extends PokemonInfoContainer {
this.pokemonListContainer.add(this.currentPokemonSprite);
// setup name and number
this.pokemonNumberText = addTextObject(80, 107.5, "0000", TextStyle.SUMMARY, { fontSize: 74 });
this.pokemonNumberText = addTextObject(84, 107, "0000", TextStyle.EGG_SUMMARY_DEX, { fontSize: 78 });
this.pokemonNumberText.setOrigin(0, 0);
this.pokemonListContainer.add(this.pokemonNumberText);
this.pokemonNameText = addTextObject(7, 107.5, "", TextStyle.SUMMARY, {
fontSize: 74,
});
this.pokemonNameText = addTextObject(7, 109, "", TextStyle.EGG_SUMMARY_NAME, { fontSize: 64 });
this.pokemonNameText.setOrigin(0, 0);
this.pokemonListContainer.add(this.pokemonNameText);
@ -93,7 +91,7 @@ export default class PokemonHatchInfoContainer extends PokemonInfoContainer {
const eggMoveBg = globalScene.add.nineslice(70, 0, "type_bgs", "unknown", 92, 14, 2, 2, 2, 2);
eggMoveBg.setOrigin(1, 0);
const eggMoveLabel = addTextObject(70 - eggMoveBg.width / 2, 0, "???", TextStyle.PARTY);
const eggMoveLabel = addTextObject(70 - eggMoveBg.width / 2, 0, "???", TextStyle.MOVE_LABEL);
eggMoveLabel.setOrigin(0.5, 0);
this.pokemonEggMoveBgs.push(eggMoveBg);
@ -158,7 +156,7 @@ export default class PokemonHatchInfoContainer extends PokemonInfoContainer {
this.pokemonCandyIcon.setVisible(true);
this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.pokemonCandyOverlayIcon.setVisible(true);
this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[species.speciesId].candyCount}`);
this.pokemonCandyCountText.setText(`×${globalScene.gameData.starterData[species.speciesId].candyCount}`);
this.pokemonCandyCountText.setVisible(true);
this.pokemonNumberText.setText(padInt(species.speciesId, 4));

View File

@ -22,11 +22,21 @@ interface LanguageSetting {
}
const languageSettings: { [key: string]: LanguageSetting } = {
en: {
infoContainerTextSize: "64px",
infoContainerLabelXPos: -20,
infoContainerTextXPos: -17,
},
pt: {
infoContainerTextSize: "60px",
infoContainerLabelXPos: -15,
infoContainerTextXPos: -12,
},
ja: {
infoContainerTextSize: "64px",
infoContainerLabelXPos: -27,
infoContainerTextXPos: -25,
},
};
export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
@ -106,7 +116,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
moveBg.setOrigin(1, 0);
moveBg.setName("nineslice-move-bg");
const moveLabel = addTextObject(-moveBg.width / 2, 0, "-", TextStyle.PARTY);
const moveLabel = addTextObject(-moveBg.width / 2, 0, "-", TextStyle.MOVE_LABEL);
moveLabel.setOrigin(0.5, 0);
moveLabel.setName("text-move-label");
@ -445,12 +455,12 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
this.pokemonShinyIcon.setPosition(82, 87);
this.pokemonShinyNewIcon.setPosition(72, 87);
this.pokemonFormLabelText.setPosition(infoContainerLabelXPos, 152);
this.pokemonFormText.setPosition(infoContainerTextXPos, 152);
this.pokemonAbilityLabelText.setPosition(infoContainerLabelXPos, 110);
this.pokemonAbilityText.setPosition(infoContainerTextXPos, 110);
this.pokemonNatureLabelText.setPosition(infoContainerLabelXPos, 125);
this.pokemonNatureText.setPosition(infoContainerTextXPos, 125);
this.pokemonFormLabelText.setPosition(infoContainerLabelXPos, 153);
this.pokemonFormText.setPosition(infoContainerTextXPos, 153);
this.pokemonAbilityLabelText.setPosition(infoContainerLabelXPos, 111);
this.pokemonAbilityText.setPosition(infoContainerTextXPos, 111);
this.pokemonNatureLabelText.setPosition(infoContainerLabelXPos, 126);
this.pokemonNatureText.setPosition(infoContainerTextXPos, 126);
this.statsContainer.setScale(0.7);
this.statsContainer.setPosition(30, -3);

View File

@ -202,7 +202,7 @@ export default class RunInfoUiHandler extends UiHandler {
);
this.runContainer.add(abilityButtonContainer);
}
const headerText = addTextObject(0, 0, i18next.t("runHistory:runInfo"), TextStyle.SETTINGS_LABEL);
const headerText = addTextObject(0, 0, i18next.t("runHistory:runInfo"), TextStyle.HEADER_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
this.runContainer.add(headerText);
@ -603,7 +603,7 @@ export default class RunInfoUiHandler extends UiHandler {
// Duration + Money
const runInfoTextContainer = globalScene.add.container(0, 0);
// Japanese is set to a greater line spacing of 35px in addBBCodeTextObject() if lineSpacing < 12.
const lineSpacing = i18next.resolvedLanguage === "ja" ? 12 : 3;
const lineSpacing = i18next.resolvedLanguage === "ja" ? 3 : 3;
const runInfoText = addBBCodeTextObject(7, 0, "", TextStyle.WINDOW, {
fontSize: "50px",
lineSpacing: lineSpacing,
@ -768,7 +768,7 @@ export default class RunInfoUiHandler extends UiHandler {
const pPassiveInfo = pokemon.passive ? passiveLabel + ": " + pokemon.getPassiveAbility().name : "";
const pAbilityInfo = abilityLabel + ": " + pokemon.getAbility().name;
// Japanese is set to a greater line spacing of 35px in addBBCodeTextObject() if lineSpacing < 12.
const lineSpacing = i18next.resolvedLanguage === "ja" ? 12 : 3;
const lineSpacing = i18next.resolvedLanguage === "ja" ? 3 : 3;
const pokeInfoText = addBBCodeTextObject(0, 0, pName, TextStyle.SUMMARY, {
fontSize: textContainerFontSize,
lineSpacing: lineSpacing,
@ -866,7 +866,7 @@ export default class RunInfoUiHandler extends UiHandler {
moveContainer.setScale(0.5);
const moveBg = globalScene.add.nineslice(0, 0, "type_bgs", "unknown", 85, 15, 2, 2, 2, 2);
moveBg.setOrigin(1, 0);
const moveLabel = addTextObject(-moveBg.width / 2, 2, "-", TextStyle.PARTY);
const moveLabel = addTextObject(-moveBg.width / 2, 1, "-", TextStyle.MOVE_LABEL);
moveLabel.setOrigin(0.5, 0);
moveLabel.setName("text-move-label");
pokemonMoveBgs.push(moveBg);

View File

@ -144,7 +144,7 @@ export default class NavigationMenu extends Phaser.GameObjects.Container {
let relative: Phaser.GameObjects.Sprite | Phaser.GameObjects.Text = iconPreviousTab;
let relativeWidth: number = iconPreviousTab.width * 6;
for (const label of navigationManager.labels) {
const labelText = addTextObject(0, 0, label, TextStyle.SETTINGS_LABEL);
const labelText = addTextObject(0, 0, label, TextStyle.SETTINGS_LABEL_NAVBAR);
labelText.setOrigin(0, 0);
labelText.setPositionRelative(relative, 6 + relativeWidth / 6, 0);
this.add(labelText);

View File

@ -148,10 +148,10 @@ const languageSettings: { [key: string]: LanguageSetting } = {
starterInfoXPos: 30,
},
ja: {
starterInfoTextSize: "62px",
instructionTextSize: "38px",
starterInfoYOffset: 0.5,
starterInfoXPos: 33,
starterInfoTextSize: "48px",
instructionTextSize: "40px",
starterInfoYOffset: 1,
starterInfoXPos: 32,
},
ca: {
starterInfoTextSize: "48px",
@ -624,7 +624,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.starterSelectContainer.add(this.pokemonSprite);
this.pokemonNumberText = addTextObject(17, 1, "0000", TextStyle.SUMMARY);
this.pokemonNumberText = addTextObject(17, 1, "0000", TextStyle.SUMMARY_DEX_NUM);
this.pokemonNumberText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNumberText);
@ -643,7 +643,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonGrowthRateLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonGrowthRateLabelText);
this.pokemonGrowthRateText = addTextObject(34, 106, "", TextStyle.SUMMARY_PINK, { fontSize: "36px" });
this.pokemonGrowthRateText = addTextObject(34, 106, "", TextStyle.GROWTH_RATE_TYPE, { fontSize: "36px" });
this.pokemonGrowthRateText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonGrowthRateText);
@ -743,7 +743,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonEggMoveBgs = [];
this.pokemonEggMoveLabels = [];
this.valueLimitLabel = addTextObject(teamWindowX + 17, 150, "0/10", TextStyle.TOOLTIP_CONTENT);
this.valueLimitLabel = addTextObject(teamWindowX + 17, 150, "0/10", TextStyle.STARTER_VALUE_LIMIT);
this.valueLimitLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(this.valueLimitLabel);
@ -872,9 +872,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonLuckLabelText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonLuckLabelText);
this.pokemonLuckText = addTextObject(8 + this.pokemonLuckLabelText.displayWidth + 2, 89, "0", TextStyle.WINDOW, {
this.pokemonLuckText = addTextObject(
8 + this.pokemonLuckLabelText.displayWidth + 2,
89,
"0",
TextStyle.LUCK_VALUE,
{
fontSize: "56px",
});
},
);
this.pokemonLuckText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonLuckText);
@ -947,7 +953,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const moveBg = globalScene.add.nineslice(0, 0, "type_bgs", "unknown", 92, 14, 2, 2, 2, 2);
moveBg.setOrigin(1, 0);
const moveLabel = addTextObject(-moveBg.width / 2, 0, "-", TextStyle.PARTY);
const moveLabel = addTextObject(-moveBg.width / 2, 0, "-", TextStyle.MOVE_LABEL);
moveLabel.setOrigin(0.5, 0);
this.pokemonMoveBgs.push(moveBg);
@ -964,7 +970,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
-this.pokemonMoveBgs[0].width / 2,
56,
"(+0)",
TextStyle.PARTY,
TextStyle.MOVE_LABEL,
);
this.pokemonAdditionalMoveCountLabel.setOrigin(0.5, 0);
@ -986,7 +992,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const eggMoveBg = globalScene.add.nineslice(0, 0, "type_bgs", "unknown", 92, 14, 2, 2, 2, 2);
eggMoveBg.setOrigin(1, 0);
const eggMoveLabel = addTextObject(-eggMoveBg.width / 2, 0, "???", TextStyle.PARTY);
const eggMoveLabel = addTextObject(-eggMoveBg.width / 2, 0, "???", TextStyle.MOVE_LABEL);
eggMoveLabel.setOrigin(0.5, 0);
this.pokemonEggMoveBgs.push(eggMoveBg);
@ -1030,7 +1036,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleShiny"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.shinyLabel.setName("text-shiny-label");
@ -1049,7 +1055,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleForm"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.formLabel.setName("text-form-label");
@ -1068,7 +1074,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleGender"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.genderLabel.setName("text-gender-label");
@ -1087,7 +1093,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleAbility"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.abilityLabel.setName("text-ability-label");
@ -1106,7 +1112,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleNature"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.natureLabel.setName("text-nature-label");
@ -1125,7 +1131,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.instructionRowX + this.instructionRowTextOffset,
this.instructionRowY,
i18next.t("starterSelectUiHandler:cycleTera"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.teraLabel.setName("text-tera-label");
@ -1144,7 +1150,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.filterInstructionRowX + this.instructionRowTextOffset,
this.filterInstructionRowY,
i18next.t("starterSelectUiHandler:goFilter"),
TextStyle.PARTY,
TextStyle.INSTRUCTIONS_TEXT,
{ fontSize: instructionTextSize },
);
this.goFilterLabel.setName("text-goFilter-label");
@ -2205,14 +2211,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (!(passiveAttr & PassiveAttr.UNLOCKED)) {
const passiveCost = getPassiveCandyCount(speciesStarterCosts[this.lastSpecies.speciesId]);
options.push({
label: `x${passiveCost} ${i18next.t("starterSelectUiHandler:unlockPassive")}`,
label: `×${passiveCost} ${i18next.t("starterSelectUiHandler:unlockPassive")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= passiveCost) {
starterData.passiveAttr |= PassiveAttr.UNLOCKED | PassiveAttr.ENABLED;
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= passiveCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
globalScene.gameData.saveSystem().then(success => {
if (!success) {
return globalScene.reset(true);
@ -2245,14 +2251,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
valueReduction
];
options.push({
label: `x${reductionCost} ${i18next.t("starterSelectUiHandler:reduceCost")}`,
label: `×${reductionCost} ${i18next.t("starterSelectUiHandler:reduceCost")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= reductionCost) {
starterData.valueReduction++;
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= reductionCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
globalScene.gameData.saveSystem().then(success => {
if (!success) {
return globalScene.reset(true);
@ -2279,7 +2285,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
// Same species egg menu option.
const sameSpeciesEggCost = getSameSpeciesEggCandyCounts(speciesStarterCosts[this.lastSpecies.speciesId]);
options.push({
label: `x${sameSpeciesEggCost} ${i18next.t("starterSelectUiHandler:sameSpeciesEgg")}`,
label: `×${sameSpeciesEggCost} ${i18next.t("starterSelectUiHandler:sameSpeciesEgg")}`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= sameSpeciesEggCost) {
if (globalScene.gameData.eggs.length >= 99 && !Overrides.UNLIMITED_EGG_COUNT_OVERRIDE) {
@ -2298,7 +2304,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (!Overrides.FREE_CANDY_UPGRADE_OVERRIDE) {
starterData.candyCount -= sameSpeciesEggCost;
}
this.pokemonCandyCountText.setText(`x${starterData.candyCount}`);
this.pokemonCandyCountText.setText(`×${starterData.candyCount}`);
const egg = new Egg({
species: this.lastSpecies.speciesId,
@ -3567,7 +3573,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonShinyIcon.setY(117);
this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0])));
this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1])));
this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[species.speciesId].candyCount}`);
this.pokemonCandyCountText.setText(`×${globalScene.gameData.starterData[species.speciesId].candyCount}`);
this.pokemonCandyContainer.setVisible(true);
this.pokemonFormText.setY(42);
this.pokemonHatchedIcon.setVisible(true);
@ -3821,9 +3827,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default?
this.pokemonNumberText.setColor(this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, false));
this.pokemonNumberText.setColor(
this.getTextColor(shiny ? TextStyle.SUMMARY_DEX_NUM_GOLD : TextStyle.SUMMARY_DEX_NUM, false),
);
this.pokemonNumberText.setShadowColor(
this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, true),
this.getTextColor(shiny ? TextStyle.SUMMARY_DEX_NUM_GOLD : TextStyle.SUMMARY_DEX_NUM, true),
);
if (forSeen ? this.speciesStarterDexEntry?.seenAttr : this.speciesStarterDexEntry?.caughtAttr) {

View File

@ -86,7 +86,7 @@ export class StatsContainer extends Phaser.GameObjects.Container {
4 +
(this.showDiff ? 0 : ivChartLabelyOffset[s]),
i18next.t(getStatKey(s)),
TextStyle.TOOLTIP_CONTENT,
TextStyle.STATS_HEXAGON,
);
statLabel.setOrigin(0.5);
@ -94,7 +94,7 @@ export class StatsContainer extends Phaser.GameObjects.Container {
statLabel.x - (this.showDiff ? 0 : ivLabelOffset[s]),
statLabel.y + 8,
"0",
TextStyle.TOOLTIP_CONTENT,
TextStyle.STATS_HEXAGON,
);
this.ivStatValueTexts[s].setOrigin(0.5);

View File

@ -148,7 +148,7 @@ export default class SummaryUiHandler extends UiHandler {
this.tabSprite.setOrigin(1, 1);
this.summaryContainer.add(this.tabSprite);
const summaryLabel = addTextObject(4, -165, i18next.t("pokemonSummary:pokemonInfo"), TextStyle.SUMMARY);
const summaryLabel = addTextObject(4, -165, i18next.t("pokemonSummary:pokemonInfo"), TextStyle.SUMMARY_HEADER);
summaryLabel.setOrigin(0, 1);
this.summaryContainer.add(summaryLabel);
@ -418,7 +418,7 @@ export default class SummaryUiHandler extends UiHandler {
}
this.candyCountText.setText(
`x${globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].candyCount}`,
`×${globalScene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].candyCount}`,
);
this.candyShadow.setCrop(0, 0, 16, candyCropY);
@ -430,7 +430,7 @@ export default class SummaryUiHandler extends UiHandler {
this.friendshipShadow.on("pointerout", () => globalScene.ui.hideTooltip());
}
this.friendshipText.setText(`${this.pokemon?.friendship || "0"} / 255`);
this.friendshipText.setText(` ${this.pokemon?.friendship || "0"}/255`);
this.friendshipShadow.setCrop(0, 0, 16, 16 - 16 * ((this.pokemon?.friendship || 0) / 255));
@ -864,7 +864,7 @@ export default class SummaryUiHandler extends UiHandler {
141 + luckLabelText.displayWidth + 2,
28,
this.pokemon.getLuck().toString(),
TextStyle.SUMMARY,
TextStyle.LUCK_VALUE,
);
luckText.setOrigin(0, 0);
luckText.setTint(getVariantTint(Math.min(this.pokemon.getLuck() - 1, 2) as Variant));
@ -917,11 +917,11 @@ export default class SummaryUiHandler extends UiHandler {
abilityInfo.labelImage.setOrigin(0, 0);
profileContainer.add(abilityInfo.labelImage);
abilityInfo.nameText = addTextObject(7, 66, abilityInfo.ability?.name!, TextStyle.SUMMARY_ALT); // TODO: is this bang correct?
abilityInfo.nameText = addTextObject(7, 68, abilityInfo.ability?.name!, TextStyle.SUMMARY_ALT); // TODO: is this bang correct?
abilityInfo.nameText.setOrigin(0, 1);
profileContainer.add(abilityInfo.nameText);
abilityInfo.descriptionText = addTextObject(7, 69, abilityInfo.ability?.description!, TextStyle.WINDOW_ALT, {
abilityInfo.descriptionText = addTextObject(7, 71, abilityInfo.ability?.description!, TextStyle.WINDOW_ALT, {
wordWrap: { width: 1224 },
}); // TODO: is this bang correct?
abilityInfo.descriptionText.setOrigin(0, 0);
@ -1000,16 +1000,16 @@ export default class SummaryUiHandler extends UiHandler {
16 * rowIndex,
statName,
natureStatMultiplier === 1
? TextStyle.SUMMARY
? TextStyle.SUMMARY_STATS
: natureStatMultiplier > 1
? TextStyle.SUMMARY_PINK
: TextStyle.SUMMARY_BLUE,
? TextStyle.SUMMARY_STATS_PINK
: TextStyle.SUMMARY_STATS_BLUE,
);
const ivLabel = addTextObject(
115 * colIndex + (colIndex === 1 ? 5 : 0),
16 * rowIndex,
statName,
this.pokemon?.ivs[stat] === 31 ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY,
this.pokemon?.ivs[stat] === 31 ? TextStyle.SUMMARY_STATS_GOLD : TextStyle.SUMMARY_STATS,
);
statLabel.setOrigin(0.5, 0);

View File

@ -11,27 +11,48 @@ export enum TextStyle {
MESSAGE,
WINDOW,
WINDOW_ALT,
WINDOW_BATTLE_COMMAND,
BATTLE_INFO,
PARTY,
PARTY_RED,
PARTY_CANCEL_BUTTON,
INSTRUCTIONS_TEXT,
MOVE_LABEL,
SUMMARY,
SUMMARY_DEX_NUM,
SUMMARY_DEX_NUM_GOLD,
SUMMARY_ALT,
SUMMARY_HEADER,
SUMMARY_RED,
SUMMARY_BLUE,
SUMMARY_PINK,
SUMMARY_GOLD,
SUMMARY_GRAY,
SUMMARY_GREEN,
SUMMARY_STATS,
SUMMARY_STATS_BLUE,
SUMMARY_STATS_PINK,
SUMMARY_STATS_GOLD,
LUCK_VALUE,
STATS_HEXAGON,
GROWTH_RATE_TYPE,
MONEY, // Money default styling (pale yellow)
MONEY_WINDOW, // Money displayed in Windows (needs different colors based on theme)
HEADER_LABEL,
STATS_LABEL,
STATS_VALUE,
SETTINGS_VALUE,
SETTINGS_LABEL,
SETTINGS_LABEL_NAVBAR,
SETTINGS_SELECTED,
SETTINGS_LOCKED,
EGG_LIST,
EGG_SUMMARY_NAME,
EGG_SUMMARY_DEX,
STARTER_VALUE_LIMIT,
TOOLTIP_TITLE,
TOOLTIP_CONTENT,
FILTER_BAR_MAIN,
MOVE_INFO_CONTENT,
MOVE_PP_FULL,
MOVE_PP_HALF_FULL,
@ -73,10 +94,6 @@ export function addTextObject(
ret.setLineSpacing(scale * 30);
}
if (ret.lineSpacing < 12 && i18next.resolvedLanguage === "ja") {
ret.setLineSpacing(ret.lineSpacing + 35);
}
return ret;
}
@ -122,10 +139,6 @@ export function addBBCodeTextObject(
ret.setLineSpacing(scale * 60);
}
if (ret.lineSpacing < 12 && i18next.resolvedLanguage === "ja") {
ret.setLineSpacing(ret.lineSpacing + 35);
}
return ret;
}
@ -154,7 +167,7 @@ export function getTextStyleOptions(
const lang = i18next.resolvedLanguage;
let shadowXpos = 4;
let shadowYpos = 5;
let scale = 0.1666666667;
const scale = 0.1666666667;
const defaultFontSize = 96;
let styleOptions: Phaser.Types.GameObjects.Text.TextStyle = {
@ -166,13 +179,58 @@ export function getTextStyleOptions(
},
};
if (i18next.resolvedLanguage === "ja") {
scale = 0.1388888889;
styleOptions.padding = { top: 2, bottom: 4 };
}
switch (style) {
case TextStyle.SUMMARY:
case TextStyle.SUMMARY: {
const fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { top: 6, bottom: 4 };
break;
}
styleOptions.fontSize = fontSizeLabel;
break;
}
// shadowXpos = 5;
// shadowYpos = 5;
// break;
case TextStyle.SUMMARY_HEADER: {
let fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { bottom: 7 };
fontSizeLabel = "80px";
break;
}
styleOptions.fontSize = fontSizeLabel;
break;
}
// shadowXpos = 5;
// shadowYpos = 5;
// break;
case TextStyle.SUMMARY_DEX_NUM: {
const fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { top: 2, bottom: 10 };
break;
}
styleOptions.fontSize = fontSizeLabel;
shadowXpos = 5;
shadowYpos = 5;
break;
}
case TextStyle.SUMMARY_DEX_NUM_GOLD: {
const fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { top: 2, bottom: 10 };
break;
}
styleOptions.fontSize = fontSizeLabel;
shadowXpos = 5;
shadowYpos = 5;
break;
}
case TextStyle.SUMMARY_ALT:
case TextStyle.SUMMARY_BLUE:
case TextStyle.SUMMARY_RED:
@ -180,6 +238,10 @@ export function getTextStyleOptions(
case TextStyle.SUMMARY_GOLD:
case TextStyle.SUMMARY_GRAY:
case TextStyle.SUMMARY_GREEN:
case TextStyle.SUMMARY_STATS:
case TextStyle.SUMMARY_STATS_BLUE:
case TextStyle.SUMMARY_STATS_PINK:
case TextStyle.SUMMARY_STATS_GOLD:
case TextStyle.WINDOW:
case TextStyle.WINDOW_ALT:
case TextStyle.ME_OPTION_DEFAULT:
@ -187,6 +249,43 @@ export function getTextStyleOptions(
shadowXpos = 3;
shadowYpos = 3;
break;
case TextStyle.LUCK_VALUE: {
const fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { top: -6, bottom: 2 };
break;
}
styleOptions.fontSize = fontSizeLabel;
shadowXpos = 3;
shadowYpos = 4;
break;
}
case TextStyle.GROWTH_RATE_TYPE: {
switch (lang) {
case "ja":
styleOptions.padding = { left: 24 };
break;
}
styleOptions.fontSize = defaultFontSize - 30;
shadowXpos = 3;
shadowYpos = 3;
break;
}
case TextStyle.WINDOW_BATTLE_COMMAND: {
let fontSizeLabel = "96px";
switch (lang) {
case "ja":
styleOptions.padding = { top: 2 };
fontSizeLabel = "92px";
break;
}
styleOptions.fontSize = fontSizeLabel;
break;
}
// shadowXpos = 5;
// shadowYpos = 5;
// break;
case TextStyle.STATS_LABEL: {
let fontSizeLabel = "96px";
switch (lang) {
@ -218,10 +317,76 @@ export function getTextStyleOptions(
break;
}
case TextStyle.MESSAGE:
case TextStyle.SETTINGS_LABEL:
case TextStyle.SETTINGS_LOCKED:
case TextStyle.SETTINGS_SELECTED:
styleOptions.fontSize = defaultFontSize;
break;
case TextStyle.HEADER_LABEL:
styleOptions.fontSize = defaultFontSize;
styleOptions.padding = { top: 6 };
break;
case TextStyle.SETTINGS_VALUE:
case TextStyle.SETTINGS_LABEL: {
shadowXpos = 3;
shadowYpos = 3;
let fontSizeValue = "96px";
switch (lang) {
case "ja":
fontSizeValue = "80px";
styleOptions.padding = { top: 10 };
break;
default:
fontSizeValue = "96px";
break;
}
styleOptions.fontSize = fontSizeValue;
break;
}
case TextStyle.SETTINGS_LABEL_NAVBAR: {
shadowXpos = 3;
shadowYpos = 3;
let fontSizeValue = "96px";
switch (lang) {
case "ja":
fontSizeValue = "92px";
break;
default:
fontSizeValue = "96px";
break;
}
styleOptions.fontSize = fontSizeValue;
break;
}
case TextStyle.SETTINGS_LOCKED: {
shadowXpos = 3;
shadowYpos = 3;
let fontSizeValue = "96px";
switch (lang) {
case "ja":
fontSizeValue = "80px";
styleOptions.padding = { top: 10 };
break;
default:
fontSizeValue = "96px";
break;
}
styleOptions.fontSize = fontSizeValue;
break;
}
case TextStyle.SETTINGS_SELECTED: {
shadowXpos = 3;
shadowYpos = 3;
let fontSizeValue = "96px";
switch (lang) {
case "ja":
fontSizeValue = "80px";
styleOptions.padding = { top: 10 };
break;
default:
fontSizeValue = "96px";
break;
}
styleOptions.fontSize = fontSizeValue;
break;
}
case TextStyle.BATTLE_INFO:
case TextStyle.MONEY:
case TextStyle.MONEY_WINDOW:
@ -231,11 +396,108 @@ export function getTextStyleOptions(
shadowYpos = 3.5;
break;
case TextStyle.PARTY:
case TextStyle.PARTY_RED:
case TextStyle.PARTY_RED: {
switch (lang) {
case "ja":
styleOptions.padding = { top: -12, bottom: 4 };
break;
}
styleOptions.fontSize = defaultFontSize - 30;
styleOptions.fontFamily = "pkmnems";
break;
case TextStyle.TOOLTIP_CONTENT:
}
case TextStyle.PARTY_CANCEL_BUTTON: {
switch (lang) {
case "ja":
styleOptions.fontSize = defaultFontSize - 42;
styleOptions.padding = { top: 4 };
break;
default:
styleOptions.fontSize = defaultFontSize - 30;
styleOptions.padding = { left: 12 };
break;
}
styleOptions.fontFamily = "pkmnems";
break;
}
case TextStyle.INSTRUCTIONS_TEXT: {
switch (lang) {
case "ja":
styleOptions.padding = { top: -3, bottom: 4 };
break;
}
styleOptions.fontSize = defaultFontSize - 30;
styleOptions.fontFamily = "pkmnems";
shadowXpos = 3;
shadowYpos = 3;
break;
}
case TextStyle.MOVE_LABEL: {
switch (lang) {
case "ja":
styleOptions.fontSize = defaultFontSize - 16;
styleOptions.padding = { top: -14, bottom: 8 };
break;
default:
styleOptions.fontSize = defaultFontSize - 30;
break;
}
styleOptions.fontFamily = "pkmnems";
break;
}
case TextStyle.EGG_LIST:
styleOptions.fontSize = defaultFontSize - 34;
break;
case TextStyle.EGG_SUMMARY_NAME: {
switch (lang) {
case "ja":
styleOptions.padding = { top: -1 };
break;
}
break;
}
case TextStyle.EGG_SUMMARY_DEX: {
switch (lang) {
case "ja":
styleOptions.padding = { top: 2 };
break;
}
break;
}
case TextStyle.STARTER_VALUE_LIMIT:
styleOptions.fontSize = defaultFontSize - 36;
shadowXpos = 3;
shadowYpos = 3;
break;
case TextStyle.TOOLTIP_CONTENT: {
switch (lang) {
case "ja":
styleOptions.fontSize = defaultFontSize - 44;
styleOptions.padding = { top: 10, right: 10 };
break;
default:
styleOptions.fontSize = defaultFontSize - 32;
break;
}
shadowXpos = 3;
shadowYpos = 3;
break;
}
case TextStyle.FILTER_BAR_MAIN: {
switch (lang) {
case "ja":
styleOptions.fontSize = defaultFontSize - 48;
styleOptions.padding = { top: 10, right: 10 };
break;
default:
styleOptions.fontSize = defaultFontSize - 32;
break;
}
shadowXpos = 3;
shadowYpos = 3;
break;
}
case TextStyle.STATS_HEXAGON:
styleOptions.fontSize = defaultFontSize - 32;
shadowXpos = 3;
shadowYpos = 3;
@ -330,9 +592,14 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.MESSAGE:
return !shadow ? "#f8f8f8" : "#6b5a73";
case TextStyle.WINDOW:
case TextStyle.WINDOW_BATTLE_COMMAND:
case TextStyle.MOVE_INFO_CONTENT:
case TextStyle.STATS_HEXAGON:
case TextStyle.MOVE_PP_FULL:
case TextStyle.EGG_LIST:
case TextStyle.TOOLTIP_CONTENT:
case TextStyle.FILTER_BAR_MAIN:
case TextStyle.STARTER_VALUE_LIMIT:
case TextStyle.SETTINGS_VALUE:
if (isLegacyTheme) {
return !shadow ? "#484848" : "#d0d0c8";
@ -361,12 +628,22 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
}
return !shadow ? "#f8f8f8" : "#6b5a73";
case TextStyle.PARTY:
case TextStyle.PARTY_CANCEL_BUTTON:
case TextStyle.INSTRUCTIONS_TEXT:
case TextStyle.MOVE_LABEL:
return !shadow ? "#f8f8f8" : "#707070";
case TextStyle.PARTY_RED:
return !shadow ? "#f89890" : "#984038";
case TextStyle.SUMMARY:
case TextStyle.SUMMARY_DEX_NUM:
case TextStyle.SUMMARY_HEADER:
case TextStyle.SUMMARY_STATS:
case TextStyle.EGG_SUMMARY_NAME:
case TextStyle.EGG_SUMMARY_DEX:
case TextStyle.LUCK_VALUE:
return !shadow ? "#f8f8f8" : "#636363";
case TextStyle.SUMMARY_ALT:
case TextStyle.GROWTH_RATE_TYPE:
if (isLegacyTheme) {
return !shadow ? "#f8f8f8" : "#636363";
}
@ -375,10 +652,14 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.TOOLTIP_TITLE:
return !shadow ? "#e70808" : "#ffbd73";
case TextStyle.SUMMARY_BLUE:
case TextStyle.SUMMARY_STATS_BLUE:
return !shadow ? "#40c8f8" : "#006090";
case TextStyle.SUMMARY_PINK:
case TextStyle.SUMMARY_STATS_PINK:
return !shadow ? "#f89890" : "#984038";
case TextStyle.SUMMARY_GOLD:
case TextStyle.SUMMARY_DEX_NUM_GOLD:
case TextStyle.SUMMARY_STATS_GOLD:
case TextStyle.MONEY:
return !shadow ? "#e8e8a8" : "#a0a060"; // Pale Yellow/Gold
case TextStyle.MONEY_WINDOW:
@ -399,6 +680,8 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.SUMMARY_GREEN:
return !shadow ? "#78c850" : "#306850";
case TextStyle.SETTINGS_LABEL:
case TextStyle.SETTINGS_LABEL_NAVBAR:
case TextStyle.HEADER_LABEL:
case TextStyle.PERFECT_IV:
return !shadow ? "#f8b050" : "#c07800";
case TextStyle.SETTINGS_SELECTED:

View File

@ -341,6 +341,10 @@ export class NumberHolder {
constructor(value: number) {
this.value = value;
}
valueOf(): number {
return this.value;
}
}
export class FixedInt {
@ -349,6 +353,10 @@ export class FixedInt {
constructor(value: number) {
this.value = value;
}
[Symbol.toPrimitive](_hint: string): number {
return this.value;
}
}
export function fixedInt(value: number): number {

View File

@ -193,6 +193,7 @@ describe("Abilities - Parental Bond", () => {
expect(leadPokemon.turnData.hitCount).toBe(2);
});
// TODO: consolidate all these tests into 1 block
it("should only trigger post-target move effects once", async () => {
game.override.moveset([MoveId.MIND_BLOWN]);
@ -233,42 +234,6 @@ describe("Abilities - Parental Bond", () => {
expect(leadPokemon.isOfType(PokemonType.FIRE)).toBe(false);
});
it("Moves boosted by this ability and Multi-Lens should strike 3 times", async () => {
game.override.moveset([MoveId.TACKLE]).startingHeldItems([{ name: "MULTI_LENS", count: 1 }]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(MoveId.TACKLE);
await game.phaseInterceptor.to("DamageAnimPhase");
expect(leadPokemon.turnData.hitCount).toBe(3);
});
it("Seismic Toss boosted by this ability and Multi-Lens should strike 3 times", async () => {
game.override.moveset([MoveId.SEISMIC_TOSS]).startingHeldItems([{ name: "MULTI_LENS", count: 1 }]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!;
const enemyPokemon = game.scene.getEnemyPokemon()!;
const enemyStartingHp = enemyPokemon.hp;
game.move.select(MoveId.SEISMIC_TOSS);
await game.move.forceHit();
await game.phaseInterceptor.to("DamageAnimPhase");
expect(leadPokemon.turnData.hitCount).toBe(3);
await game.phaseInterceptor.to("MoveEndPhase", false);
expect(enemyPokemon.hp).toBe(enemyStartingHp - 200);
});
it("Hyper Beam boosted by this ability should strike twice, then recharge", async () => {
game.override.moveset([MoveId.HYPER_BEAM]);

View File

@ -211,21 +211,4 @@ describe("Items - Multi Lens", () => {
// TODO: Update hit count to 1 once Future Sight is fixed to not activate held items if user is off the field
expect(enemyPokemon.damageAndUpdate).toHaveBeenCalledTimes(2);
});
it("should not allow Pollen Puff to heal ally more than once", async () => {
game.override.battleStyle("double").moveset([MoveId.POLLEN_PUFF, MoveId.ENDURE]);
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.OMANYTE]);
const [, rightPokemon] = game.scene.getPlayerField();
rightPokemon.damageAndUpdate(rightPokemon.hp - 1);
game.move.select(MoveId.POLLEN_PUFF, 0, BattlerIndex.PLAYER_2);
game.move.select(MoveId.ENDURE, 1);
await game.toNextTurn();
// Pollen Puff heals with a ratio of 0.5, as long as Pollen Puff triggers only once the pokemon will always be <= (0.5 * Max HP) + 1
expect(rightPokemon.hp).toBeLessThanOrEqual(0.5 * rightPokemon.getMaxHp() + 1);
});
});