From 70324c415955477a3f569a5c342df4561537da56 Mon Sep 17 00:00:00 2001 From: Greenlamp2 <44787002+Greenlamp2@users.noreply.github.com> Date: Fri, 3 May 2024 18:59:10 +0200 Subject: [PATCH] Rework - Inputs management to include all gamepad mapping (#390) * rework of the input handling, including different gamepad and keyboard * rework of the input handling, including different gamepad and keyboard * first version of a too complex inputHandler based on phaser3-merged-input * removed useless control management and kept it simple for our use case, investigating to put out button_XX() * renamed inputHandler to inputController * aggregate directions and some action into a same method + fix menu return value * added back repeated input feature on keeping down a key * cleanup + return type * fix submit/action doing two things simultaneously, still same behaviour as before * extracted UI inputs out of battle-scene * tab -> spaces * tab -> spaces what about now github ? --- src/battle-scene.ts | 272 +-------------------- src/configs/pad_dualshock.ts | 29 +++ src/configs/pad_generic.ts | 27 ++ src/configs/pad_unlicensedSNES.ts | 23 ++ src/configs/pad_xbox360.ts | 28 +++ src/inputs-controller.ts | 266 ++++++++++++++++++++ src/ui-inputs.ts | 159 ++++++++++++ src/ui/abstact-option-select-ui-handler.ts | 3 +- src/ui/achvs-ui-handler.ts | 3 +- src/ui/awaitable-ui-handler.ts | 3 +- src/ui/ball-ui-handler.ts | 3 +- src/ui/battle-message-ui-handler.ts | 3 +- src/ui/command-ui-handler.ts | 3 +- src/ui/confirm-ui-handler.ts | 3 +- src/ui/egg-gacha-ui-handler.ts | 3 +- src/ui/egg-hatch-scene-handler.ts | 3 +- src/ui/egg-list-ui-handler.ts | 3 +- src/ui/evolution-scene-handler.ts | 3 +- src/ui/fight-ui-handler.ts | 3 +- src/ui/form-modal-ui-handler.ts | 3 +- src/ui/game-stats-ui-handler.ts | 3 +- src/ui/menu-ui-handler.ts | 3 +- src/ui/modal-ui-handler.ts | 3 +- src/ui/modifier-select-ui-handler.ts | 3 +- src/ui/party-ui-handler.ts | 3 +- src/ui/save-slot-select-ui-handler.ts | 3 +- src/ui/settings-ui-handler.ts | 3 +- src/ui/starter-select-ui-handler.ts | 3 +- src/ui/summary-ui-handler.ts | 3 +- src/ui/target-select-ui-handler.ts | 3 +- src/ui/ui-handler.ts | 3 +- src/ui/ui.ts | 3 +- src/ui/vouchers-ui-handler.ts | 3 +- 33 files changed, 593 insertions(+), 289 deletions(-) create mode 100644 src/configs/pad_dualshock.ts create mode 100644 src/configs/pad_generic.ts create mode 100644 src/configs/pad_unlicensedSNES.ts create mode 100644 src/configs/pad_xbox360.ts create mode 100644 src/inputs-controller.ts create mode 100644 src/ui-inputs.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index cbf363f689a..f6e5a9c5948 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,4 +1,4 @@ -import Phaser, { Time } from 'phaser'; +import Phaser from 'phaser'; import UI, { Mode } from './ui/ui'; import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases'; import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon'; @@ -54,13 +54,14 @@ import CharSprite from './ui/char-sprite'; import DamageNumberHandler from './field/damage-number-handler'; import PokemonInfoContainer from './ui/pokemon-info-container'; import { biomeDepths } from './data/biomes'; -import { initTouchControls } from './touch-controls'; import { UiTheme } from './enums/ui-theme'; import { SceneBase } from './scene-base'; import CandyBar from './ui/candy-bar'; import { Variant, variantData } from './data/variant'; import { Localizable } from './plugins/i18n'; import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides'; +import {InputsController} from "./inputs-controller"; +import {UiInputs} from "./ui-inputs"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -69,33 +70,12 @@ const DEBUG_RNG = false; export const startingWave = STARTING_WAVE_OVERRIDE || 1; const expSpriteKeys: string[] = []; -const repeatInputDelayMillis = 250; export let starterColors: StarterColors; interface StarterColors { [key: string]: [string, string] } -export enum Button { - UP, - DOWN, - LEFT, - RIGHT, - SUBMIT, - ACTION, - CANCEL, - MENU, - STATS, - CYCLE_SHINY, - CYCLE_FORM, - CYCLE_GENDER, - CYCLE_ABILITY, - CYCLE_NATURE, - CYCLE_VARIANT, - SPEED_UP, - SLOW_DOWN -} - export interface PokeballCounts { [pb: string]: integer; } @@ -104,6 +84,8 @@ export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound export default class BattleScene extends SceneBase { public rexUI: UIPlugin; + public inputController: InputsController; + public uiInputs: UiInputs; public sessionPlayTime: integer = null; public masterVolume: number = 0.5; @@ -189,34 +171,6 @@ export default class BattleScene extends SceneBase { private bgmResumeTimer: Phaser.Time.TimerEvent; private bgmCache: Set = new Set(); private playTimeTimer: Phaser.Time.TimerEvent; - - private buttonKeys: Phaser.Input.Keyboard.Key[][]; - private lastProcessedButtonPressTimes: Map = new Map(); - // movementButtonLock ensures only a single movement key is firing repeated inputs - // (i.e. by holding down a button) at a time - private movementButtonLock: Button; - - // using a dualshock controller as a map - private gamepadKeyConfig = { - [Button.UP]: 12, // up - [Button.DOWN]: 13, // down - [Button.LEFT]: 14, // left - [Button.RIGHT]: 15, // right - [Button.SUBMIT]: 17, // touchpad - [Button.ACTION]: 0, // X - [Button.CANCEL]: 1, // O - [Button.MENU]: 9, // options - [Button.STATS]: 8, // share - [Button.CYCLE_SHINY]: 5, // RB - [Button.CYCLE_FORM]: 4, // LB - [Button.CYCLE_GENDER]: 6, // LT - [Button.CYCLE_ABILITY]: 7, // RT - [Button.CYCLE_NATURE]: 2, // square - [Button.CYCLE_VARIANT]: 3, // triangle - [Button.SPEED_UP]: 10, // L3 - [Button.SLOW_DOWN]: 11 // R3 - }; - public gamepadButtonStates: boolean[] = new Array(17).fill(false); public rngCounter: integer = 0; public rngSeedOverride: string = ''; @@ -246,7 +200,9 @@ export default class BattleScene extends SceneBase { this.load.atlas(key, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.png`, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.json`); } - async preload() { + async preload() { + this.load.scenePlugin('inputController', InputsController); + this.load.scenePlugin('uiInputs', UiInputs); if (DEBUG_RNG) { const scene = this; const originalRealInRange = Phaser.Math.RND.realInRange; @@ -260,7 +216,7 @@ export default class BattleScene extends SceneBase { return ret; }; } - + populateAnims(); await this.initVariantData(); @@ -273,8 +229,6 @@ export default class BattleScene extends SceneBase { addUiThemeOverrides(this); - this.setupControls(); - this.load.setBaseURL(); this.spritePipeline = new SpritePipeline(this.game); @@ -287,7 +241,6 @@ export default class BattleScene extends SceneBase { } update() { - this.checkInput(); this.ui?.update(); } @@ -606,42 +559,6 @@ export default class BattleScene extends SceneBase { return true; } - setupControls() { - const keyCodes = Phaser.Input.Keyboard.KeyCodes; - const keyConfig = { - [Button.UP]: [keyCodes.UP, keyCodes.W], - [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], - [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], - [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], - [Button.SUBMIT]: [keyCodes.ENTER], - [Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z], - [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], - [Button.MENU]: [keyCodes.ESC, keyCodes.M], - [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], - [Button.CYCLE_SHINY]: [keyCodes.R], - [Button.CYCLE_FORM]: [keyCodes.F], - [Button.CYCLE_GENDER]: [keyCodes.G], - [Button.CYCLE_ABILITY]: [keyCodes.E], - [Button.CYCLE_NATURE]: [keyCodes.N], - [Button.CYCLE_VARIANT]: [keyCodes.V], - [Button.SPEED_UP]: [keyCodes.PLUS], - [Button.SLOW_DOWN]: [keyCodes.MINUS] - }; - const mobileKeyConfig = {}; - this.buttonKeys = []; - for (let b of Utils.getEnumValues(Button)) { - const keys: Phaser.Input.Keyboard.Key[] = []; - if (keyConfig.hasOwnProperty(b)) { - for (let k of keyConfig[b]) - keys.push(this.input.keyboard.addKey(k, false)); - mobileKeyConfig[Button[b]] = keys[0]; - } - this.buttonKeys[b] = keys; - } - - initTouchControls(mobileKeyConfig); - } - getParty(): PlayerPokemon[] { return this.party; } @@ -1343,177 +1260,6 @@ export default class BattleScene extends SceneBase { return biomes[Utils.randSeedInt(biomes.length)]; } - checkInput(): boolean { - let inputSuccess = false; - let vibrationLength = 0; - if (this.buttonJustPressed(Button.UP) || this.repeatInputDurationJustPassed(Button.UP)) { - inputSuccess = this.ui.processInput(Button.UP); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.UP) - } else if (this.buttonJustPressed(Button.DOWN) || this.repeatInputDurationJustPassed(Button.DOWN)) { - inputSuccess = this.ui.processInput(Button.DOWN); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.DOWN) - } else if (this.buttonJustPressed(Button.LEFT) || this.repeatInputDurationJustPassed(Button.LEFT)) { - inputSuccess = this.ui.processInput(Button.LEFT); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.LEFT) - } else if (this.buttonJustPressed(Button.RIGHT) || this.repeatInputDurationJustPassed(Button.RIGHT)) { - inputSuccess = this.ui.processInput(Button.RIGHT); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.RIGHT) - } else if (this.buttonJustPressed(Button.SUBMIT) || this.repeatInputDurationJustPassed(Button.SUBMIT)) { - inputSuccess = this.ui.processInput(Button.SUBMIT) || this.ui.processInput(Button.ACTION); - this.setLastProcessedMovementTime(Button.SUBMIT); - } else if (this.buttonJustPressed(Button.ACTION) || this.repeatInputDurationJustPassed(Button.ACTION)) { - inputSuccess = this.ui.processInput(Button.ACTION); - this.setLastProcessedMovementTime(Button.ACTION); - } else if (this.buttonJustPressed(Button.CANCEL)|| this.repeatInputDurationJustPassed(Button.CANCEL)) { - inputSuccess = this.ui.processInput(Button.CANCEL); - this.setLastProcessedMovementTime(Button.CANCEL); - } else if (this.buttonJustPressed(Button.MENU)) { - if (this.disableMenu) - return; - switch (this.ui?.getMode()) { - case Mode.MESSAGE: - if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt) - return; - case Mode.TITLE: - case Mode.COMMAND: - case Mode.FIGHT: - case Mode.BALL: - case Mode.TARGET_SELECT: - case Mode.SAVE_SLOT: - case Mode.PARTY: - case Mode.SUMMARY: - case Mode.STARTER_SELECT: - case Mode.CONFIRM: - case Mode.OPTION_SELECT: - this.ui.setOverlayMode(Mode.MENU); - inputSuccess = true; - break; - case Mode.MENU: - case Mode.SETTINGS: - case Mode.ACHIEVEMENTS: - this.ui.revertMode(); - this.playSound('select'); - inputSuccess = true; - break; - default: - return; - } - } else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) { - if (this.buttonJustPressed(Button.CYCLE_SHINY)) { - inputSuccess = this.ui.processInput(Button.CYCLE_SHINY); - this.setLastProcessedMovementTime(Button.CYCLE_SHINY); - } else if (this.buttonJustPressed(Button.CYCLE_FORM)) { - inputSuccess = this.ui.processInput(Button.CYCLE_FORM); - this.setLastProcessedMovementTime(Button.CYCLE_FORM); - } else if (this.buttonJustPressed(Button.CYCLE_GENDER)) { - inputSuccess = this.ui.processInput(Button.CYCLE_GENDER); - this.setLastProcessedMovementTime(Button.CYCLE_GENDER); - } else if (this.buttonJustPressed(Button.CYCLE_ABILITY)) { - inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY); - this.setLastProcessedMovementTime(Button.CYCLE_ABILITY); - } else if (this.buttonJustPressed(Button.CYCLE_NATURE)) { - inputSuccess = this.ui.processInput(Button.CYCLE_NATURE); - this.setLastProcessedMovementTime(Button.CYCLE_NATURE); - } else if (this.buttonJustPressed(Button.CYCLE_VARIANT)) { - inputSuccess = this.ui.processInput(Button.CYCLE_VARIANT); - this.setLastProcessedMovementTime(Button.CYCLE_VARIANT); - } else - return; - } else if (this.buttonJustPressed(Button.SPEED_UP)) { - if (this.gameSpeed < 5) { - this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1); - if (this.ui?.getMode() === Mode.SETTINGS) - (this.ui.getHandler() as SettingsUiHandler).show([]); - } - } else if (this.buttonJustPressed(Button.SLOW_DOWN)) { - if (this.gameSpeed > 1) { - this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0)); - if (this.ui?.getMode() === Mode.SETTINGS) - (this.ui.getHandler() as SettingsUiHandler).show([]); - } - } else { - let pressed = false; - if (this.ui && (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS)))) { - for (let p of this.getField().filter(p => p?.isActive(true))) - p.toggleStats(pressed); - if (pressed) - this.setLastProcessedMovementTime(Button.STATS); - } else - return; - } - if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') - navigator.vibrate(vibrationLength || 10); - } - - /** - * gamepadButtonJustDown returns true if @param button has just been pressed down - * or not. It will only return true once, until the key is released and pressed down - * again. - */ - gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { - if (!button || !this.gamepadSupport) - return false; - - let ret = false; - if (button.pressed) { - if (!this.gamepadButtonStates[button.index]) - ret = true; - this.gamepadButtonStates[button.index] = true; - } else - this.gamepadButtonStates[button.index] = false; - - return ret; - } - - buttonJustPressed(button: Button): boolean { - const gamepad = this.input.gamepad?.gamepads[0]; - return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); - } - - /** - * gamepadButtonJustUp returns true if @param button has just been released - * or not. It will only return true once, until the key is released and pressed down - * again. - */ - gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { - if (!button || !this.gamepadSupport) - return false; - - return !this.gamepadButtonStates[button.index]; - } - - buttonJustReleased(button: Button): boolean { - const gamepad = this.input.gamepad?.gamepads[0]; - return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); - } - - /** - * repeatInputDurationJustPassed returns true if @param button has been held down long - * enough to fire a repeated input. A button must claim the movementButtonLock before - * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. - */ - repeatInputDurationJustPassed(button: Button): boolean { - if (this.movementButtonLock !== null && this.movementButtonLock !== button) { - return false; - } - if (this.buttonKeys[button].every(k => k.isUp) && this.gamepadButtonStates.every(b => b == false)) { - this.movementButtonLock = null; - return false; - } - if (this.time.now - this.lastProcessedButtonPressTimes.get(button) >= repeatInputDelayMillis) { - return true; - } - } - - setLastProcessedMovementTime(button: Button) { - this.lastProcessedButtonPressTimes.set(button, this.time.now); - this.movementButtonLock = button; - } - isBgmPlaying(): boolean { return this.bgm && this.bgm.isPlaying; } diff --git a/src/configs/pad_dualshock.ts b/src/configs/pad_dualshock.ts new file mode 100644 index 00000000000..4f66ff8c00a --- /dev/null +++ b/src/configs/pad_dualshock.ts @@ -0,0 +1,29 @@ +/** + * Dualshock mapping + */ +const pad_dualshock = { + padID: 'Dualshock', + padType: 'Sony', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, // Options + SELECT: 8, // Share + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15, + MENU: 16, + TOUCH: 17 + }, +}; + +export default pad_dualshock; diff --git a/src/configs/pad_generic.ts b/src/configs/pad_generic.ts new file mode 100644 index 00000000000..19b5d3df16e --- /dev/null +++ b/src/configs/pad_generic.ts @@ -0,0 +1,27 @@ +/** + * Generic pad mapping + */ +const pad_generic = { + padID: 'Generic', + padType: 'generic', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15 + }, +}; + +export default pad_generic; diff --git a/src/configs/pad_unlicensedSNES.ts b/src/configs/pad_unlicensedSNES.ts new file mode 100644 index 00000000000..ba8ee538d30 --- /dev/null +++ b/src/configs/pad_unlicensedSNES.ts @@ -0,0 +1,23 @@ +/** + * 081f-e401 - UnlicensedSNES + */ +const pad_unlicensedSNES = { + padID: '081f-e401', + padType: 'snes', + gamepadMapping : { + RC_S: 2, + RC_E: 1, + RC_W: 3, + RC_N: 0, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15 + } +}; + +export default pad_unlicensedSNES; diff --git a/src/configs/pad_xbox360.ts b/src/configs/pad_xbox360.ts new file mode 100644 index 00000000000..e44ebb54b64 --- /dev/null +++ b/src/configs/pad_xbox360.ts @@ -0,0 +1,28 @@ +/** + * Generic pad mapping + */ +const pad_xbox360 = { + padID: 'Xbox 360 controller (XInput STANDARD GAMEPAD)', + padType: 'xbox', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15, + MENU: 16 + }, +}; + +export default pad_xbox360; diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts new file mode 100644 index 00000000000..441649a5199 --- /dev/null +++ b/src/inputs-controller.ts @@ -0,0 +1,266 @@ +import Phaser, {Time} from "phaser"; +import * as Utils from "./utils"; +import {initTouchControls} from './touch-controls'; +import pad_generic from "#app/configs/pad_generic"; +import pad_unlicensedSNES from "#app/configs/pad_unlicensedSNES"; +import pad_xbox360 from "#app/configs/pad_xbox360"; +import pad_dualshock from "#app/configs/pad_dualshock"; + + +export enum Button { + UP, + DOWN, + LEFT, + RIGHT, + SUBMIT, + ACTION, + CANCEL, + MENU, + STATS, + CYCLE_SHINY, + CYCLE_FORM, + CYCLE_GENDER, + CYCLE_ABILITY, + CYCLE_NATURE, + CYCLE_VARIANT, + SPEED_UP, + SLOW_DOWN +} + +const repeatInputDelayMillis = 250; + +export class InputsController extends Phaser.Plugins.ScenePlugin { + private game: Phaser.Game; + private buttonKeys: Phaser.Input.Keyboard.Key[][]; + private gamepads: Array = new Array(); + private scene: Phaser.Scene; + + // buttonLock ensures only a single movement key is firing repeated inputs + // (i.e. by holding down a button) at a time + private buttonLock: Button; + private interactions: Map> = new Map(); + private time: Time; + + constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { + super(scene, pluginManager, pluginKey); + this.game = pluginManager.game; + this.scene = scene; + this.time = this.scene.time; + this.buttonKeys = []; + + for (const b of Utils.getEnumValues(Button)) { + this.interactions[b] = { + pressTime: false, + isPressed: false, + } + } + // We don't want the menu key to be repeated + delete this.interactions[Button.MENU]; + } + + boot() { + this.eventEmitter = this.systems.events; + this.events = new Phaser.Events.EventEmitter(); + this.game.events.on(Phaser.Core.Events.STEP, this.update, this); + + if (typeof this.systems.input.gamepad !== 'undefined') { + this.systems.input.gamepad.on('connected', function (thisGamepad) { + this.refreshGamepads(); + this.setupGamepad(thisGamepad); + }, this); + + // Check to see if the gamepad has already been setup by the browser + this.systems.input.gamepad.refreshPads(); + if (this.systems.input.gamepad.total) { + this.refreshGamepads(); + for (const thisGamepad of this.gamepads) { + this.systems.input.gamepad.emit('connected', thisGamepad); + } + } + + this.systems.input.gamepad.on('down', this.gamepadButtonDown, this); + this.systems.input.gamepad.on('up', this.gamepadButtonUp, this); + } + + // Keyboard + this.setupKeyboardControls(); + } + + update() { + for (const b of Utils.getEnumValues(Button)) { + if (!this.interactions.hasOwnProperty(b)) continue; + if (this.repeatInputDurationJustPassed(b)) { + this.events.emit('input_down', { + controller_type: 'keyboard', + button: b, + }); + this.setLastProcessedMovementTime(b); + } + } + } + + setupGamepad(thisGamepad): void { + let gamepadID = thisGamepad.id.toLowerCase(); + const mappedPad = this.mapGamepad(gamepadID); + this.player = { + 'mapping': mappedPad.gamepadMapping, + } + } + + refreshGamepads(): void { + // Sometimes, gamepads are undefined. For some reason. + this.gamepads = this.systems.input.gamepad.gamepads.filter(function (el) { + return el != null; + }); + + for (const [index, thisGamepad] of this.gamepads.entries()) { + thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier + } + } + + getActionGamepadMapping() { + const gamepadMapping = {}; + gamepadMapping[this.player.mapping.LC_N] = Button.UP; + gamepadMapping[this.player.mapping.LC_S] = Button.DOWN; + gamepadMapping[this.player.mapping.LC_W] = Button.LEFT; + gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT; + gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT; + gamepadMapping[this.player.mapping.RC_S] = Button.ACTION; + gamepadMapping[this.player.mapping.RC_E] = Button.CANCEL; + gamepadMapping[this.player.mapping.SELECT] = Button.STATS; + gamepadMapping[this.player.mapping.START] = Button.MENU; + gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY; + gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM; + gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER; + gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY; + gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE; + gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT; + gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP; + gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN; + + return gamepadMapping; + } + + gamepadButtonDown(pad, button, value): void { + const actionMapping = this.getActionGamepadMapping(); + const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; + if (buttonDown !== undefined) { + this.events.emit('input_down', { + controller_type: 'gamepad', + button: buttonDown, + }); + this.setLastProcessedMovementTime(buttonDown); + } + } + + gamepadButtonUp(pad, button, value): void { + const actionMapping = this.getActionGamepadMapping(); + const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; + if (buttonUp !== undefined) { + this.events.emit('input_up', { + controller_type: 'gamepad', + button: buttonUp, + }); + this.delLastProcessedMovementTime(buttonUp); + } + } + + setupKeyboardControls(): void { + const keyCodes = Phaser.Input.Keyboard.KeyCodes; + const keyConfig = { + [Button.UP]: [keyCodes.UP, keyCodes.W], + [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], + [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], + [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], + [Button.SUBMIT]: [keyCodes.ENTER], + [Button.ACTION]: [keyCodes.SPACE, keyCodes.Z], + [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], + [Button.MENU]: [keyCodes.ESC, keyCodes.M], + [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], + [Button.CYCLE_SHINY]: [keyCodes.R], + [Button.CYCLE_FORM]: [keyCodes.F], + [Button.CYCLE_GENDER]: [keyCodes.G], + [Button.CYCLE_ABILITY]: [keyCodes.E], + [Button.CYCLE_NATURE]: [keyCodes.N], + [Button.CYCLE_VARIANT]: [keyCodes.V], + [Button.SPEED_UP]: [keyCodes.PLUS], + [Button.SLOW_DOWN]: [keyCodes.MINUS] + }; + const mobileKeyConfig = {}; + for (const b of Utils.getEnumValues(Button)) { + const keys: Phaser.Input.Keyboard.Key[] = []; + if (keyConfig.hasOwnProperty(b)) { + for (let k of keyConfig[b]) + keys.push(this.systems.input.keyboard.addKey(k, false)); + mobileKeyConfig[Button[b]] = keys[0]; + } + this.buttonKeys[b] = keys; + } + + initTouchControls(mobileKeyConfig); + this.listenInputKeyboard(); + } + + listenInputKeyboard(): void { + this.buttonKeys.forEach((row, index) => { + for (const key of row) { + key.on('down', () => { + this.events.emit('input_down', { + controller_type: 'keyboard', + button: index, + }); + this.setLastProcessedMovementTime(index); + }); + key.on('up', () => { + this.events.emit('input_up', { + controller_type: 'keyboard', + button: index, + }); + this.delLastProcessedMovementTime(index); + }); + } + }); + } + + mapGamepad(id) { + id = id.toLowerCase(); + let padConfig = pad_generic; + + if (id.includes('081f') && id.includes('e401')) { + padConfig = pad_unlicensedSNES; + } else if (id.includes('xbox') && id.includes('360')) { + padConfig = pad_xbox360; + } else if (id.includes('054c')) { + padConfig = pad_dualshock; + } + + return padConfig; + } + + /** + * repeatInputDurationJustPassed returns true if @param button has been held down long + * enough to fire a repeated input. A button must claim the buttonLock before + * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. + */ + repeatInputDurationJustPassed(button: Button): boolean { + if (this.buttonLock === null || this.buttonLock !== button) { + return false; + } + if (this.time.now - this.interactions[button].pressTime >= repeatInputDelayMillis) { + this.buttonLock = null; + return true; + } + } + + setLastProcessedMovementTime(button: Button): void { + if (!this.interactions.hasOwnProperty(button)) return; + this.buttonLock = button; + this.interactions[button].pressTime = this.time.now; + } + + delLastProcessedMovementTime(button: Button): void { + if (!this.interactions.hasOwnProperty(button)) return; + this.buttonLock = null; + this.interactions[button].pressTime = null; + } +} \ No newline at end of file diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts new file mode 100644 index 00000000000..bcdcc34b1fa --- /dev/null +++ b/src/ui-inputs.ts @@ -0,0 +1,159 @@ +import Phaser from "phaser"; +import UI, {Mode} from "./ui/ui"; +import {Button} from "#app/inputs-controller"; +import MessageUiHandler from "#app/ui/message-ui-handler"; +import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; +import {Setting, settingOptions} from "#app/system/settings"; +import SettingsUiHandler from "#app/ui/settings-ui-handler"; + + +export class UiInputs extends Phaser.Plugins.ScenePlugin { + private game: Phaser.Game; + private scene: Phaser.Scene; + private events; + + constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { + super(scene, pluginManager, pluginKey); + this.game = pluginManager.game; + this.scene = scene; + this.events = this.scene.inputController.events + } + + boot() { + this.listenInputs(); + } + + listenInputs(): void { + this.events.on('input_down', (event) => { + const actions = this.getActionsKeyDown(); + if (!actions.hasOwnProperty(event.button)) return; + const [inputSuccess, vibrationLength] = actions[event.button](); + if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength); + }, this); + + this.events.on('input_up', (event) => { + const actions = this.getActionsKeyUp(); + if (!actions.hasOwnProperty(event.button)) return; + const [inputSuccess, vibrationLength] = actions[event.button](); + if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength); + }, this); + } + + getActionsKeyDown() { + const actions = {}; + actions[Button.UP] = () => this.buttonDirection(Button.UP); + actions[Button.DOWN] = () => this.buttonDirection(Button.DOWN); + actions[Button.LEFT] = () => this.buttonDirection(Button.LEFT); + actions[Button.RIGHT] = () => this.buttonDirection(Button.RIGHT); + actions[Button.SUBMIT] = () => this.buttonTouch(); + actions[Button.ACTION] = () => this.buttonAb(Button.ACTION); + actions[Button.CANCEL] = () => this.buttonAb(Button.CANCEL); + actions[Button.MENU] = () => this.buttonMenu(); + actions[Button.STATS] = () => this.buttonStats(true); + actions[Button.CYCLE_SHINY] = () => this.buttonCycleOption(Button.CYCLE_SHINY); + actions[Button.CYCLE_FORM] = () => this.buttonCycleOption(Button.CYCLE_FORM); + actions[Button.CYCLE_GENDER] = () => this.buttonCycleOption(Button.CYCLE_GENDER); + actions[Button.CYCLE_ABILITY] = () => this.buttonCycleOption(Button.CYCLE_ABILITY); + actions[Button.CYCLE_NATURE] = () => this.buttonCycleOption(Button.CYCLE_NATURE); + actions[Button.CYCLE_VARIANT] = () => this.buttonCycleOption(Button.CYCLE_VARIANT); + actions[Button.SPEED_UP] = () => this.buttonSpeedChange(); + actions[Button.SLOW_DOWN] = () => this.buttonSpeedChange(false); + return actions; + } + + getActionsKeyUp() { + const actions = {}; + actions[Button.STATS] = () => this.buttonStats(false); + return actions; + } + + buttonDirection(direction): Array { + const inputSuccess = this.scene.ui.processInput(direction); + const vibrationLength = 5; + return [inputSuccess, vibrationLength]; + } + + buttonAb(button): Array { + const inputSuccess = this.scene.ui.processInput(button); + return [inputSuccess, 0]; + } + + buttonTouch(): Array { + const inputSuccess = this.scene.ui.processInput(Button.SUBMIT) || this.scene.ui.processInput(Button.ACTION); + return [inputSuccess, 0]; + } + + buttonStats(pressed = true): Array { + if (pressed) { + for (let p of this.scene.getField().filter(p => p?.isActive(true))) + p.toggleStats(true); + } else { + for (let p of this.scene.getField().filter(p => p?.isActive(true))) + p.toggleStats(false); + } + return [true, 0]; + } + + buttonMenu(): Array { + let inputSuccess; + if (this.scene.disableMenu) + return [true, 0]; + switch (this.scene.ui?.getMode()) { + case Mode.MESSAGE: + if (!(this.scene.ui.getHandler() as MessageUiHandler).pendingPrompt) + return [true, 0]; + case Mode.TITLE: + case Mode.COMMAND: + case Mode.FIGHT: + case Mode.BALL: + case Mode.TARGET_SELECT: + case Mode.SAVE_SLOT: + case Mode.PARTY: + case Mode.SUMMARY: + case Mode.STARTER_SELECT: + case Mode.CONFIRM: + case Mode.OPTION_SELECT: + this.scene.ui.setOverlayMode(Mode.MENU); + inputSuccess = true; + break; + case Mode.MENU: + case Mode.SETTINGS: + case Mode.ACHIEVEMENTS: + this.scene.ui.revertMode(); + this.scene.playSound('select'); + inputSuccess = true; + break; + default: + return [true, 0]; + } + return [inputSuccess, 0]; + } + + buttonCycleOption(button): Array { + let inputSuccess; + if (this.scene.ui?.getHandler() instanceof StarterSelectUiHandler) { + inputSuccess = this.scene.ui.processInput(button); + } + return [inputSuccess, 0]; + } + + buttonSpeedChange(up = true): Array { + if (up) { + if (this.scene.gameSpeed < 5) { + this.scene.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) + 1); + if (this.scene.ui?.getMode() === Mode.SETTINGS) + (this.scene.ui.getHandler() as SettingsUiHandler).show([]); + } + return [0, 0]; + } + if (this.scene.gameSpeed > 1) { + this.scene.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) - 1, 0)); + if (this.scene.ui?.getMode() === Mode.SETTINGS) + (this.scene.ui.getHandler() as SettingsUiHandler).show([]); + } + return [0, 0]; + } + +} \ No newline at end of file diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index 2f2c4face89..ac2dca03ed3 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -1,10 +1,11 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { argbFromRgba } from "@material/material-color-utilities"; +import {Button} from "#app/inputs-controller"; export interface OptionSelectConfig { xOffset?: number; diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index cadda64e032..778a5d5f131 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -1,9 +1,10 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Achv, achvs } from "../system/achv"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class AchvsUiHandler extends MessageUiHandler { private achvsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index e8cc979e423..5d5f0b7a094 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; +import {Button} from "#app/inputs-controller"; export default abstract class AwaitableUiHandler extends UiHandler { protected awaitingActionInput: boolean; diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index f2ebdc342a4..a4ee6c99d46 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -1,11 +1,12 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { getPokeballName } from "../data/pokeball"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 5e2cb56518f..7bba9657cd9 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -6,6 +6,7 @@ import MessageUiHandler from "./message-ui-handler"; import { getStatName, Stat } from "../data/pokemon-stat"; import { addWindow } from "./ui-theme"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; +import {Button} from "#app/inputs-controller"; export default class BattleMessageUiHandler extends MessageUiHandler { private levelUpStatsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index b8223694b4c..4c49246ebb6 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -1,10 +1,11 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import PartyUiHandler, { PartyUiMode } from "./party-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export enum Command { FIGHT = 0, diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index d9e7726d826..600a84e614d 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import AbstractOptionSelectUiHandler, { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { private switchCheck: boolean; diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index f0e32dbc2e9..0f8b999ba59 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import { TextStyle, addTextObject, getEggTierTextTint } from "./text"; import MessageUiHandler from "./message-ui-handler"; @@ -9,6 +9,7 @@ import { getPokemonSpecies } from "../data/pokemon-species"; import { addWindow } from "./ui-theme"; import { Tutorial, handleTutorial } from "../tutorial"; import { EggTier } from "../data/enums/egg-type"; +import {Button} from "#app/inputs-controller"; const defaultText = 'Select a machine.'; diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index f841bafc268..fefd5197be2 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -1,7 +1,8 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { EggHatchPhase } from "../egg-hatch-phase"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; +import {Button} from "#app/inputs-controller"; export default class EggHatchSceneHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts index 7537b8deeb0..8271ee00788 100644 --- a/src/ui/egg-list-ui-handler.ts +++ b/src/ui/egg-list-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; import { TextStyle, addTextObject } from "./text"; @@ -6,6 +6,7 @@ import MessageUiHandler from "./message-ui-handler"; import { EGG_SEED, Egg, GachaType, getEggGachaTypeDescriptor, getEggHatchWavesMessage, getEggDescriptor } from "../data/egg"; import * as Utils from "../utils"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class EggListUiHandler extends MessageUiHandler { private eggListContainer: Phaser.GameObjects.Container; diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index 7e0ef063ea0..21b39b593cf 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -1,7 +1,8 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default class EvolutionSceneHandler extends MessageUiHandler { public evolutionContainer: Phaser.GameObjects.Container; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 1a7a8bef597..b35292ebd45 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import { Type } from "../data/type"; import { Command } from "./command-ui-handler"; @@ -8,6 +8,7 @@ import * as Utils from "../utils"; import { CommandPhase } from "../phases"; import { MoveCategory } from "#app/data/move.js"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export default class FightUiHandler extends UiHandler { private movesContainer: Phaser.GameObjects.Container; diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index ec5f4147c58..4830bd191f9 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; import { Mode } from "./ui"; import { TextStyle, addTextInputObject, addTextObject } from "./text"; @@ -6,6 +6,7 @@ import { WindowVariant, addWindow } from "./ui-theme"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; import * as Utils from "../utils"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export interface FormModalConfig extends ModalConfig { errorMessage?: string; diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 00e358ff8e4..5b271159f4a 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject, getTextColor } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; @@ -6,6 +6,7 @@ import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { DexAttr, GameData } from "../system/game-data"; import { speciesStarters } from "../data/pokemon-species"; +import {Button} from "#app/inputs-controller"; interface DisplayStat { label?: string; diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 03d93699e75..7ce5302aa0e 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button, bypassLogin } from "../battle-scene"; +import BattleScene, { bypassLogin } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -9,6 +9,7 @@ import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui import { Tutorial, handleTutorial } from "../tutorial"; import { updateUserInfo } from "../account"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export enum MenuOptions { GAME_SETTINGS, diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index f193a3db54f..507e3292fb9 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -1,8 +1,9 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { WindowVariant, addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export interface ModalConfig { buttonActions: Function[]; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index e5252e02a8f..7597503d645 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption } from "../modifier/modifier-type"; import { getPokeballAtlasKey, PokeballType } from "../data/pokeball"; import { addTextObject, getModifierTierTextTint, getTextColor, TextStyle } from "./text"; @@ -6,6 +6,7 @@ import AwaitableUiHandler from "./awaitable-ui-handler"; import { Mode } from "./ui"; import { LockModifierTiersModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { handleTutorial, Tutorial } from "../tutorial"; +import {Button} from "#app/inputs-controller"; export const SHOP_OPTIONS_ROW_LIMIT = 6; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 35014fa7027..29b0bb85011 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,5 +1,5 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; @@ -16,6 +16,7 @@ import { pokemonEvolutions } from "../data/pokemon-evolutions"; import { addWindow } from "./ui-theme"; import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms"; import { getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; const defaultMessage = 'Choose a Pokémon.'; diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 181b0643cb9..07a9283f7e8 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { gameModes } from "../game-mode"; import { SessionSaveData } from "../system/game-data"; import { TextStyle, addTextObject } from "./text"; @@ -8,6 +8,7 @@ import * as Utils from "../utils"; import PokemonData from "../system/pokemon-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import MessageUiHandler from "./message-ui-handler"; +import {Button} from "#app/inputs-controller"; const sessionSlotCount = 5; diff --git a/src/ui/settings-ui-handler.ts b/src/ui/settings-ui-handler.ts index 8f43b377d21..6b1b7467d67 100644 --- a/src/ui/settings-ui-handler.ts +++ b/src/ui/settings-ui-handler.ts @@ -1,10 +1,11 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Setting, reloadSettings, settingDefaults, settingOptions } from "../system/settings"; import { hasTouchscreen, isMobile } from "../touch-controls"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class SettingsUiHandler extends UiHandler { private settingsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index f1e058b12cf..ad3e51d24a2 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button, starterColors } from "../battle-scene"; +import BattleScene, { starterColors } from "../battle-scene"; import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { Species } from "../data/enums/species"; import { TextStyle, addBBCodeTextObject, addTextObject } from "./text"; @@ -27,6 +27,7 @@ import { argbFromRgba } from "@material/material-color-utilities"; import { OptionSelectItem } from "./abstact-option-select-ui-handler"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; export type StarterSelectCallback = (starters: Starter[]) => void; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index cf5eb3639fd..4b014b83778 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; @@ -17,6 +17,7 @@ import { Nature, getNatureStatMultiplier } from "../data/nature"; import { loggedInUser } from "../account"; import { PlayerGender } from "../system/game-data"; import { Variant, getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; enum Page { PROFILE, diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index f8a7c9d28a3..b5242e713d7 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -1,10 +1,11 @@ import { BattlerIndex } from "../battle"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Moves } from "../data/enums/moves"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; import { getMoveTargets } from "../data/move"; +import {Button} from "#app/inputs-controller"; export type TargetSelectCallback = (cursor: integer) => void; diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index e3c94b76467..20f34a33388 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, getTextColor } from "./text"; import UI, { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default abstract class UiHandler { protected scene: BattleScene; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 6e20b2cb8b8..0555c54193d 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -1,4 +1,4 @@ -import { Button, default as BattleScene } from '../battle-scene'; +import { default as BattleScene } from '../battle-scene'; import UiHandler from './ui-handler'; import BattleMessageUiHandler from './battle-message-ui-handler'; import CommandUiHandler from './command-ui-handler'; @@ -35,6 +35,7 @@ import SavingIconHandler from './saving-icon-handler'; import UnavailableModalUiHandler from './unavailable-modal-ui-handler'; import OutdatedModalUiHandler from './outdated-modal-ui-handler'; import SessionReloadModalUiHandler from './session-reload-modal-ui-handler'; +import {Button} from "#app/inputs-controller"; export enum Mode { MESSAGE, diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 3f41cf9ae74..36926c6fa71 100644 --- a/src/ui/vouchers-ui-handler.ts +++ b/src/ui/vouchers-ui-handler.ts @@ -1,9 +1,10 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; const itemRows = 4; const itemCols = 17;