From d98f7733d4103db3bd0d0bcf4a5d4be578aaf77a Mon Sep 17 00:00:00 2001 From: Greenlamp2 <44787002+Greenlamp2@users.noreply.github.com> Date: Sun, 5 May 2024 16:30:00 +0200 Subject: [PATCH] Rework - Inputs management to include all gamepad mapping V2 (#429) * 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 ? * tab -> spaces final (maybe) * tried to fix the plugin loading issue on prod * remove Plugins things as it's too uncertain how it works on prod * seems old code source is indented with tab * cleanup * cleanup * cleanup * putting in an enum file the enum buttons * fix repeating stats button + change message in event when the key is repeating * added return type for ui-inputs * added return type for inputs-controller * adapted the code to integrate changes of bennybroseph --- src/battle-scene.ts | 283 +-------------------- 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/enums/buttons.ts | 19 ++ src/inputs-controller.ts | 255 +++++++++++++++++++ src/system/settings.ts | 2 +- src/ui-inputs.ts | 154 +++++++++++ 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 +- 35 files changed, 599 insertions(+), 299 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/enums/buttons.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 46f7b4ae0..504fa1af1 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; @@ -124,7 +106,8 @@ export default class BattleScene extends SceneBase { public gamepadSupport: boolean = true; public enableTouchControls: boolean = false; public enableVibration: boolean = false; - + public abSwapped: boolean = false; + public disableMenu: boolean = false; public gameData: GameData; @@ -189,34 +172,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 = ''; @@ -235,15 +190,6 @@ export default class BattleScene extends SceneBase { this.nextCommandPhaseQueue = []; } - /** - * Conditionally swaps the ACTION and CANCEL button - * @param standard When true, uses the default values - */ - setGamepadConfirm(standard: boolean) { - this.gamepadKeyConfig[Button.ACTION] = standard ? 0 : 1; - this.gamepadKeyConfig[Button.CANCEL] = standard ? 1 : 0; - } - loadPokemonAtlas(key: string, atlasPath: string, experimental?: boolean) { if (experimental === undefined) experimental = this.experimentalSprites; @@ -269,7 +215,7 @@ export default class BattleScene extends SceneBase { return ret; }; } - + populateAnims(); await this.initVariantData(); @@ -277,13 +223,13 @@ export default class BattleScene extends SceneBase { create() { initGameSpeed.apply(this); + this.inputController = new InputsController(this); + this.uiInputs = new UiInputs(this, this.inputController); this.gameData = new GameData(this); addUiThemeOverrides(this); - this.setupControls(); - this.load.setBaseURL(); this.spritePipeline = new SpritePipeline(this.game); @@ -296,7 +242,7 @@ export default class BattleScene extends SceneBase { } update() { - this.checkInput(); + this.inputController.update(); this.ui?.update(); } @@ -615,42 +561,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; } @@ -1352,177 +1262,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 000000000..4f66ff8c0 --- /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 000000000..19b5d3df1 --- /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 000000000..ba8ee538d --- /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 000000000..e44ebb54b --- /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/enums/buttons.ts b/src/enums/buttons.ts new file mode 100644 index 000000000..034c5a2af --- /dev/null +++ b/src/enums/buttons.ts @@ -0,0 +1,19 @@ +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 +} diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts new file mode 100644 index 000000000..a68fcd805 --- /dev/null +++ b/src/inputs-controller.ts @@ -0,0 +1,255 @@ +import Phaser, {Time} from "phaser"; +import * as Utils from "./utils"; +import {initTouchControls} from './touch-controls'; +import pad_generic from "./configs/pad_generic"; +import pad_unlicensedSNES from "./configs/pad_unlicensedSNES"; +import pad_xbox360 from "./configs/pad_xbox360"; +import pad_dualshock from "./configs/pad_dualshock"; +import {Button} from "./enums/buttons"; + +export interface GamepadMapping { + [key: string]: number; +} + +export interface GamepadConfig { + padID: string; + padType: string; + gamepadMapping: GamepadMapping; +} + +export interface ActionGamepadMapping { + [key: string]: Button; +} + +const repeatInputDelayMillis = 250; + +export class InputsController { + 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; + private player: Map = new Map(); + + constructor(scene: Phaser.Scene) { + 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]; + delete this.interactions[Button.STATS]; + this.init(); + } + + init(): void { + this.events = new Phaser.Events.EventEmitter(); + + if (typeof this.scene.input.gamepad !== 'undefined') { + this.scene.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.scene.input.gamepad.refreshPads(); + if (this.scene.input.gamepad.total) { + this.refreshGamepads(); + for (const thisGamepad of this.gamepads) { + this.scene.input.gamepad.emit('connected', thisGamepad); + } + } + + this.scene.input.gamepad.on('down', this.gamepadButtonDown, this); + this.scene.input.gamepad.on('up', this.gamepadButtonUp, this); + } + + // Keyboard + this.setupKeyboardControls(); + } + + update(): void { + for (const b of Utils.getEnumValues(Button)) { + if (!this.interactions.hasOwnProperty(b)) continue; + if (this.repeatInputDurationJustPassed(b)) { + this.events.emit('input_down', { + controller_type: 'repeated', + button: b, + }); + this.setLastProcessedMovementTime(b); + } + } + } + + setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): 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.scene.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(): ActionGamepadMapping { + 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] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION; + gamepadMapping[this.player.mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : 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: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): 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: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): 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, this.scene.abSwapped ? keyCodes.X : keyCodes.Z], + [Button.CANCEL]: [keyCodes.BACKSPACE, this.scene.abSwapped ? keyCodes.Z : 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.scene.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: string): GamepadConfig { + id = id.toLowerCase(); + + if (id.includes('081f') && id.includes('e401')) { + return pad_unlicensedSNES; + } else if (id.includes('xbox') && id.includes('360')) { + return pad_xbox360; + } else if (id.includes('054c')) { + return pad_dualshock; + } + + return pad_generic; + } + + /** + * 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/system/settings.ts b/src/system/settings.ts index e5769dfcc..3805a35bb 100644 --- a/src/system/settings.ts +++ b/src/system/settings.ts @@ -152,7 +152,7 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer) scene.gamepadSupport = settingOptions[setting][value] !== 'Disabled'; break; case Setting.Swap_A_and_B: - scene.setGamepadConfirm(settingOptions[setting][value] !== 'Enabled'); + scene.abSwapped = settingOptions[setting][value] !== 'Disabled'; break; case Setting.Touch_Controls: scene.enableTouchControls = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen(); diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts new file mode 100644 index 000000000..38d8e7830 --- /dev/null +++ b/src/ui-inputs.ts @@ -0,0 +1,154 @@ +import Phaser from "phaser"; +import {Mode} from "./ui/ui"; +import {InputsController} from "./inputs-controller"; +import MessageUiHandler from "./ui/message-ui-handler"; +import StarterSelectUiHandler from "./ui/starter-select-ui-handler"; +import {Setting, settingOptions} from "./system/settings"; +import SettingsUiHandler from "./ui/settings-ui-handler"; +import {Button} from "./enums/buttons"; + +export interface ActionKeys { + [key in Button]: () => void; +} + +export class UiInputs { + private scene: Phaser.Scene; + private events: Phaser.Events; + private inputsController: InputsController; + + constructor(scene: Phaser.Scene, inputsController: InputsController) { + this.scene = scene; + this.inputsController = inputsController; + this.init(); + } + + init(): void { + this.events = this.inputsController.events; + this.listenInputs(); + } + + listenInputs(): void { + this.events.on('input_down', (event) => { + const actions = this.getActionsKeyDown(); + if (!actions.hasOwnProperty(event.button)) return; + actions[event.button](); + }, this); + + this.events.on('input_up', (event) => { + const actions = this.getActionsKeyUp(); + if (!actions.hasOwnProperty(event.button)) return; + actions[event.button](); + }, this); + } + + doVibration(inputSuccess: boolean, vibrationLength: number): void { + if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength); + } + + getActionsKeyDown(): ActionKeys { + 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(): ActionKeys { + const actions = {}; + actions[Button.STATS] = () => this.buttonStats(false); + return actions; + } + + buttonDirection(direction: Button): void { + const inputSuccess = this.scene.ui.processInput(direction); + const vibrationLength = 5; + this.doVibration(inputSuccess, vibrationLength); + } + + buttonAb(button: Button): void { + this.scene.ui.processInput(button); + } + + buttonTouch(): void { + this.scene.ui.processInput(Button.SUBMIT) || this.scene.ui.processInput(Button.ACTION); + } + + buttonStats(pressed: boolean = true): void { + 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); + } + } + + buttonMenu(): void { + if (this.scene.disableMenu) + return; + switch (this.scene.ui?.getMode()) { + case Mode.MESSAGE: + if (!(this.scene.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.scene.ui.setOverlayMode(Mode.MENU); + break; + case Mode.MENU: + case Mode.SETTINGS: + case Mode.ACHIEVEMENTS: + this.scene.ui.revertMode(); + this.scene.playSound('select'); + break; + default: + return + } + } + + buttonCycleOption(button: Button): void { + if (this.scene.ui?.getHandler() instanceof StarterSelectUiHandler) { + this.scene.ui.processInput(button); + } + } + + buttonSpeedChange(up = true): void { + 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; + } + 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([]); + } + } + +} \ 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 2f2c4face..ffc0cabc8 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 "../enums/buttons"; export interface OptionSelectConfig { xOffset?: number; diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index cadda64e0..561b09171 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 "../enums/buttons"; 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 e8cc979e4..532ca1115 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 "../enums/buttons"; 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 f2ebdc342..06729151d 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 "../enums/buttons"; 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 5e2cb5651..d04a98ea8 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 "../enums/buttons"; 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 b8223694b..a27053015 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 "../enums/buttons"; export enum Command { FIGHT = 0, diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index a220b6f3a..bac980db9 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,7 +1,8 @@ -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 i18next from "i18next"; +import {Button} from "../enums/buttons"; 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 f0e32dbc2..315dfdbd3 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 "../enums/buttons"; const defaultText = 'Select a machine.'; diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index f841bafc2..ea8df429c 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 "../enums/buttons"; 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 7537b8dee..edeac7d71 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 "../enums/buttons"; 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 7e0ef063e..3361e9038 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 "../enums/buttons"; 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 1a7a8bef5..ee7e413db 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 "../enums/buttons"; 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 ec5f4147c..b2c2c1181 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 "../enums/buttons"; 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 00e358ff8..0b97d322e 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 "../enums/buttons"; interface DisplayStat { label?: string; diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 03d93699e..bf0326676 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 "../enums/buttons"; export enum MenuOptions { GAME_SETTINGS, diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index f193a3db5..77a3c14bd 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 "../enums/buttons"; export interface ModalConfig { buttonActions: Function[]; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index e5252e02a..8af13d8f6 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 "../enums/buttons"; export const SHOP_OPTIONS_ROW_LIMIT = 6; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 35014fa70..8b497655a 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 "../enums/buttons"; 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 69ac94d99..a30e21c8f 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"; @@ -9,6 +9,7 @@ import PokemonData from "../system/pokemon-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import MessageUiHandler from "./message-ui-handler"; import i18next from "i18next"; +import {Button} from "../enums/buttons"; const sessionSlotCount = 5; diff --git a/src/ui/settings-ui-handler.ts b/src/ui/settings-ui-handler.ts index 8f43b377d..3ed83268e 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 "../enums/buttons"; 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 4cfef282c..f887fe69c 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"; @@ -28,6 +28,7 @@ import { OptionSelectItem } from "./abstact-option-select-ui-handler"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; import i18next from "i18next"; +import {Button} from "../enums/buttons"; export type StarterSelectCallback = (starters: Starter[]) => void; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index ee514665d..ac04d41be 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button, starterColors } from "../battle-scene"; +import BattleScene, { starterColors } from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; @@ -19,6 +19,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 "../enums/buttons"; enum Page { PROFILE, diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index f8a7c9d28..36588dc47 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 "../enums/buttons"; export type TargetSelectCallback = (cursor: integer) => void; diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index e3c94b764..7fdb85d94 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 "../enums/buttons"; export default abstract class UiHandler { protected scene: BattleScene; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 6e20b2cb8..09deb2bdd 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 "../enums/buttons"; export enum Mode { MESSAGE, diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 3f41cf9ae..e28e211ee 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 "../enums/buttons"; const itemRows = 4; const itemCols = 17;