mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-12-16 23:05:23 +01:00
278 lines
8.6 KiB
TypeScript
278 lines
8.6 KiB
TypeScript
import { globalScene } from "#app/global-scene";
|
|
import { Button } from "#enums/buttons";
|
|
import { TextStyle } from "#enums/text-style";
|
|
import type { UiMode } from "#enums/ui-mode";
|
|
import { NavigationManager } from "#ui/navigation-menu";
|
|
import { addTextObject, getTextColor } from "#ui/text";
|
|
import { UiHandler } from "#ui/ui-handler";
|
|
import { addWindow } from "#ui/ui-theme";
|
|
import i18next from "i18next";
|
|
|
|
type CancelFn = (success?: boolean) => boolean;
|
|
|
|
/**
|
|
* Abstract class for handling UI elements related to button bindings.
|
|
*/
|
|
export abstract class AbstractBindingUiHandler extends UiHandler {
|
|
// Containers for different segments of the UI.
|
|
protected optionSelectContainer: Phaser.GameObjects.Container;
|
|
protected actionsContainer: Phaser.GameObjects.Container;
|
|
|
|
// Background elements for titles and action areas.
|
|
protected titleBg: Phaser.GameObjects.NineSlice;
|
|
protected actionBg: Phaser.GameObjects.NineSlice;
|
|
protected optionSelectBg: Phaser.GameObjects.NineSlice;
|
|
|
|
// Text elements for displaying instructions and actions.
|
|
protected unlockText: Phaser.GameObjects.Text;
|
|
protected timerText: Phaser.GameObjects.Text;
|
|
protected swapText: Phaser.GameObjects.Text;
|
|
protected actionLabel: Phaser.GameObjects.Text;
|
|
protected cancelLabel: Phaser.GameObjects.Text;
|
|
|
|
protected listening = false;
|
|
protected buttonPressed: number | null = null;
|
|
|
|
// Icons for displaying current and new button assignments.
|
|
protected newButtonIcon: Phaser.GameObjects.Sprite;
|
|
protected targetButtonIcon: Phaser.GameObjects.Sprite;
|
|
|
|
// Function to call on cancel or completion of binding.
|
|
protected cancelFn: CancelFn | null;
|
|
abstract swapAction(): boolean;
|
|
|
|
protected timeLeftAutoClose = 5;
|
|
protected countdownTimer;
|
|
|
|
// The specific setting being modified.
|
|
protected target;
|
|
|
|
/**
|
|
* Constructor for the AbstractBindingUiHandler.
|
|
*
|
|
* @param mode - The UI mode.
|
|
*/
|
|
constructor(mode: UiMode | null = null) {
|
|
super(mode);
|
|
}
|
|
|
|
/**
|
|
* Setup UI elements.
|
|
*/
|
|
setup() {
|
|
const ui = this.getUi();
|
|
this.optionSelectContainer = globalScene.add.container(0, 0);
|
|
this.actionsContainer = globalScene.add.container(0, 0);
|
|
// Initially, containers are not visible.
|
|
this.optionSelectContainer.setVisible(false);
|
|
this.actionsContainer.setVisible(false);
|
|
|
|
// Add containers to the UI.
|
|
ui.add(this.optionSelectContainer);
|
|
ui.add(this.actionsContainer);
|
|
|
|
// Setup backgrounds and text objects for UI.
|
|
this.titleBg = addWindow(
|
|
globalScene.scaledCanvas.width - this.getWindowWidth(),
|
|
-globalScene.scaledCanvas.height + 28 + 21,
|
|
this.getWindowWidth(),
|
|
24,
|
|
);
|
|
this.titleBg.setOrigin(0.5);
|
|
this.optionSelectContainer.add(this.titleBg);
|
|
|
|
this.actionBg = addWindow(
|
|
globalScene.scaledCanvas.width - this.getWindowWidth(),
|
|
-globalScene.scaledCanvas.height + this.getWindowHeight() + 28 + 21 + 21,
|
|
this.getWindowWidth(),
|
|
24,
|
|
);
|
|
this.actionBg.setOrigin(0.5);
|
|
this.actionsContainer.add(this.actionBg);
|
|
|
|
// Text prompts and instructions for the user.
|
|
this.unlockText = addTextObject(0, 0, i18next.t("settings:pressButton"), TextStyle.WINDOW);
|
|
this.unlockText.setOrigin(0, 0);
|
|
this.unlockText.setPositionRelative(this.titleBg, 36, 4);
|
|
this.optionSelectContainer.add(this.unlockText);
|
|
|
|
this.timerText = addTextObject(0, 0, "(5)", TextStyle.WINDOW);
|
|
this.timerText.setOrigin(0, 0);
|
|
this.timerText.setPositionRelative(this.unlockText, this.unlockText.width / 6 + 5, 0);
|
|
this.optionSelectContainer.add(this.timerText);
|
|
|
|
this.optionSelectBg = addWindow(
|
|
globalScene.scaledCanvas.width - this.getWindowWidth(),
|
|
-globalScene.scaledCanvas.height + this.getWindowHeight() + 28,
|
|
this.getWindowWidth(),
|
|
this.getWindowHeight(),
|
|
);
|
|
this.optionSelectBg.setOrigin(0.5);
|
|
this.optionSelectContainer.add(this.optionSelectBg);
|
|
|
|
this.cancelLabel = addTextObject(0, 0, i18next.t("settings:back"), TextStyle.SETTINGS_LABEL);
|
|
this.cancelLabel.setOrigin(0, 0.5);
|
|
this.cancelLabel.setPositionRelative(this.actionBg, 10, this.actionBg.height / 2);
|
|
this.actionsContainer.add(this.cancelLabel);
|
|
}
|
|
|
|
manageAutoCloseTimer() {
|
|
clearTimeout(this.countdownTimer);
|
|
this.countdownTimer = setTimeout(() => {
|
|
this.timeLeftAutoClose -= 1;
|
|
this.timerText.setText(`(${this.timeLeftAutoClose})`);
|
|
if (this.timeLeftAutoClose >= 0) {
|
|
this.manageAutoCloseTimer();
|
|
} else {
|
|
this.cancelFn?.();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
/**
|
|
* Show the UI with the provided arguments.
|
|
*
|
|
* @param args - Arguments to be passed to the show method.
|
|
* @returns `true` if successful.
|
|
*/
|
|
show(args: any[]): boolean {
|
|
super.show(args);
|
|
this.buttonPressed = null;
|
|
this.timeLeftAutoClose = 5;
|
|
this.cancelFn = args[0].cancelHandler;
|
|
this.target = args[0].target;
|
|
|
|
// Bring the option and action containers to the front of the UI.
|
|
this.getUi().bringToTop(this.optionSelectContainer);
|
|
this.getUi().bringToTop(this.actionsContainer);
|
|
|
|
this.optionSelectContainer.setVisible(true);
|
|
setTimeout(() => {
|
|
this.listening = true;
|
|
this.manageAutoCloseTimer();
|
|
}, 100);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the width of the window.
|
|
*
|
|
* @returns The window width.
|
|
*/
|
|
getWindowWidth(): number {
|
|
return 160;
|
|
}
|
|
|
|
/**
|
|
* Get the height of the window.
|
|
*
|
|
* @returns The window height.
|
|
*/
|
|
getWindowHeight(): number {
|
|
return 64;
|
|
}
|
|
|
|
/**
|
|
* Process the input for the given button.
|
|
*
|
|
* @param button - The button to process.
|
|
* @returns `true` if the input was processed successfully.
|
|
*/
|
|
processInput(button: Button): boolean {
|
|
if (this.buttonPressed === null) {
|
|
return false; // TODO: is false correct as default? (previously was `undefined`)
|
|
}
|
|
const ui = this.getUi();
|
|
let success = false;
|
|
switch (button) {
|
|
case Button.LEFT:
|
|
case Button.RIGHT: {
|
|
// Toggle between action and cancel options.
|
|
success = this.setCursor(this.cursor ? 0 : 1);
|
|
break;
|
|
}
|
|
case Button.ACTION:
|
|
// Process actions based on current cursor position.
|
|
if (this.cursor === 0) {
|
|
this.cancelFn?.();
|
|
} else {
|
|
success = this.swapAction();
|
|
NavigationManager.getInstance().updateIcons();
|
|
this.cancelFn?.(success);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Plays a select sound effect if an action was successfully processed.
|
|
if (success) {
|
|
ui.playSelect();
|
|
} else {
|
|
ui.playError();
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
/**
|
|
* Set the cursor to the specified position.
|
|
*
|
|
* @param cursor - The cursor position to set.
|
|
* @returns `true` if the cursor was set successfully.
|
|
*/
|
|
setCursor(cursor: number): boolean {
|
|
this.cursor = cursor;
|
|
if (cursor === 1) {
|
|
this.actionLabel.setColor(getTextColor(TextStyle.SETTINGS_SELECTED));
|
|
this.actionLabel.setShadowColor(getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
|
this.cancelLabel.setColor(getTextColor(TextStyle.WINDOW));
|
|
this.cancelLabel.setShadowColor(getTextColor(TextStyle.WINDOW, true));
|
|
return true;
|
|
}
|
|
this.actionLabel.setColor(getTextColor(TextStyle.WINDOW));
|
|
this.actionLabel.setShadowColor(getTextColor(TextStyle.WINDOW, true));
|
|
this.cancelLabel.setColor(getTextColor(TextStyle.SETTINGS_SELECTED));
|
|
this.cancelLabel.setShadowColor(getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Clear the UI elements and state.
|
|
*/
|
|
clear() {
|
|
super.clear();
|
|
clearTimeout(this.countdownTimer);
|
|
this.timerText.setText("(5)");
|
|
this.timeLeftAutoClose = 5;
|
|
this.listening = false;
|
|
this.target = null;
|
|
this.cancelFn = null;
|
|
this.optionSelectContainer.setVisible(false);
|
|
this.actionsContainer.setVisible(false);
|
|
this.newButtonIcon.setVisible(false);
|
|
this.buttonPressed = null;
|
|
}
|
|
|
|
/**
|
|
* Handle input down events.
|
|
*
|
|
* @param buttonIcon - The icon of the button that was pressed.
|
|
* @param assignedButtonIcon - The icon of the button that is assigned.
|
|
* @param type - The type of button press.
|
|
*/
|
|
onInputDown(buttonIcon: string, assignedButtonIcon: string | null, type: string): void {
|
|
clearTimeout(this.countdownTimer);
|
|
this.timerText.setText("");
|
|
this.newButtonIcon.setTexture(type);
|
|
this.newButtonIcon.setFrame(buttonIcon);
|
|
if (assignedButtonIcon) {
|
|
this.targetButtonIcon.setTexture(type);
|
|
this.targetButtonIcon.setFrame(assignedButtonIcon);
|
|
this.targetButtonIcon.setVisible(true);
|
|
this.swapText.setVisible(true);
|
|
}
|
|
this.newButtonIcon.setVisible(true);
|
|
this.setCursor(0);
|
|
this.actionsContainer.setVisible(true);
|
|
}
|
|
}
|