diff --git a/src/configs/gamepad-utils.ts b/src/configs/gamepad-utils.ts index df31ed827..946db4d4e 100644 --- a/src/configs/gamepad-utils.ts +++ b/src/configs/gamepad-utils.ts @@ -1,5 +1,6 @@ import {GamepadConfig} from "../inputs-controller"; import {SettingGamepad} from "#app/system/settings-gamepad"; +import {Button} from "#app/enums/buttons"; export function getKeyForButtonIndex(config: GamepadConfig, index: number): String { @@ -21,6 +22,25 @@ export function getIconForCustomIndex(config: GamepadConfig, index: number): Str return config.icons[key]; } +export function getKeyForRebindedAction(config: GamepadConfig, action: Button): String { + for (const key of Object.keys(config.default)) { + if (config.default[key] === action) return key; + } + return null; +} + +export function getKeyForRebindedSettingName(config: GamepadConfig, settingName: SettingGamepad): String { + const oldKey = getKeyForSettingName(config, settingName) + const action = config.custom[oldKey]; + return getKeyForRebindedAction(config, action); +} + +export function getIconForRebindedKey(config: GamepadConfig, _key): String { + const action = config.custom[_key]; + const key = getKeyForRebindedAction(config, action); + return config.icons[key]; +} + export function getKeyForSettingName(config: GamepadConfig, settingName: SettingGamepad) { for (const key of Object.keys(config.setting)) { const name = config.setting[key]; diff --git a/src/configs/pad_xbox360.ts b/src/configs/pad_xbox360.ts index 28c379041..189c2a349 100644 --- a/src/configs/pad_xbox360.ts +++ b/src/configs/pad_xbox360.ts @@ -58,12 +58,12 @@ const pad_xbox360 = { RS: SettingGamepad.Button_Slow_Down, }, default: { - RC_S: Button.ACTION, + RC_S: Button.ACTION, //5 RC_E: Button.CANCEL, RC_W: Button.CYCLE_NATURE, - RC_N: Button.CYCLE_VARIANT, - START: Button.MENU, - SELECT: Button.STATS, + RC_N: Button.CYCLE_VARIANT, //14 + START: Button.MENU, //7 + SELECT: Button.STATS, //8 LB: Button.CYCLE_FORM, RB: Button.CYCLE_SHINY, LT: Button.CYCLE_GENDER, diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index f4e0e8056..f56f3e77f 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -10,8 +10,8 @@ import SettingsGamepadUiHandler from "./ui/settings-gamepad-ui-handler"; import {SettingGamepad} from "./system/settings-gamepad"; import { getButtonIndexForKey, - getIconForCustomIndex, - getKeyForButtonIndex, + getIconForCustomIndex, getIconForRebindedKey, + getKeyForButtonIndex, getKeyForRebindedSettingName, getKeyForSettingName } from "./configs/gamepad-utils"; @@ -27,7 +27,7 @@ export interface SettingMapping { [key: string]: string; } -export interface DefaultMapping { +export interface MappingLayout { [key: string]: Button; } @@ -37,8 +37,8 @@ export interface GamepadConfig { gamepadMapping: GamepadMapping; icons: IconsMapping; setting: SettingMapping; - default: DefaultMapping; - custom: DefaultMapping; + default: MappingLayout; + custom: MappingLayout; } export interface ActionGamepadMapping { @@ -86,6 +86,8 @@ export class InputsController { public chosenGamepad: String; private disconnectedGamepads: Array = new Array(); + private pauseUpdate: boolean = false; + /** * Initializes a new instance of the game control system, setting up initial state and configurations. * @@ -218,7 +220,8 @@ export class InputsController { // Prevents repeating button interactions when gamepad support is disabled. if ( (!this.gamepadSupport && this.interactions[b].source === 'gamepad') || - (this.interactions[b].sourceName && this.interactions[b].sourceName !== this.chosenGamepad) + (this.interactions[b].sourceName && this.interactions[b].sourceName !== this.chosenGamepad) || + this.pauseUpdate ) { // Deletes the last interaction for a button if gamepad is disabled. this.delLastProcessedMovementTime(b as Button); @@ -304,8 +307,8 @@ export class InputsController { // for each gamepad, we set its mapping in this.configs const gamepadID = gamepad.toLowerCase(); const config = this.getConfig(gamepadID); + config.custom = this.configs[gamepad]?.custom || config.default; this.configs[gamepad] = config; - this.configs[gamepad].custom = {...config.default}; } if (this.chosenGamepad === thisGamepad.id) this.initChosenGamepad(this.chosenGamepad) } @@ -583,6 +586,7 @@ export class InputsController { * This method is typically called when needing to ensure that all inputs are neutralized. */ deactivatePressedKey(): void { + this.pauseUpdate = true; this.releaseButtonLock(this.buttonLock); this.releaseButtonLock(this.buttonLock2); for (const b of Utils.getEnumValues(Button)) { @@ -593,6 +597,7 @@ export class InputsController { this.interactions[b].sourceName = null; } } + setTimeout(() => this.pauseUpdate = false, 500); } /** @@ -643,12 +648,9 @@ export class InputsController { else if (this.buttonLock2 === button) this.buttonLock2 = null; } - setBind(setting: SettingGamepad, button: Button) { - console.log('button,', button); - } - getActiveConfig() :GamepadConfig { - return this.configs[this.chosenGamepad] || pad_generic; + if (this.configs[this.chosenGamepad]?.padID) return this.configs[this.chosenGamepad] + return pad_generic as GamepadConfig; } getPressedButtonLabel(button: Phaser.Input.Gamepad.Button) { @@ -657,17 +659,23 @@ export class InputsController { getCurrentButtonLabel(target: SettingGamepad) { const key = getKeyForSettingName(this.configs[this.chosenGamepad], target); - const id = getButtonIndexForKey(this.configs[this.chosenGamepad], key); - return getIconForCustomIndex(this.configs[this.chosenGamepad], id); + return getIconForRebindedKey(this.configs[this.chosenGamepad], key); } swapBinding(target, newBinding) { - this.deactivatePressedKey(); - const keyTarget = getKeyForSettingName(this.configs[this.chosenGamepad], target); + this.pauseUpdate = true; + const keyTarget = getKeyForRebindedSettingName(this.configs[this.chosenGamepad], target) const keyNewBinding = getKeyForButtonIndex(this.configs[this.chosenGamepad], newBinding); const previousActionForThisNewBinding = this.configs[this.chosenGamepad].custom[keyNewBinding]; const ActionForThisNewBinding = this.configs[this.chosenGamepad].custom[keyTarget]; this.configs[this.chosenGamepad].custom[keyTarget] = previousActionForThisNewBinding; this.configs[this.chosenGamepad].custom[keyNewBinding] = ActionForThisNewBinding; + this.scene.gameData.saveCustomMapping(this.chosenGamepad, this.configs[this.chosenGamepad].custom); + setTimeout(() => this.pauseUpdate = false, 500); + } + + loadConfig(gamepadName: String, customMappings: MappingLayout): void { + if (!this.configs[gamepadName]) this.configs[gamepadName] = {}; + this.configs[gamepadName].custom = customMappings; } } \ No newline at end of file diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 37f506ad3..a131cd318 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -30,6 +30,7 @@ import { TrainerVariant } from "../field/trainer"; import { OutdatedPhase, ReloadSessionPhase } from "#app/phases"; import { Variant, variantData } from "#app/data/variant"; import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings-gamepad"; +import {MappingLayout} from "#app/inputs-controller"; const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary @@ -227,6 +228,7 @@ export class GameData { this.scene = scene; this.loadSettings(); this.loadGamepadSettings(); + this.loadCustomMapping(); this.trainerId = Utils.randInt(65536); this.secretId = Utils.randInt(65536); this.starterData = {}; @@ -482,6 +484,25 @@ export class GameData { return true; } + public saveCustomMapping(gamepadName: string, mapping: MappingLayout): boolean { + let customMappings: object = {}; + if (localStorage.hasOwnProperty('customMapping')) + customMappings = JSON.parse(localStorage.getItem('customMapping')); + customMappings[gamepadName] = mapping; + localStorage.setItem('customMapping', JSON.stringify(customMappings)); + return true; + } + + public loadCustomMapping(): boolean { + console.log('loadCustomMapping'); + if (!localStorage.hasOwnProperty('customMapping')) + return false; + const customMappings = JSON.parse(localStorage.getItem('customMapping')); + for (const key of Object.keys(customMappings)) + this.scene.inputController.loadConfig(key, customMappings[key]); + + } + public saveGamepadSetting(setting: SettingGamepad, valueIndex: integer): boolean { let settingsGamepad: object = {}; if (localStorage.hasOwnProperty('settingsGamepad')) diff --git a/src/system/settings-gamepad.ts b/src/system/settings-gamepad.ts index 9d987e3df..8b5f28e87 100644 --- a/src/system/settings-gamepad.ts +++ b/src/system/settings-gamepad.ts @@ -121,6 +121,7 @@ export function setSettingGamepad(scene: BattleScene, setting: SettingGamepad, v const cancelHandler = () => { scene.ui.revertMode(); (scene.ui.getHandler() as SettingsGamepadUiHandler).setOptionCursor(Object.values(SettingGamepad).indexOf(SettingGamepad.Default_Controller), 0, true); + (scene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings(); return false; }; const changeGamepadHandler = (gamepad: string) => { diff --git a/src/ui/settings-gamepad-ui-handler.ts b/src/ui/settings-gamepad-ui-handler.ts index b0be6b5b2..2dad71523 100644 --- a/src/ui/settings-gamepad-ui-handler.ts +++ b/src/ui/settings-gamepad-ui-handler.ts @@ -12,7 +12,7 @@ import { settingGamepadOptions } from "../system/settings-gamepad"; import {truncateString} from "../utils"; -import {getKeyForSettingName} from "#app/configs/gamepad-utils"; +import {getIconForRebindedKey, getKeyForSettingName} from "#app/configs/gamepad-utils"; export default class SettingsGamepadUiHandler extends UiHandler { private settingsContainer: Phaser.GameObjects.Container; @@ -89,11 +89,9 @@ export default class SettingsGamepadUiHandler extends UiHandler { continue; } const key = getKeyForSettingName(this.scene.inputController.getActiveConfig(), SettingGamepad[setting]); - const frame = this.scene.inputController.getActiveConfig().icons[key]; const icon = this.scene.add.sprite(0, 0, 'xbox'); icon.setScale(0.1); icon.setOrigin(0, 0); - icon.setFrame(frame); this.inputsIcons[key] = icon; this.optionsContainer.add(icon); valueLabels.push(icon); @@ -140,13 +138,17 @@ export default class SettingsGamepadUiHandler extends UiHandler { } updateBindings(): void { - // for (const elm of noOptionsCursors) { - // console.log('elm:', elm); - // } + const activeConfig = this.scene.inputController.getActiveConfig(); + for (const elm of noOptionsCursors) { + const key = getKeyForSettingName(activeConfig, elm); + const icon = getIconForRebindedKey(activeConfig, key); + this.inputsIcons[key].setFrame(icon); + } } show(args: any[]): boolean { super.show(args); + this.updateBindings(); const settings: object = localStorage.hasOwnProperty('settingsGamepad') ? JSON.parse(localStorage.getItem('settingsGamepad')) : {}; // in the menu, for each line, we set the cursor position for each option, either on the previously selected, or the default value.