From 82bccd4a2def67cf616a9b760ad7dd2c5b0a2320 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Mon, 6 Jan 2025 02:21:48 +0100 Subject: [PATCH] Displaying base stats as bars in an overlay --- src/ui/base-stats-overlay.ts | 125 ++++++++++++++++++++++++++++++ src/ui/pokedex-page-ui-handler.ts | 70 +++++++---------- 2 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 src/ui/base-stats-overlay.ts diff --git a/src/ui/base-stats-overlay.ts b/src/ui/base-stats-overlay.ts new file mode 100644 index 00000000000..8f5e3722a5b --- /dev/null +++ b/src/ui/base-stats-overlay.ts @@ -0,0 +1,125 @@ +import BattleScene, { InfoToggle } from "../battle-scene"; +import { TextStyle, addTextObject } from "./text"; +import { addWindow } from "./ui-theme"; +import * as Utils from "../utils"; +import i18next from "i18next"; + +export interface BaseStatsOverlaySettings { + scale?:number; // scale the box? A scale of 0.5 is recommended + x?: number; + y?: number; + /** Default is always half the screen, regardless of scale */ + width?: number; +} + +const HEIGHT = 120; +const BORDER = 8; +const GLOBAL_SCALE = 6; +const shortStats = [ "HP", "ATK", "DEF", "SPATK", "SPDEF", "SPD" ]; + +export default class BaseStatsOverlay extends Phaser.GameObjects.Container implements InfoToggle { + + public active: boolean = false; + + private statsLabels: Phaser.GameObjects.Text[] = []; + private statsRectangles: Phaser.GameObjects.Rectangle[] = []; + private statsShadows: Phaser.GameObjects.Rectangle[] = []; + private statsTotalLabel: Phaser.GameObjects.Text; + + private statsBg: Phaser.GameObjects.NineSlice; + + private options: BaseStatsOverlaySettings; + + public scale: number; + public width: number; + + constructor(scene: BattleScene, options?: BaseStatsOverlaySettings) { + super(scene, options?.x, options?.y); + this.scale = options?.scale || 1; // set up the scale + this.setScale(this.scale); + this.options = options || {}; + + // prepare the description box + this.width = (options?.width || BaseStatsOverlay.getWidth(this.scale, scene)) / this.scale; // divide by scale as we always want this to be half a window wide + this.statsBg = addWindow(scene, 0, 0, this.width, HEIGHT); + this.statsBg.setOrigin(0, 0); + this.add(this.statsBg); + + for (let i = 0; i < 6; i++) { + const shadow = this.scene.add.rectangle(0, BORDER + 3 + i * 15, 100, 5, 0x006860); + shadow.setOrigin(1, 0); + shadow.setX(this.width - BORDER + 1); + this.statsShadows.push(shadow); + this.add(shadow); + + const rectangle = this.scene.add.rectangle(0, BORDER + 2 + i * 15, 100, 5, 0x66aa99); + rectangle.setOrigin(1, 0); + rectangle.setX(this.width - BORDER); + this.statsRectangles.push(rectangle); + this.add(rectangle); + + const label = addTextObject(scene, BORDER, BORDER - 2 + i * 15, "A", TextStyle.BATTLE_INFO); + this.statsLabels.push(label); + this.add(label); + } + + this.statsTotalLabel = addTextObject(scene, BORDER, BORDER + 6 * 15, "A", TextStyle.BATTLE_INFO, { color: "#ccbe00" }); + this.add(this.statsTotalLabel); + + // hide this component for now + this.setVisible(false); + } + + // show this component with infos for the specific move + show(values: number[], total: number):boolean { + + for (let i = 0; i < 6; i++) { + this.statsLabels[i].setText(i18next.t(`pokemonInfo:Stat.${shortStats[i]}shortened`) + ": " + `${values[i]}`); + // This accounts for base stats up to 200, might not be enough. + // TODO: change color based on value. + this.statsShadows[i].setSize(values[i] / 2, 5); + this.statsRectangles[i].setSize(values[i] / 2, 5); + } + + this.statsTotalLabel.setText(i18next.t("pokedexUiHandler:baseTotal") + ": " + `${total}`); + + + this.setVisible(true); + this.active = true; + return true; + } + + clear() { + this.setVisible(false); + this.active = false; + } + + toggleInfo(visible: boolean): void { + if (visible) { + this.setVisible(true); + } + this.scene.tweens.add({ + targets: this.statsLabels, + duration: Utils.fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible ? 1 : 0 + }); + if (!visible) { + this.setVisible(false); + } + } + + isActive(): boolean { + return this.active; + } + + // width of this element + static getWidth(scale:number, scene: BattleScene):number { + return scene.game.canvas.width / GLOBAL_SCALE / 2; + } + + // height of this element + static getHeight(scale:number, onSide?: boolean):number { + return HEIGHT * scale; + } +} diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 68800b291f5..434ac12e987 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -49,6 +49,7 @@ import { Biome } from "#app/enums/biome"; import { TimeOfDay } from "#app/enums/time-of-day"; import { SpeciesFormKey } from "#app/enums/species-form-key"; import { Abilities } from "#app/enums/abilities"; +import BaseStatsOverlay from "./base-stats-overlay"; interface LanguageSetting { @@ -182,8 +183,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private starterSelectMessageBox: Phaser.GameObjects.NineSlice; private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; private statsContainer: StatsContainer; - private moveInfoOverlay : MoveInfoOverlay; - private infoOverlay : PokedexInfoOverlay; + private moveInfoOverlay: MoveInfoOverlay; + private infoOverlay: PokedexInfoOverlay; + private baseStatsOverlay: BaseStatsOverlay; private statsMode: boolean; @@ -230,6 +232,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private starterAttributes: StarterAttributes; protected blockInput: boolean = false; + protected blockInputOverlay: boolean = false; // Menu private menuContainer: Phaser.GameObjects.Container; @@ -239,7 +242,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private menuOptions: MenuOptions[]; protected scale: number = 0.1666666667; - constructor(scene: BattleScene) { super(scene, Mode.POKEDEX_PAGE); } @@ -477,14 +479,10 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.bgmBar = new BgmBar(this.scene); this.bgmBar.setup(); - ui.bgmBar = this.bgmBar; - this.menuContainer.add(this.bgmBar); - this.menuContainer.setVisible(false); - this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => parseInt(MenuOptions[m]) as MenuOptions); this.optionSelectText = addTextObject(this.scene, 0, 0, this.menuOptions.map(o => `${i18next.t(`pokedexUiHandler:${MenuOptions[o]}`)}`).join("\n"), TextStyle.WINDOW, { maxLines: this.menuOptions.length }); @@ -510,6 +508,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.starterSelectContainer.add(this.menuContainer); + // adding base stats + this.baseStatsOverlay = new BaseStatsOverlay(this.scene, { x: 317, y: 0, width:133 }); + this.menuContainer.add(this.baseStatsOverlay); + this.menuContainer.bringToTop(this.baseStatsOverlay); + // add the info overlay last to be the top most ui element and prevent the IVs from overlaying this const overlayScale = 1; this.moveInfoOverlay = new MoveInfoOverlay(this.scene, { @@ -929,6 +932,21 @@ export default class PokedexPageUiHandler extends MessageUiHandler { let success = false; let error = false; + if (this.blockInputOverlay) { + if (button === Button.CANCEL || button === Button.ACTION) { + this.blockInputOverlay = false; + this.baseStatsOverlay.clear(); + ui.showText(""); + return true; + } else if (button === Button.UP || button === Button.DOWN) { + this.blockInputOverlay = false; + this.baseStatsOverlay.clear(); + ui.showText(""); + } else { + return false; + } + } + if (button === Button.SUBMIT) { success = true; } else if (button === Button.CANCEL) { @@ -956,43 +974,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler { ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:baseStats"), null, () => { - const options: any[] = []; - const shortStats = [ "HP", "ATK", "DEF", "SPATK", "SPDEF", "SPD" ]; - this.baseStats.map((bst, index) => { - options.push({ - label: i18next.t(`pokemonInfo:Stat.${shortStats[index]}shortened`).padEnd(5, " ") + ": " + `${bst}`, - handler: () => { - return false; - } - }); - }); - options.push({ - label: i18next.t("pokedexUiHandler:baseTotal") + ": " + `${this.baseTotal}`, - color: "#ccbe00", - handler: () => { - return false; - } - }); - options.push({ - label: i18next.t("menu:cancel"), - handler: () => { - this.moveInfoOverlay.clear(); - this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); - return true; - }, - onHover: () => this.moveInfoOverlay.clear() - }); - - ui.setModeWithoutClear(Mode.OPTION_SELECT, { - options: options, - supportHover: true, - maxOptions: 8, - yOffset: 19 - }); + this.baseStatsOverlay.show(this.baseStats, this.baseTotal); this.blockInput = false; + this.blockInputOverlay = true; + + return true; }); }); break;