From 81f0228b3c0fc449b49eea42211c353e77de6c5b Mon Sep 17 00:00:00 2001 From: Burai Mu Date: Tue, 16 Sep 2025 23:12:22 +0800 Subject: [PATCH] - Adding Hotkeys --- src/battle-scene.ts | 1 + src/configs/inputs/config-handler.ts | 11 ++++ src/inputs-controller.ts | 10 +++- src/system/settings/settings.ts | 11 ++++ src/ui-inputs.ts | 22 ++++++-- src/ui/handlers/modifier-select-ui-handler.ts | 51 +++++++++++++++---- src/ui/handlers/ui-handler.ts | 2 + .../abstract-control-settings-ui-handler.ts | 25 +++++---- 8 files changed, 109 insertions(+), 24 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 94b77303469..cbe82857414 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -231,6 +231,7 @@ export class BattleScene extends SceneBase { public fusionPaletteSwaps = true; public enableTouchControls = false; public enableVibration = false; + public enableHotkeyTip = false; public showBgmBar = true; public hideUsername = false; /** Determines the selected battle style. */ diff --git a/src/configs/inputs/config-handler.ts b/src/configs/inputs/config-handler.ts index 11af770f969..823b30a8efb 100644 --- a/src/configs/inputs/config-handler.ts +++ b/src/configs/inputs/config-handler.ts @@ -92,6 +92,17 @@ export function getIconWithSettingName(config, settingName) { return getIconWithKey(config, key); } +export function getKeyForLatestInput(configs, source, devices, settingName) { + let config: any; // TODO: refine type + if (source === "gamepad") { + config = configs[devices[Device.GAMEPAD]]; + } else { + config = configs[devices[Device.KEYBOARD]]; + } + const key = Object.keys(config["custom"]).find(k => config["custom"][k] === settingName); + return key?.slice(4) +} + export function getIconForLatestInput(configs, source, devices, settingName) { let config: any; // TODO: refine type if (source === "gamepad") { diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index 0207297fd58..0e19cf20dd7 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -4,7 +4,7 @@ import { Button } from "#enums/buttons"; import { Device } from "#enums/devices"; import { UiMode } from "#enums/ui-mode"; import cfg_keyboard_qwerty from "#inputs/cfg-keyboard-qwerty"; -import { assign, getButtonWithKeycode, getIconForLatestInput, swap } from "#inputs/config-handler"; +import { assign, getButtonWithKeycode, getIconForLatestInput, getKeyForLatestInput, getKeyWithKeycode, swap } from "#inputs/config-handler"; import pad_dualshock from "#inputs/pad-dualshock"; import pad_generic from "#inputs/pad-generic"; import pad_procon from "#inputs/pad-procon"; @@ -540,6 +540,14 @@ export class InputsController { return getIconForLatestInput(this.configs, this.lastSource, this.selectedDevice, settingName); } + getKeyForLatestInputRecorded(settingName) { + if (this.lastSource === "keyboard") { + this.ensureKeyboardIsInit(); + } + return getKeyForLatestInput(this.configs, this.lastSource, this.selectedDevice, settingName); + } + + getLastSourceDevice(): Device { if (this.lastSource === "gamepad") { return Device.GAMEPAD; diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 78b6044b0fc..467b8e291d3 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -151,6 +151,7 @@ export const SettingKeys = { Tutorials: "TUTORIALS", Touch_Controls: "TOUCH_CONTROLS", Vibration: "VIBRATION", + HotkeyTips: "HOTKEY_TIPS", Language: "LANGUAGE", UI_Theme: "UI_THEME", Window_Type: "WINDOW_TYPE", @@ -386,6 +387,13 @@ export const Setting: Array = [ default: 0, type: SettingType.GENERAL, }, + { + key: SettingKeys.HotkeyTips, + label: i18next.t("settings:hotkeyTips"), + options: OFF_ON, + default: 0, + type: SettingType.GENERAL, + }, { key: SettingKeys.Touch_Controls, label: i18next.t("settings:touchControls"), @@ -906,6 +914,9 @@ export function setSetting(setting: string, value: number): boolean { case SettingKeys.Vibration: globalScene.enableVibration = Setting[index].options[value].value !== "Disabled" && hasTouchscreen(); break; + case SettingKeys.HotkeyTips: + globalScene.enableHotkeyTip = Setting[index].options[value].value !== "On"; + break; case SettingKeys.Type_Hints: globalScene.typeHints = Setting[index].options[value].value === "On"; break; diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 72144ccddac..13cf701fc4b 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -87,8 +87,8 @@ export class UiInputs { [Button.LEFT]: () => this.buttonDirection(Button.LEFT), [Button.RIGHT]: () => this.buttonDirection(Button.RIGHT), [Button.SUBMIT]: () => this.buttonTouch(), - [Button.ACTION]: () => this.buttonAb(Button.ACTION), - [Button.CANCEL]: () => this.buttonAb(Button.CANCEL), + [Button.ACTION]: () => this.buttonAB(Button.ACTION), + [Button.CANCEL]: () => this.buttonAB(Button.CANCEL), [Button.MENU]: () => this.buttonMenu(), [Button.STATS]: () => this.buttonGoToFilter(Button.STATS), [Button.CYCLE_SHINY]: () => this.buttonCycleOption(Button.CYCLE_SHINY), @@ -132,7 +132,15 @@ export class UiInputs { this.doVibration(inputSuccess, vibrationLength); } - buttonAb(button: Button): void { + buttonAB(button: Button): void { + if (this.isInSettings()) { + const whiteListUIModes : UiMode[] = [ + UiMode.MODIFIER_SELECT + ] + for (const uiMode of whiteListUIModes){ + globalScene.ui.handlers[uiMode].updateInstructionsText() + } + } globalScene.ui.processInput(button); } @@ -250,4 +258,12 @@ export class UiInputs { (globalScene.ui.getHandler() as SettingsUiHandler).show([]); } } + + private isInSettings(){ + return globalScene.ui?.getMode() === UiMode.SETTINGS || + globalScene.ui?.getMode() === UiMode.SETTINGS_AUDIO || + globalScene.ui?.getMode() === UiMode.SETTINGS_DISPLAY || + globalScene.ui?.getMode() === UiMode.SETTINGS_GAMEPAD || + globalScene.ui?.getMode() === UiMode.SETTINGS_KEYBOARD + } } diff --git a/src/ui/handlers/modifier-select-ui-handler.ts b/src/ui/handlers/modifier-select-ui-handler.ts index 8807f6daf66..930f09068fb 100644 --- a/src/ui/handlers/modifier-select-ui-handler.ts +++ b/src/ui/handlers/modifier-select-ui-handler.ts @@ -11,6 +11,7 @@ import { UiMode } from "#enums/ui-mode"; import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#modifiers/modifier"; import type { ModifierTypeOption } from "#modifiers/modifier-type"; import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "#modifiers/modifier-type"; +import { SettingKeyboard } from "#system/settings-keyboard"; import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; import { MoveInfoOverlay } from "#ui/move-info-overlay"; import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions } from "#ui/text"; @@ -31,6 +32,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { private checkButtonContainer: Phaser.GameObjects.Container; private continueButtonContainer: Phaser.GameObjects.Container; private rerollCostText: Phaser.GameObjects.Text; + private rerollButtonText: Phaser.GameObjects.Text; private lockRarityButtonText: Phaser.GameObjects.Text; private moveInfoOverlay: MoveInfoOverlay; private moveInfoOverlayActive = false; @@ -100,26 +102,28 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { this.rerollButtonContainer.setName("reroll-brn"); this.rerollButtonContainer.setVisible(false); ui.add(this.rerollButtonContainer); - - const rerollButtonText = addTextObject(-4, -2, i18next.t("modifierSelectUiHandler:reroll"), TextStyle.PARTY); - rerollButtonText.setName("text-reroll-btn"); - rerollButtonText.setOrigin(0, 0); - this.rerollButtonContainer.add(rerollButtonText); + + const Reroll_Key = !globalScene.enableHotkeyTip ? globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny) ? `(${globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny)}) ` : "" : ""; + this.rerollButtonText = addTextObject(-4, -2, i18next.t("modifierSelectUiHandler:reroll", {Reroll_Key}), TextStyle.PARTY); + this.rerollButtonText.setName("text-reroll-btn"); + this.rerollButtonText.setOrigin(0, 0); + this.rerollButtonContainer.add(this.rerollButtonText); this.rerollCostText = addTextObject(0, 0, "", TextStyle.MONEY); this.rerollCostText.setName("text-reroll-cost"); this.rerollCostText.setOrigin(0, 0); - this.rerollCostText.setPositionRelative(rerollButtonText, rerollButtonText.displayWidth + 5, 1); + this.rerollCostText.setPositionRelative(this.rerollButtonText, this.rerollButtonText.displayWidth + 5, 1); this.rerollButtonContainer.add(this.rerollCostText); this.lockRarityButtonContainer = globalScene.add.container(16, OPTION_BUTTON_YPOSITION); this.lockRarityButtonContainer.setVisible(false); ui.add(this.lockRarityButtonContainer); + const Lock_Rarity_Key = !globalScene.enableHotkeyTip ? globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Ability) ? `(${globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Ability)}) ` : "" : ""; this.lockRarityButtonText = addTextObject( -4, -2, - i18next.t("modifierSelectUiHandler:lockRarities"), + i18next.t("modifierSelectUiHandler:lockRarities", {Lock_Rarity_Key}), TextStyle.PARTY, ); this.lockRarityButtonText.setOrigin(0, 0); @@ -156,6 +160,11 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { globalScene.addInfoToggle(this.moveInfoOverlay); } + updateInstructionsText() : void { + this.updateRerollText(); + this.updateRerollCostPosition(); + } + show(args: any[]): boolean { globalScene.disableMenu = false; @@ -181,7 +190,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { const partyHasHeldItem = this.player && globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferable).length > 0; - const canLockRarities = !!globalScene.findModifier(m => m instanceof LockModifierTiersModifier); + const canLockRarities = !(!!globalScene.findModifier(m => m instanceof LockModifierTiersModifier)); this.transferButtonContainer.setVisible(false); this.transferButtonContainer.setAlpha(0); @@ -201,7 +210,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { this.rerollButtonContainer.setPositionRelative(this.lockRarityButtonContainer, 0, canLockRarities ? -12 : 0); this.rerollCost = args[3] as number; - + this.updateRerollText(); this.updateRerollCostText(); const typeOptions = args[1] as ModifierTypeOption[]; @@ -682,10 +691,28 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { for (const shopOption of shopOptions) { shopOption.updateCostText(); } - + this.updateRerollText(); this.updateRerollCostText(); } + updateRerollText(): void { + const Reroll_Key = !globalScene.enableHotkeyTip ? globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny) ? `(${globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny)}) ` : "" : ""; + this.rerollButtonText.setText(i18next.t("modifierSelectUiHandler:reroll", { Reroll_Key })); + if (this.lockRarityButtonText.visible){ + const Lock_Rarity_Key = !globalScene.enableHotkeyTip ? globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Ability) ? `(${globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Ability)}) ` : "" : ""; + this.lockRarityButtonText.setText(i18next.t("modifierSelectUiHandler:lockRarities", { Lock_Rarity_Key })); + } + } + + + updateRerollCostPosition(): void { + if (globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny)){ + const Reroll_Key = globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny) + this.rerollCostText.setPositionRelative(this.rerollButtonText, this.rerollButtonText.displayWidth + 5 + Reroll_Key?.length, 1); + } + } + + updateRerollCostText(): void { const rerollDisabled = this.rerollCost < 0; if (rerollDisabled) { @@ -700,6 +727,10 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler { this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney })); this.rerollCostText.setColor(getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED)); this.rerollCostText.setShadowColor(getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED, true)); + if (globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny)){ + const Reroll_Key = globalScene.inputController?.getKeyForLatestInputRecorded( SettingKeyboard.Button_Cycle_Shiny) + this.rerollCostText.setPositionRelative(this.rerollButtonText, this.rerollButtonText.displayWidth + 5 + Reroll_Key?.length, 1); + } } updateLockRaritiesText(): void { diff --git a/src/ui/handlers/ui-handler.ts b/src/ui/handlers/ui-handler.ts index 558cb08f252..264b1778ba2 100644 --- a/src/ui/handlers/ui-handler.ts +++ b/src/ui/handlers/ui-handler.ts @@ -25,6 +25,8 @@ export abstract class UiHandler { return true; } + abstract updateInstructionsText(): void; + abstract processInput(button: Button): boolean; getUi() { diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts index 17812785d1e..5856e5257a8 100644 --- a/src/ui/settings/abstract-control-settings-ui-handler.ts +++ b/src/ui/settings/abstract-control-settings-ui-handler.ts @@ -451,16 +451,21 @@ export abstract class AbstractControlSettingsUiHandler extends UiHandler { // Retrieve the layout settings based on the type of the gamepad. const layout = this.layout[configType]; // Update the main controller with configuration details from the selected layout. - this.keys = layout.keys; - this.optionsContainer = layout.optionsContainer; - this.optionsContainer.setVisible(true); - this.settingLabels = layout.settingLabels; - this.optionValueLabels = layout.optionValueLabels; - this.optionCursors = layout.optionCursors; - this.inputsIcons = layout.inputsIcons; - this.bindingSettings = layout.bindingSettings; - this.scrollBar.setTotalRows(layout.settingLabels.length); - this.scrollBar.setScrollCursor(0); + if (layout){ + this.keys = layout.keys; + this.optionsContainer = layout.optionsContainer; + this.optionsContainer.setVisible(true); + this.settingLabels = layout.settingLabels; + this.optionValueLabels = layout.optionValueLabels; + this.optionCursors = layout.optionCursors; + this.inputsIcons = layout.inputsIcons; + this.bindingSettings = layout.bindingSettings; + this.scrollBar.setTotalRows(layout.settingLabels.length); + this.scrollBar.setScrollCursor(0); + }else{ + return false + } + // Return true indicating the layout was successfully applied. return true;