mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-03-10 03:48:27 +00:00
* resize achv box default width * add language font size option. DE font size 80px * resize challenge desc window width. fix cursor width. shrink font size of desc. set middle align start label
431 lines
15 KiB
TypeScript
431 lines
15 KiB
TypeScript
import BattleScene from "../battle-scene";
|
|
import { Button } from "#enums/buttons";
|
|
import i18next from "i18next";
|
|
import { Achv, achvs, getAchievementDescription } from "../system/achv";
|
|
import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher";
|
|
import MessageUiHandler from "./message-ui-handler";
|
|
import { addTextObject, TextStyle } from "./text";
|
|
import { Mode } from "./ui";
|
|
import { addWindow } from "./ui-theme";
|
|
import { ParseKeys } from "i18next";
|
|
import { PlayerGender } from "#enums/player-gender";
|
|
|
|
enum Page {
|
|
ACHIEVEMENTS,
|
|
VOUCHERS
|
|
}
|
|
|
|
interface LanguageSetting {
|
|
TextSize: string,
|
|
}
|
|
|
|
const languageSettings: { [key: string]: LanguageSetting } = {
|
|
"de":{
|
|
TextSize: "80px"
|
|
}
|
|
};
|
|
|
|
export default class AchvsUiHandler extends MessageUiHandler {
|
|
private readonly ROWS = 4;
|
|
private readonly COLS = 17;
|
|
|
|
private mainContainer: Phaser.GameObjects.Container;
|
|
private iconsContainer: Phaser.GameObjects.Container;
|
|
|
|
private headerBg: Phaser.GameObjects.NineSlice;
|
|
private headerText: Phaser.GameObjects.Text;
|
|
private headerActionText: Phaser.GameObjects.Text;
|
|
private headerActionButton: Phaser.GameObjects.Sprite;
|
|
private headerBgX: number;
|
|
private iconsBg: Phaser.GameObjects.NineSlice;
|
|
private icons: Phaser.GameObjects.Sprite[];
|
|
|
|
private titleText: Phaser.GameObjects.Text;
|
|
private scoreText: Phaser.GameObjects.Text;
|
|
private unlockText: Phaser.GameObjects.Text;
|
|
|
|
private achvsName: string;
|
|
private achvsTotal: number;
|
|
private vouchersName: string;
|
|
private vouchersTotal: number;
|
|
private currentTotal: number;
|
|
|
|
private scrollCursor: number;
|
|
private cursorObj: Phaser.GameObjects.NineSlice | null;
|
|
private currentPage: Page;
|
|
|
|
constructor(scene: BattleScene, mode: Mode | null = null) {
|
|
super(scene, mode);
|
|
|
|
this.achvsTotal = Object.keys(achvs).length;
|
|
this.vouchersTotal = Object.keys(vouchers).length;
|
|
this.scrollCursor = 0;
|
|
}
|
|
|
|
setup() {
|
|
const ui = this.getUi();
|
|
|
|
this.mainContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
|
|
|
this.mainContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
|
|
|
this.headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
|
|
this.headerBg.setOrigin(0, 0);
|
|
|
|
this.headerText = addTextObject(this.scene, 0, 0, "", TextStyle.SETTINGS_LABEL);
|
|
this.headerText.setOrigin(0, 0);
|
|
this.headerText.setPositionRelative(this.headerBg, 8, 4);
|
|
this.headerActionButton = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "keyboard", "SPACE.png");
|
|
this.headerActionButton.setOrigin(0, 0);
|
|
this.headerActionButton.setPositionRelative(this.headerBg, 236, 6);
|
|
this.headerActionText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW, {fontSize:"60px"});
|
|
this.headerActionText.setOrigin(0, 0);
|
|
this.headerActionText.setPositionRelative(this.headerBg, 264, 8);
|
|
|
|
// We need to get the player gender from the game data to add the correct prefix to the achievement name
|
|
const playerGender = this.scene.gameData.gender;
|
|
let genderPrefix = "PGM";
|
|
if (playerGender === PlayerGender.FEMALE) {
|
|
genderPrefix = "PGF";
|
|
}
|
|
|
|
this.achvsName = i18next.t(`${genderPrefix}achv:Achievements.name` as ParseKeys);
|
|
this.vouchersName = i18next.t("voucher:vouchers");
|
|
|
|
this.iconsBg = addWindow(this.scene, 0, this.headerBg.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - this.headerBg.height - 68);
|
|
this.iconsBg.setOrigin(0, 0);
|
|
|
|
this.iconsContainer = this.scene.add.container(6, this.headerBg.height + 6);
|
|
|
|
this.icons = [];
|
|
|
|
for (let a = 0; a < this.ROWS * this.COLS; a++) {
|
|
const x = (a % this.COLS) * 18;
|
|
const y = Math.floor(a / this.COLS) * 18;
|
|
|
|
const icon = this.scene.add.sprite(x, y, "items", "unknown");
|
|
icon.setOrigin(0, 0);
|
|
icon.setScale(0.5);
|
|
|
|
this.icons.push(icon);
|
|
this.iconsContainer.add(icon);
|
|
}
|
|
|
|
const titleBg = addWindow(this.scene, 0, this.headerBg.height + this.iconsBg.height, 174, 24);
|
|
titleBg.setOrigin(0, 0);
|
|
|
|
this.titleText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
|
|
const textSize = languageSettings[i18next.language]?.TextSize ?? this.titleText.style.fontSize;
|
|
this.titleText.setFontSize(textSize);
|
|
this.titleText.setOrigin(0, 0);
|
|
const titleBgCenterX = titleBg.x + titleBg.width / 2;
|
|
const titleBgCenterY = titleBg.y + titleBg.height / 2;
|
|
this.titleText.setOrigin(0.5, 0.5);
|
|
this.titleText.setPosition(titleBgCenterX, titleBgCenterY);
|
|
|
|
const scoreBg = addWindow(this.scene, titleBg.x + titleBg.width, titleBg.y, 46, 24);
|
|
scoreBg.setOrigin(0, 0);
|
|
|
|
this.scoreText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
|
|
this.scoreText.setOrigin(0, 0);
|
|
this.scoreText.setPositionRelative(scoreBg, 8, 4);
|
|
|
|
const unlockBg = addWindow(this.scene, scoreBg.x + scoreBg.width, scoreBg.y, 98, 24);
|
|
unlockBg.setOrigin(0, 0);
|
|
|
|
this.unlockText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
|
|
this.unlockText.setOrigin(0, 0);
|
|
this.unlockText.setPositionRelative(unlockBg, 8, 4);
|
|
|
|
const descriptionBg = addWindow(this.scene, 0, titleBg.y + titleBg.height, (this.scene.game.canvas.width / 6) - 2, 42);
|
|
descriptionBg.setOrigin(0, 0);
|
|
|
|
const descriptionText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW, { maxLines: 2 });
|
|
descriptionText.setWordWrapWidth(1870);
|
|
descriptionText.setOrigin(0, 0);
|
|
descriptionText.setPositionRelative(descriptionBg, 8, 4);
|
|
|
|
this.message = descriptionText;
|
|
|
|
this.mainContainer.add(this.headerBg);
|
|
this.mainContainer.add(this.headerActionButton);
|
|
this.mainContainer.add(this.headerText);
|
|
this.mainContainer.add(this.headerActionText);
|
|
this.mainContainer.add(this.iconsBg);
|
|
this.mainContainer.add(this.iconsContainer);
|
|
this.mainContainer.add(titleBg);
|
|
this.mainContainer.add(this.titleText);
|
|
this.mainContainer.add(scoreBg);
|
|
this.mainContainer.add(this.scoreText);
|
|
this.mainContainer.add(unlockBg);
|
|
this.mainContainer.add(this.unlockText);
|
|
this.mainContainer.add(descriptionBg);
|
|
this.mainContainer.add(descriptionText);
|
|
|
|
ui.add(this.mainContainer);
|
|
|
|
this.currentPage = Page.ACHIEVEMENTS;
|
|
this.setCursor(0);
|
|
|
|
this.mainContainer.setVisible(false);
|
|
}
|
|
|
|
show(args: any[]): boolean {
|
|
super.show(args);
|
|
|
|
this.headerBgX = this.headerBg.getTopRight().x;
|
|
this.updateAchvIcons();
|
|
|
|
this.mainContainer.setVisible(true);
|
|
this.setCursor(0);
|
|
this.setScrollCursor(0);
|
|
|
|
this.getUi().moveTo(this.mainContainer, this.getUi().length - 1);
|
|
|
|
this.getUi().hideTooltip();
|
|
|
|
return true;
|
|
}
|
|
|
|
protected showAchv(achv: Achv) {
|
|
// We need to get the player gender from the game data to add the correct prefix to the achievement name
|
|
const playerGender = this.scene.gameData.gender;
|
|
let genderPrefix = "PGM";
|
|
if (playerGender === PlayerGender.FEMALE) {
|
|
genderPrefix = "PGF";
|
|
}
|
|
|
|
achv.name = i18next.t(`${genderPrefix}achv:${achv.localizationKey}.name` as ParseKeys);
|
|
achv.description = getAchievementDescription(achv.localizationKey);
|
|
const achvUnlocks = this.scene.gameData.achvUnlocks;
|
|
const unlocked = achvUnlocks.hasOwnProperty(achv.id);
|
|
const hidden = !unlocked && achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId));
|
|
this.titleText.setText(unlocked ? achv.name : "???");
|
|
this.showText(!hidden ? achv.description : "");
|
|
this.scoreText.setText(`${achv.score}pt`);
|
|
this.unlockText.setText(unlocked ? new Date(achvUnlocks[achv.id]).toLocaleDateString() : i18next.t(`${genderPrefix}achv:Locked.name` as ParseKeys));
|
|
}
|
|
|
|
protected showVoucher(voucher: Voucher) {
|
|
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
|
|
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
|
|
|
|
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
|
|
this.showText(voucher.description);
|
|
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : i18next.t("voucher:locked"));
|
|
}
|
|
|
|
processInput(button: Button): boolean {
|
|
const ui = this.getUi();
|
|
|
|
let success = false;
|
|
|
|
if (button === Button.ACTION) {
|
|
success = true;
|
|
this.setScrollCursor(0);
|
|
if (this.currentPage === Page.ACHIEVEMENTS) {
|
|
this.currentPage = Page.VOUCHERS;
|
|
this.updateVoucherIcons();
|
|
} else if (this.currentPage === Page.VOUCHERS) {
|
|
this.currentPage = Page.ACHIEVEMENTS;
|
|
this.updateAchvIcons();
|
|
}
|
|
this.setCursor(0, true);
|
|
this.mainContainer.update();
|
|
}
|
|
if (button === Button.CANCEL) {
|
|
success = true;
|
|
this.scene.ui.revertMode();
|
|
} else {
|
|
const rowIndex = Math.floor(this.cursor / this.COLS);
|
|
const itemOffset = (this.scrollCursor * this.COLS);
|
|
switch (button) {
|
|
case Button.UP:
|
|
if (this.cursor < this.COLS) {
|
|
if (this.scrollCursor) {
|
|
success = this.setScrollCursor(this.scrollCursor - 1);
|
|
}
|
|
} else {
|
|
success = this.setCursor(this.cursor - this.COLS);
|
|
}
|
|
break;
|
|
case Button.DOWN:
|
|
const canMoveDown = (this.cursor + itemOffset) + this.COLS < this.currentTotal;
|
|
if (rowIndex >= this.ROWS - 1) {
|
|
if (this.scrollCursor < Math.ceil(this.currentTotal / this.COLS) - this.ROWS && canMoveDown) {
|
|
success = this.setScrollCursor(this.scrollCursor + 1);
|
|
}
|
|
} else if (canMoveDown) {
|
|
success = this.setCursor(this.cursor + this.COLS);
|
|
}
|
|
break;
|
|
case Button.LEFT:
|
|
if (!this.cursor && this.scrollCursor) {
|
|
success = this.setScrollCursor(this.scrollCursor - 1) && this.setCursor(this.cursor + (this.COLS - 1));
|
|
} else if (this.cursor) {
|
|
success = this.setCursor(this.cursor - 1);
|
|
}
|
|
break;
|
|
case Button.RIGHT:
|
|
if (this.cursor + 1 === this.ROWS * this.COLS && this.scrollCursor < Math.ceil(this.currentTotal / this.COLS) - this.ROWS) {
|
|
success = this.setScrollCursor(this.scrollCursor + 1) && this.setCursor(this.cursor - (this.COLS - 1));
|
|
} else if (this.cursor + itemOffset < this.currentTotal - 1) {
|
|
success = this.setCursor(this.cursor + 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
ui.playSelect();
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
setCursor(cursor: integer, pageChange?: boolean): boolean {
|
|
const ret = super.setCursor(cursor);
|
|
|
|
let update = ret;
|
|
|
|
if (!this.cursorObj) {
|
|
this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", undefined, 16, 16, 1, 1, 1, 1);
|
|
this.cursorObj.setOrigin(0, 0);
|
|
this.iconsContainer.add(this.cursorObj);
|
|
update = true;
|
|
}
|
|
|
|
this.cursorObj.setPositionRelative(this.icons[this.cursor], 0, 0);
|
|
|
|
if (update || pageChange) {
|
|
switch (this.currentPage) {
|
|
case Page.ACHIEVEMENTS:
|
|
this.showAchv(achvs[Object.keys(achvs)[cursor + this.scrollCursor * this.COLS]]);
|
|
break;
|
|
case Page.VOUCHERS:
|
|
this.showVoucher(vouchers[Object.keys(vouchers)[cursor + this.scrollCursor * this.COLS]]);
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* setScrollCursor(scrollCursor: integer) : boolean
|
|
* scrollCursor refers to the page's position within the entire sum of the data, unlike cursor, which refers to a user's position within displayed data
|
|
* @param takes a scrollCursor that has been updated based on user behavior
|
|
* @returns returns a boolean that indicates whether the updated scrollCursor led to an update in the data displayed.
|
|
*/
|
|
setScrollCursor(scrollCursor: integer): boolean {
|
|
if (scrollCursor === this.scrollCursor) {
|
|
return false;
|
|
}
|
|
|
|
this.scrollCursor = scrollCursor;
|
|
|
|
switch (this.currentPage) {
|
|
case Page.ACHIEVEMENTS:
|
|
this.updateAchvIcons();
|
|
this.showAchv(achvs[Object.keys(achvs)[Math.min(this.cursor + this.scrollCursor * this.COLS, Object.values(achvs).length - 1)]]);
|
|
break;
|
|
case Page.VOUCHERS:
|
|
this.updateVoucherIcons();
|
|
this.showVoucher(vouchers[Object.keys(vouchers)[Math.min(this.cursor + this.scrollCursor * this.COLS, Object.values(vouchers).length - 1)]]);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* updateAchvIcons(): void
|
|
* Determines what data is to be displayed on the UI and updates it accordingly based on the current value of this.scrollCursor
|
|
*/
|
|
updateAchvIcons(): void {
|
|
this.headerText.text = this.achvsName;
|
|
this.headerActionText.text = this.vouchersName;
|
|
const textPosition = this.headerBgX - this.headerActionText.displayWidth - 8;
|
|
this.headerActionText.setX(textPosition);
|
|
this.headerActionButton.setX(textPosition - this.headerActionButton.displayWidth - 4);
|
|
|
|
const achvUnlocks = this.scene.gameData.achvUnlocks;
|
|
|
|
const itemOffset = this.scrollCursor * this.COLS;
|
|
const itemLimit = this.ROWS * this.COLS;
|
|
|
|
const achvRange = Object.values(achvs).slice(itemOffset, itemLimit + itemOffset);
|
|
|
|
achvRange.forEach((achv: Achv, i: integer) => {
|
|
const icon = this.icons[i];
|
|
const unlocked = achvUnlocks.hasOwnProperty(achv.id);
|
|
const hidden = !unlocked && achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId));
|
|
const tinted = !hidden && !unlocked;
|
|
|
|
icon.setFrame(!hidden ? achv.iconImage : "unknown");
|
|
icon.setVisible(true);
|
|
if (tinted) {
|
|
icon.setTintFill(0);
|
|
} else {
|
|
icon.clearTint();
|
|
}
|
|
});
|
|
|
|
if (achvRange.length < this.icons.length) {
|
|
this.icons.slice(achvRange.length).map(i => i.setVisible(false));
|
|
}
|
|
|
|
this.currentTotal = this.achvsTotal;
|
|
}
|
|
|
|
/**
|
|
* updateVoucherIcons(): void
|
|
* Determines what data is to be displayed on the UI and updates it accordingly based on the current value of this.scrollCursor
|
|
*/
|
|
updateVoucherIcons(): void {
|
|
this.headerText.text = this.vouchersName;
|
|
this.headerActionText.text = this.achvsName;
|
|
const textPosition = this.headerBgX - this.headerActionText.displayWidth - 8;
|
|
this.headerActionText.setX(textPosition);
|
|
this.headerActionButton.setX(textPosition - this.headerActionButton.displayWidth - 4);
|
|
|
|
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
|
|
|
|
const itemOffset = this.scrollCursor * this.COLS;
|
|
const itemLimit = this.ROWS * this.COLS;
|
|
|
|
const voucherRange = Object.values(vouchers).slice(itemOffset, itemLimit + itemOffset);
|
|
|
|
voucherRange.forEach((voucher: Voucher, i: integer) => {
|
|
const icon = this.icons[i];
|
|
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
|
|
|
|
icon.setFrame(getVoucherTypeIcon(voucher.voucherType));
|
|
icon.setVisible(true);
|
|
if (!unlocked) {
|
|
icon.setTintFill(0);
|
|
} else {
|
|
icon.clearTint();
|
|
}
|
|
});
|
|
|
|
if (voucherRange.length < this.icons.length) {
|
|
this.icons.slice(voucherRange.length).map(i => i.setVisible(false));
|
|
}
|
|
this.currentTotal = this.vouchersTotal;
|
|
}
|
|
|
|
clear() {
|
|
super.clear();
|
|
this.currentPage = Page.ACHIEVEMENTS;
|
|
this.mainContainer.setVisible(false);
|
|
this.eraseCursor();
|
|
}
|
|
|
|
eraseCursor() {
|
|
if (this.cursorObj) {
|
|
this.cursorObj.destroy();
|
|
}
|
|
this.cursorObj = null;
|
|
}
|
|
}
|