Displaying base stats as bars in an overlay

This commit is contained in:
Wlowscha 2025-01-06 02:21:48 +01:00
parent 717a2c38f7
commit 82bccd4a2d
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
2 changed files with 154 additions and 41 deletions

View File

@ -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;
}
}

View File

@ -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;