mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-26 08:46:55 +00:00
Settings Refactor (#1771)
This commit is contained in:
parent
763d2bfeeb
commit
69da96d543
@ -1,5 +1,5 @@
|
|||||||
import {Button} from "#app/enums/buttons";
|
import {Button} from "#app/enums/buttons";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
|
|
||||||
const cfg_keyboard_qwerty = {
|
const cfg_keyboard_qwerty = {
|
||||||
padID: "default",
|
padID: "default",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "../../system/settings-gamepad";
|
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||||
import {Button} from "../../enums/buttons";
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "../../system/settings-gamepad";
|
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||||
import {Button} from "../../enums/buttons";
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "#app/system/settings-gamepad";
|
import {SettingGamepad} from "#app/system/settings/settings-gamepad.js";
|
||||||
import {Button} from "#app/enums/buttons";
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "../../system/settings-gamepad";
|
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||||
import {Button} from "../../enums/buttons";
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "../../system/settings-gamepad";
|
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||||
import {Button} from "#app/enums/buttons";
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,8 +19,8 @@ import {
|
|||||||
getIconForLatestInput, swap,
|
getIconForLatestInput, swap,
|
||||||
} from "#app/configs/inputs/configHandler";
|
} from "#app/configs/inputs/configHandler";
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
import {SettingGamepad} from "#app/system/settings-gamepad";
|
import {SettingGamepad} from "#app/system/settings/settings-gamepad.js";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
|
|
||||||
export interface DeviceMapping {
|
export interface DeviceMapping {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
|
@ -48,7 +48,7 @@ import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims
|
|||||||
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
|
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
|
||||||
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";
|
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";
|
||||||
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler";
|
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler";
|
||||||
import { Setting } from "./system/settings";
|
import { SettingKeys } from "./system/settings/settings";
|
||||||
import { Tutorial, handleTutorial } from "./tutorial";
|
import { Tutorial, handleTutorial } from "./tutorial";
|
||||||
import { TerrainType } from "./data/terrain";
|
import { TerrainType } from "./data/terrain";
|
||||||
import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select-ui-handler";
|
import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select-ui-handler";
|
||||||
@ -477,7 +477,7 @@ export class SelectGenderPhase extends Phase {
|
|||||||
label: i18next.t("menu:boy"),
|
label: i18next.t("menu:boy"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.scene.gameData.gender = PlayerGender.MALE;
|
this.scene.gameData.gender = PlayerGender.MALE;
|
||||||
this.scene.gameData.saveSetting(Setting.Player_Gender, 0);
|
this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 0);
|
||||||
this.scene.gameData.saveSystem().then(() => this.end());
|
this.scene.gameData.saveSystem().then(() => this.end());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -486,7 +486,7 @@ export class SelectGenderPhase extends Phase {
|
|||||||
label: i18next.t("menu:girl"),
|
label: i18next.t("menu:girl"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.scene.gameData.gender = PlayerGender.FEMALE;
|
this.scene.gameData.gender = PlayerGender.FEMALE;
|
||||||
this.scene.gameData.saveSetting(Setting.Player_Gender, 1);
|
this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 1);
|
||||||
this.scene.gameData.saveSystem().then(() => this.end());
|
this.scene.gameData.saveSystem().then(() => this.end());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import { GameModes, gameModes } from "../game-mode";
|
|||||||
import { BattleType } from "../battle";
|
import { BattleType } from "../battle";
|
||||||
import TrainerData from "./trainer-data";
|
import TrainerData from "./trainer-data";
|
||||||
import { trainerConfigs } from "../data/trainer-config";
|
import { trainerConfigs } from "../data/trainer-config";
|
||||||
import { Setting, setSetting, settingDefaults } from "./settings";
|
import { SettingKeys, resetSettings, setSetting } from "./settings/settings";
|
||||||
import { achvs } from "./achv";
|
import { achvs } from "./achv";
|
||||||
import EggData from "./egg-data";
|
import EggData from "./egg-data";
|
||||||
import { Egg } from "../data/egg";
|
import { Egg } from "../data/egg";
|
||||||
@ -30,9 +30,10 @@ import { allMoves } from "../data/move";
|
|||||||
import { TrainerVariant } from "../field/trainer";
|
import { TrainerVariant } from "../field/trainer";
|
||||||
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
|
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
|
||||||
import { Variant, variantData } from "#app/data/variant";
|
import { Variant, variantData } from "#app/data/variant";
|
||||||
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings-gamepad";
|
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad";
|
||||||
import {setSettingKeyboard, SettingKeyboard, settingKeyboardDefaults} from "#app/system/settings-keyboard";
|
import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js";
|
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js";
|
||||||
|
import { Device } from "#app/enums/devices.js";
|
||||||
|
|
||||||
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
||||||
|
|
||||||
@ -402,7 +403,7 @@ export class GameData {
|
|||||||
|
|
||||||
this.gender = systemData.gender;
|
this.gender = systemData.gender;
|
||||||
|
|
||||||
this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
|
this.saveSetting(SettingKeys.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
|
||||||
|
|
||||||
const initStarterData = !systemData.starterData;
|
const initStarterData = !systemData.starterData;
|
||||||
|
|
||||||
@ -568,19 +569,21 @@ export class GameData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public saveSetting(setting: Setting, valueIndex: integer): boolean {
|
/**
|
||||||
|
* Saves a setting to localStorage
|
||||||
|
* @param setting string ideally of SettingKeys
|
||||||
|
* @param valueIndex index of the setting's option
|
||||||
|
* @returns true
|
||||||
|
*/
|
||||||
|
public saveSetting(setting: string, valueIndex: integer): boolean {
|
||||||
let settings: object = {};
|
let settings: object = {};
|
||||||
if (localStorage.hasOwnProperty("settings")) {
|
if (localStorage.hasOwnProperty("settings")) {
|
||||||
settings = JSON.parse(localStorage.getItem("settings"));
|
settings = JSON.parse(localStorage.getItem("settings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
setSetting(this.scene, setting as Setting, valueIndex);
|
setSetting(this.scene, setting, valueIndex);
|
||||||
|
|
||||||
Object.keys(settingDefaults).forEach(s => {
|
settings[setting] = valueIndex;
|
||||||
if (s === setting) {
|
|
||||||
settings[s] = valueIndex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
localStorage.setItem("settings", JSON.stringify(settings));
|
localStorage.setItem("settings", JSON.stringify(settings));
|
||||||
|
|
||||||
@ -653,61 +656,36 @@ export class GameData {
|
|||||||
* to update the specified setting with the new value. Finally, it saves the updated settings back
|
* to update the specified setting with the new value. Finally, it saves the updated settings back
|
||||||
* to localStorage and returns `true` to indicate success.
|
* to localStorage and returns `true` to indicate success.
|
||||||
*/
|
*/
|
||||||
public saveGamepadSetting(setting: SettingGamepad, valueIndex: integer): boolean {
|
public saveControlSetting(device: Device, localStoragePropertyName: string, setting: SettingGamepad|SettingKeyboard, settingDefaults, valueIndex: integer): boolean {
|
||||||
let settingsGamepad: object = {}; // Initialize an empty object to hold the gamepad settings
|
let settingsControls: object = {}; // Initialize an empty object to hold the gamepad settings
|
||||||
|
|
||||||
if (localStorage.hasOwnProperty("settingsGamepad")) { // Check if 'settingsGamepad' exists in localStorage
|
if (localStorage.hasOwnProperty(localStoragePropertyName)) { // Check if 'settingsControls' exists in localStorage
|
||||||
settingsGamepad = JSON.parse(localStorage.getItem("settingsGamepad")); // Parse the existing 'settingsGamepad' from localStorage
|
settingsControls = JSON.parse(localStorage.getItem(localStoragePropertyName)); // Parse the existing 'settingsControls' from localStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device === Device.GAMEPAD) {
|
||||||
setSettingGamepad(this.scene, setting as SettingGamepad, valueIndex); // Set the gamepad setting in the current scene
|
setSettingGamepad(this.scene, setting as SettingGamepad, valueIndex); // Set the gamepad setting in the current scene
|
||||||
|
} else if (device === Device.KEYBOARD) {
|
||||||
|
setSettingKeyboard(this.scene, setting as SettingKeyboard, valueIndex); // Set the keyboard setting in the current scene
|
||||||
|
}
|
||||||
|
|
||||||
Object.keys(settingGamepadDefaults).forEach(s => { // Iterate over the default gamepad settings
|
Object.keys(settingDefaults).forEach(s => { // Iterate over the default gamepad settings
|
||||||
if (s === setting) {// If the current setting matches, update its value
|
if (s === setting) {// If the current setting matches, update its value
|
||||||
settingsGamepad[s] = valueIndex;
|
settingsControls[s] = valueIndex;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
localStorage.setItem("settingsGamepad", JSON.stringify(settingsGamepad)); // Save the updated gamepad settings back to localStorage
|
localStorage.setItem(localStoragePropertyName, JSON.stringify(settingsControls)); // Save the updated gamepad settings back to localStorage
|
||||||
|
|
||||||
return true; // Return true to indicate the operation was successful
|
return true; // Return true to indicate the operation was successful
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a keyboard setting to localStorage.
|
* Loads Settings from local storage if available
|
||||||
*
|
* @returns true if succesful, false if not
|
||||||
* @param setting - The keyboard setting to save.
|
|
||||||
* @param valueIndex - The index of the value to set for the keyboard setting.
|
|
||||||
* @returns `true` if the setting is successfully saved.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method initializes an empty object for keyboard settings if none exist in localStorage.
|
|
||||||
* It then updates the setting in the current scene and iterates over the default keyboard settings
|
|
||||||
* to update the specified setting with the new value. Finally, it saves the updated settings back
|
|
||||||
* to localStorage and returns `true` to indicate success.
|
|
||||||
*/
|
*/
|
||||||
public saveKeyboardSetting(setting: SettingKeyboard, valueIndex: integer): boolean {
|
|
||||||
let settingsKeyboard: object = {}; // Initialize an empty object to hold the keyboard settings
|
|
||||||
|
|
||||||
if (localStorage.hasOwnProperty("settingsKeyboard")) { // Check if 'settingsKeyboard' exists in localStorage
|
|
||||||
settingsKeyboard = JSON.parse(localStorage.getItem("settingsKeyboard")); // Parse the existing 'settingsKeyboard' from localStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
setSettingKeyboard(this.scene, setting as SettingKeyboard, valueIndex); // Set the keyboard setting in the current scene
|
|
||||||
|
|
||||||
Object.keys(settingKeyboardDefaults).forEach(s => { // Iterate over the default keyboard settings
|
|
||||||
if (s === setting) {// If the current setting matches, update its value
|
|
||||||
settingsKeyboard[s] = valueIndex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
localStorage.setItem("settingsKeyboard", JSON.stringify(settingsKeyboard)); // Save the updated keyboard settings back to localStorage
|
|
||||||
|
|
||||||
return true; // Return true to indicate the operation was successful
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadSettings(): boolean {
|
private loadSettings(): boolean {
|
||||||
Object.values(Setting).map(setting => setting as Setting).forEach(setting => setSetting(this.scene, setting, settingDefaults[setting]));
|
resetSettings(this.scene);
|
||||||
|
|
||||||
if (!localStorage.hasOwnProperty("settings")) {
|
if (!localStorage.hasOwnProperty("settings")) {
|
||||||
return false;
|
return false;
|
||||||
@ -716,7 +694,7 @@ export class GameData {
|
|||||||
const settings = JSON.parse(localStorage.getItem("settings"));
|
const settings = JSON.parse(localStorage.getItem("settings"));
|
||||||
|
|
||||||
for (const setting of Object.keys(settings)) {
|
for (const setting of Object.keys(settings)) {
|
||||||
setSetting(this.scene, setting as Setting, settings[setting]);
|
setSetting(this.scene, setting, settings[setting]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,279 +0,0 @@
|
|||||||
import { Mode } from "#app/ui/ui";
|
|
||||||
import i18next from "i18next";
|
|
||||||
import BattleScene from "../battle-scene";
|
|
||||||
import { hasTouchscreen } from "../touch-controls";
|
|
||||||
import { updateWindowType } from "../ui/ui-theme";
|
|
||||||
import { PlayerGender } from "./game-data";
|
|
||||||
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
|
||||||
import { MoneyFormat } from "../enums/money-format";
|
|
||||||
import SettingsUiHandler from "#app/ui/settings/settings-ui-handler";
|
|
||||||
|
|
||||||
export enum Setting {
|
|
||||||
Game_Speed = "GAME_SPEED",
|
|
||||||
Master_Volume = "MASTER_VOLUME",
|
|
||||||
BGM_Volume = "BGM_VOLUME",
|
|
||||||
SE_Volume = "SE_VOLUME",
|
|
||||||
Language = "LANGUAGE",
|
|
||||||
Damage_Numbers = "DAMAGE_NUMBERS",
|
|
||||||
UI_Theme = "UI_THEME",
|
|
||||||
Window_Type = "WINDOW_TYPE",
|
|
||||||
Tutorials = "TUTORIALS",
|
|
||||||
Enable_Retries = "ENABLE_RETRIES",
|
|
||||||
Skip_Seen_Dialogues = "SKIP_SEEN_DIALOGUES",
|
|
||||||
Candy_Upgrade_Notification = "CANDY_UPGRADE_NOTIFICATION",
|
|
||||||
Candy_Upgrade_Display = "CANDY_UPGRADE_DISPLAY",
|
|
||||||
Money_Format = "MONEY_FORMAT",
|
|
||||||
Sprite_Set = "SPRITE_SET",
|
|
||||||
Move_Animations = "MOVE_ANIMATIONS",
|
|
||||||
Show_Moveset_Flyout = "SHOW_MOVESET_FLYOUT",
|
|
||||||
Show_Stats_on_Level_Up = "SHOW_LEVEL_UP_STATS",
|
|
||||||
EXP_Gains_Speed = "EXP_GAINS_SPEED",
|
|
||||||
EXP_Party_Display = "EXP_PARTY_DISPLAY",
|
|
||||||
HP_Bar_Speed = "HP_BAR_SPEED",
|
|
||||||
Fusion_Palette_Swaps = "FUSION_PALETTE_SWAPS",
|
|
||||||
Player_Gender = "PLAYER_GENDER",
|
|
||||||
Touch_Controls = "TOUCH_CONTROLS",
|
|
||||||
Vibration = "VIBRATION"
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SettingOptions {
|
|
||||||
[key: string]: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SettingDefaults {
|
|
||||||
[key: string]: integer
|
|
||||||
}
|
|
||||||
|
|
||||||
export const settingOptions: SettingOptions = {
|
|
||||||
[Setting.Game_Speed]: ["1x", "1.25x", "1.5x", "2x", "2.5x", "3x", "4x", "5x"],
|
|
||||||
[Setting.Master_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : "Mute"),
|
|
||||||
[Setting.BGM_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : "Mute"),
|
|
||||||
[Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : "Mute"),
|
|
||||||
[Setting.Language]: ["English", "Change"],
|
|
||||||
[Setting.Damage_Numbers]: ["Off", "Simple", "Fancy"],
|
|
||||||
[Setting.UI_Theme]: ["Default", "Legacy"],
|
|
||||||
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
|
||||||
[Setting.Tutorials]: ["Off", "On"],
|
|
||||||
[Setting.Enable_Retries]: ["Off", "On"],
|
|
||||||
[Setting.Skip_Seen_Dialogues]: ["Off", "On"],
|
|
||||||
[Setting.Candy_Upgrade_Notification]: ["Off", "Passives Only", "On"],
|
|
||||||
[Setting.Candy_Upgrade_Display]: ["Icon", "Animation"],
|
|
||||||
[Setting.Money_Format]: ["Normal", "Abbreviated"],
|
|
||||||
[Setting.Sprite_Set]: ["Consistent", "Mixed Animated"],
|
|
||||||
[Setting.Move_Animations]: ["Off", "On"],
|
|
||||||
[Setting.Show_Moveset_Flyout]: ["Off", "On"],
|
|
||||||
[Setting.Show_Stats_on_Level_Up]: ["Off", "On"],
|
|
||||||
[Setting.EXP_Gains_Speed]: ["Normal", "Fast", "Faster", "Skip"],
|
|
||||||
[Setting.EXP_Party_Display]: ["Normal", "Level Up Notification", "Skip"],
|
|
||||||
[Setting.HP_Bar_Speed]: ["Normal", "Fast", "Faster", "Instant"],
|
|
||||||
[Setting.Fusion_Palette_Swaps]: ["Off", "On"],
|
|
||||||
[Setting.Player_Gender]: ["Boy", "Girl"],
|
|
||||||
[Setting.Touch_Controls]: ["Auto", "Disabled"],
|
|
||||||
[Setting.Vibration]: ["Auto", "Disabled"]
|
|
||||||
};
|
|
||||||
|
|
||||||
export const settingDefaults: SettingDefaults = {
|
|
||||||
[Setting.Game_Speed]: 3,
|
|
||||||
[Setting.Master_Volume]: 5,
|
|
||||||
[Setting.BGM_Volume]: 10,
|
|
||||||
[Setting.SE_Volume]: 10,
|
|
||||||
[Setting.Language]: 0,
|
|
||||||
[Setting.Damage_Numbers]: 0,
|
|
||||||
[Setting.UI_Theme]: 0,
|
|
||||||
[Setting.Window_Type]: 0,
|
|
||||||
[Setting.Tutorials]: 1,
|
|
||||||
[Setting.Enable_Retries]: 0,
|
|
||||||
[Setting.Skip_Seen_Dialogues]: 0,
|
|
||||||
[Setting.Candy_Upgrade_Notification]: 0,
|
|
||||||
[Setting.Candy_Upgrade_Display]: 0,
|
|
||||||
[Setting.Money_Format]: 0,
|
|
||||||
[Setting.Sprite_Set]: 0,
|
|
||||||
[Setting.Move_Animations]: 1,
|
|
||||||
[Setting.Show_Moveset_Flyout]: 1,
|
|
||||||
[Setting.Show_Stats_on_Level_Up]: 1,
|
|
||||||
[Setting.EXP_Gains_Speed]: 0,
|
|
||||||
[Setting.EXP_Party_Display]: 0,
|
|
||||||
[Setting.HP_Bar_Speed]: 0,
|
|
||||||
[Setting.Fusion_Palette_Swaps]: 1,
|
|
||||||
[Setting.Player_Gender]: 0,
|
|
||||||
[Setting.Touch_Controls]: 0,
|
|
||||||
[Setting.Vibration]: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set, Setting.Candy_Upgrade_Display];
|
|
||||||
|
|
||||||
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
|
|
||||||
switch (setting) {
|
|
||||||
case Setting.Game_Speed:
|
|
||||||
scene.gameSpeed = parseFloat(settingOptions[setting][value].replace("x", ""));
|
|
||||||
break;
|
|
||||||
case Setting.Master_Volume:
|
|
||||||
scene.masterVolume = value ? parseInt(settingOptions[setting][value]) * 0.01 : 0;
|
|
||||||
scene.updateSoundVolume();
|
|
||||||
break;
|
|
||||||
case Setting.BGM_Volume:
|
|
||||||
scene.bgmVolume = value ? parseInt(settingOptions[setting][value]) * 0.01 : 0;
|
|
||||||
scene.updateSoundVolume();
|
|
||||||
break;
|
|
||||||
case Setting.SE_Volume:
|
|
||||||
scene.seVolume = value ? parseInt(settingOptions[setting][value]) * 0.01 : 0;
|
|
||||||
scene.updateSoundVolume();
|
|
||||||
break;
|
|
||||||
case Setting.Damage_Numbers:
|
|
||||||
scene.damageNumbersMode = value;
|
|
||||||
break;
|
|
||||||
case Setting.UI_Theme:
|
|
||||||
scene.uiTheme = value;
|
|
||||||
break;
|
|
||||||
case Setting.Window_Type:
|
|
||||||
updateWindowType(scene, parseInt(settingOptions[setting][value]));
|
|
||||||
break;
|
|
||||||
case Setting.Tutorials:
|
|
||||||
scene.enableTutorials = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.Enable_Retries:
|
|
||||||
scene.enableRetries = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.Candy_Upgrade_Notification:
|
|
||||||
if (scene.candyUpgradeNotification === value) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.candyUpgradeNotification = value;
|
|
||||||
scene.eventTarget.dispatchEvent(new CandyUpgradeNotificationChangedEvent(value));
|
|
||||||
break;
|
|
||||||
case Setting.Candy_Upgrade_Display:
|
|
||||||
scene.candyUpgradeDisplay = value;
|
|
||||||
case Setting.Money_Format:
|
|
||||||
switch (settingOptions[setting][value]) {
|
|
||||||
case "Normal":
|
|
||||||
scene.moneyFormat = MoneyFormat.NORMAL;
|
|
||||||
break;
|
|
||||||
case "Abbreviated":
|
|
||||||
scene.moneyFormat = MoneyFormat.ABBREVIATED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
scene.updateMoneyText(false);
|
|
||||||
break;
|
|
||||||
case Setting.Sprite_Set:
|
|
||||||
scene.experimentalSprites = !!value;
|
|
||||||
if (value) {
|
|
||||||
scene.initExpSprites();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Setting.Move_Animations:
|
|
||||||
scene.moveAnimations = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.Show_Moveset_Flyout:
|
|
||||||
scene.showMovesetFlyout = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.Show_Stats_on_Level_Up:
|
|
||||||
scene.showLevelUpStats = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.EXP_Gains_Speed:
|
|
||||||
scene.expGainsSpeed = value;
|
|
||||||
break;
|
|
||||||
case Setting.EXP_Party_Display:
|
|
||||||
scene.expParty = value;
|
|
||||||
break;
|
|
||||||
case Setting.HP_Bar_Speed:
|
|
||||||
scene.hpBarSpeed = value;
|
|
||||||
break;
|
|
||||||
case Setting.Fusion_Palette_Swaps:
|
|
||||||
scene.fusionPaletteSwaps = !!value;
|
|
||||||
break;
|
|
||||||
case Setting.Player_Gender:
|
|
||||||
if (scene.gameData) {
|
|
||||||
const female = settingOptions[setting][value] === "Girl";
|
|
||||||
scene.gameData.gender = female ? PlayerGender.FEMALE : PlayerGender.MALE;
|
|
||||||
scene.trainer.setTexture(scene.trainer.texture.key.replace(female ? "m" : "f", female ? "f" : "m"));
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Setting.Touch_Controls:
|
|
||||||
scene.enableTouchControls = settingOptions[setting][value] !== "Disabled" && hasTouchscreen();
|
|
||||||
const touchControls = document.getElementById("touchControls");
|
|
||||||
if (touchControls) {
|
|
||||||
touchControls.classList.toggle("visible", scene.enableTouchControls);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Setting.Vibration:
|
|
||||||
scene.enableVibration = settingOptions[setting][value] !== "Disabled" && hasTouchscreen();
|
|
||||||
break;
|
|
||||||
case Setting.Skip_Seen_Dialogues:
|
|
||||||
scene.skipSeenDialogues = settingOptions[setting][value] === "On";
|
|
||||||
break;
|
|
||||||
case Setting.Language:
|
|
||||||
if (value) {
|
|
||||||
if (scene.ui) {
|
|
||||||
const cancelHandler = () => {
|
|
||||||
scene.ui.revertMode();
|
|
||||||
(scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(Object.values(Setting).indexOf(Setting.Language), 0, true);
|
|
||||||
};
|
|
||||||
const changeLocaleHandler = (locale: string): boolean => {
|
|
||||||
try {
|
|
||||||
i18next.changeLanguage(locale);
|
|
||||||
localStorage.setItem("prLang", locale);
|
|
||||||
cancelHandler();
|
|
||||||
// Reload the whole game to apply the new locale since also some constants are translated
|
|
||||||
window.location.reload();
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error changing locale:", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "English",
|
|
||||||
handler: () => changeLocaleHandler("en")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Español",
|
|
||||||
handler: () => changeLocaleHandler("es")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Italiano",
|
|
||||||
handler: () => changeLocaleHandler("it")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Français",
|
|
||||||
handler: () => changeLocaleHandler("fr")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Deutsch",
|
|
||||||
handler: () => changeLocaleHandler("de")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Português (BR)",
|
|
||||||
handler: () => changeLocaleHandler("pt_BR")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "简体中文",
|
|
||||||
handler: () => changeLocaleHandler("zh_CN")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "繁體中文",
|
|
||||||
handler: () => changeLocaleHandler("zh_TW")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "한국어",
|
|
||||||
handler: () => changeLocaleHandler("ko")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cancel",
|
|
||||||
handler: () => cancelHandler()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
maxOptions: 7
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,10 +1,9 @@
|
|||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import {SettingDefaults, SettingOptions} from "./settings";
|
import SettingsGamepadUiHandler from "../../ui/settings/settings-gamepad-ui-handler";
|
||||||
import SettingsGamepadUiHandler from "../ui/settings/settings-gamepad-ui-handler";
|
import {Mode} from "../../ui/ui";
|
||||||
import {Mode} from "../ui/ui";
|
import {truncateString} from "../../utils";
|
||||||
import {truncateString} from "../utils";
|
import {Button} from "../../enums/buttons";
|
||||||
import {Button} from "../enums/buttons";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
|
||||||
|
|
||||||
export enum SettingGamepad {
|
export enum SettingGamepad {
|
||||||
Controller = "CONTROLLER",
|
Controller = "CONTROLLER",
|
||||||
@ -28,29 +27,31 @@ export enum SettingGamepad {
|
|||||||
Button_Submit = "BUTTON_SUBMIT",
|
Button_Submit = "BUTTON_SUBMIT",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settingGamepadOptions: SettingOptions = {
|
const pressAction = "Press action to assign";
|
||||||
|
|
||||||
|
export const settingGamepadOptions = {
|
||||||
[SettingGamepad.Controller]: ["Default", "Change"],
|
[SettingGamepad.Controller]: ["Default", "Change"],
|
||||||
[SettingGamepad.Gamepad_Support]: ["Auto", "Disabled"],
|
[SettingGamepad.Gamepad_Support]: ["Auto", "Disabled"],
|
||||||
[SettingGamepad.Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Up]: [`KEY ${Button.UP.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Down]: [`KEY ${Button.DOWN.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Left]: [`KEY ${Button.LEFT.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Action]: [`KEY ${Button.ACTION.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Menu]: [`KEY ${Button.MENU.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Stats]: [`KEY ${Button.STATS.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, pressAction],
|
||||||
[SettingGamepad.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
[SettingGamepad.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, pressAction],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const settingGamepadDefaults: SettingDefaults = {
|
export const settingGamepadDefaults = {
|
||||||
[SettingGamepad.Controller]: 0,
|
[SettingGamepad.Controller]: 0,
|
||||||
[SettingGamepad.Gamepad_Support]: 0,
|
[SettingGamepad.Gamepad_Support]: 0,
|
||||||
[SettingGamepad.Button_Up]: 0,
|
[SettingGamepad.Button_Up]: 0,
|
@ -1,4 +1,3 @@
|
|||||||
import {SettingDefaults, SettingOptions} from "#app/system/settings";
|
|
||||||
import {Button} from "#app/enums/buttons";
|
import {Button} from "#app/enums/buttons";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import {Mode} from "#app/ui/ui";
|
import {Mode} from "#app/ui/ui";
|
||||||
@ -42,46 +41,47 @@ export enum SettingKeyboard {
|
|||||||
Alt_Button_Submit = "ALT_BUTTON_SUBMIT",
|
Alt_Button_Submit = "ALT_BUTTON_SUBMIT",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settingKeyboardOptions: SettingOptions = {
|
const pressAction = "Press action to assign";
|
||||||
// [SettingKeyboard.Default_Layout]: ['Default'],
|
|
||||||
[SettingKeyboard.Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Alt_Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
|
||||||
[SettingKeyboard.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
|
||||||
|
|
||||||
[SettingKeyboard.Alt_Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
export const settingKeyboardOptions = {
|
||||||
[SettingKeyboard.Alt_Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
// [SettingKeyboard.Default_Layout]: ['Default'],
|
||||||
[SettingKeyboard.Alt_Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Up]: [`KEY ${Button.UP.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Down]: [`KEY ${Button.DOWN.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Up]: [`KEY ${Button.UP.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Left]: [`KEY ${Button.LEFT.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Action]: [`KEY ${Button.ACTION.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Menu]: [`KEY ${Button.MENU.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Down]: [`KEY ${Button.DOWN.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Left]: [`KEY ${Button.LEFT.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Right]: [`KEY ${Button.RIGHT.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Action]: [`KEY ${Button.ACTION.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Menu]: [`KEY ${Button.MENU.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Stats]: [`KEY ${Button.STATS.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Stats]: [`KEY ${Button.STATS.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Alt_Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, pressAction],
|
||||||
[SettingKeyboard.Alt_Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
[SettingKeyboard.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, pressAction],
|
||||||
|
[SettingKeyboard.Alt_Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, pressAction],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const settingKeyboardDefaults: SettingDefaults = {
|
export const settingKeyboardDefaults = {
|
||||||
// [SettingKeyboard.Default_Layout]: 0,
|
// [SettingKeyboard.Default_Layout]: 0,
|
||||||
[SettingKeyboard.Button_Up]: 0,
|
[SettingKeyboard.Button_Up]: 0,
|
||||||
[SettingKeyboard.Button_Down]: 0,
|
[SettingKeyboard.Button_Down]: 0,
|
453
src/system/settings/settings.ts
Normal file
453
src/system/settings/settings.ts
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
import { Mode } from "#app/ui/ui";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import { hasTouchscreen } from "../../touch-controls";
|
||||||
|
import { updateWindowType } from "../../ui/ui-theme";
|
||||||
|
import { PlayerGender } from "../game-data";
|
||||||
|
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
||||||
|
import { MoneyFormat } from "../../enums/money-format";
|
||||||
|
import SettingsUiHandler from "#app/ui/settings/settings-ui-handler";
|
||||||
|
|
||||||
|
const MUTE = "Mute";
|
||||||
|
const VOLUME_OPTIONS = new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : MUTE);
|
||||||
|
const OFF_ON = ["Off", "On"];
|
||||||
|
const AUTO_DISABLED = ["Auto", "Disabled"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types for helping separate settings to different menus
|
||||||
|
*/
|
||||||
|
export enum SettingType {
|
||||||
|
GENERAL,
|
||||||
|
ACCESSIBILITY
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Setting {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
options: Array<string>
|
||||||
|
default: number
|
||||||
|
type: SettingType
|
||||||
|
requireReload?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting Keys for existing settings
|
||||||
|
* to be used when trying to find or update Settings
|
||||||
|
*/
|
||||||
|
export const SettingKeys = {
|
||||||
|
Game_Speed: "GAME_SPEED",
|
||||||
|
Master_Volume: "MASTER_VOLUME",
|
||||||
|
BGM_Volume: "BGM_VOLUME",
|
||||||
|
SE_Volume: "SE_VOLUME",
|
||||||
|
Language: "LANGUAGE",
|
||||||
|
Damage_Numbers: "DAMAGE_NUMBERS",
|
||||||
|
UI_Theme: "UI_THEME",
|
||||||
|
Window_Type: "WINDOW_TYPE",
|
||||||
|
Tutorials: "TUTORIALS",
|
||||||
|
Enable_Retries: "ENABLE_RETRIES",
|
||||||
|
Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES",
|
||||||
|
Candy_Upgrade_Notification: "CANDY_UPGRADE_NOTIFICATION",
|
||||||
|
Candy_Upgrade_Display: "CANDY_UPGRADE_DISPLAY",
|
||||||
|
Money_Format: "MONEY_FORMAT",
|
||||||
|
Sprite_Set: "SPRITE_SET",
|
||||||
|
Move_Animations: "MOVE_ANIMATIONS",
|
||||||
|
Show_Moveset_Flyout: "SHOW_MOVESET_FLYOUT",
|
||||||
|
Show_Stats_on_Level_Up: "SHOW_LEVEL_UP_STATS",
|
||||||
|
EXP_Gains_Speed: "EXP_GAINS_SPEED",
|
||||||
|
EXP_Party_Display: "EXP_PARTY_DISPLAY",
|
||||||
|
HP_Bar_Speed: "HP_BAR_SPEED",
|
||||||
|
Fusion_Palette_Swaps: "FUSION_PALETTE_SWAPS",
|
||||||
|
Player_Gender: "PLAYER_GENDER",
|
||||||
|
Touch_Controls: "TOUCH_CONTROLS",
|
||||||
|
Vibration: "VIBRATION"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All Settings not related to controls
|
||||||
|
*/
|
||||||
|
export const Setting: Array<Setting> = [
|
||||||
|
{
|
||||||
|
key: SettingKeys.Game_Speed,
|
||||||
|
label: "Game Speed",
|
||||||
|
options: ["1x", "1.25x", "1.5x", "2x", "2.5x", "3x", "4x", "5x"],
|
||||||
|
default: 3,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Master_Volume,
|
||||||
|
label: "Master Volume",
|
||||||
|
options: VOLUME_OPTIONS,
|
||||||
|
default: 5,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.BGM_Volume,
|
||||||
|
label: "BGM Volume",
|
||||||
|
options: VOLUME_OPTIONS,
|
||||||
|
default: 10,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.SE_Volume,
|
||||||
|
label: "SE Volume",
|
||||||
|
options: VOLUME_OPTIONS,
|
||||||
|
default: 10,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Language,
|
||||||
|
label: "Language",
|
||||||
|
options: ["English", "Change"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL,
|
||||||
|
requireReload: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Damage_Numbers,
|
||||||
|
label: "Damage Numbers",
|
||||||
|
options: ["Off", "Simple", "Fancy"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.UI_Theme,
|
||||||
|
label: "UI Theme",
|
||||||
|
options: ["Default", "Legacy"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL,
|
||||||
|
requireReload: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Window_Type,
|
||||||
|
label: "Window Type",
|
||||||
|
options: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Tutorials,
|
||||||
|
label: "Tutorials",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 1,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Enable_Retries,
|
||||||
|
label: "Enable Retries",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.ACCESSIBILITY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Skip_Seen_Dialogues,
|
||||||
|
label: "Skip Seen Dialogues",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Candy_Upgrade_Notification,
|
||||||
|
label: "Candy Upgrade Notification",
|
||||||
|
options: ["Off", "Passives Only", "On"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.ACCESSIBILITY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Candy_Upgrade_Display,
|
||||||
|
label: "Candy Upgrade Display",
|
||||||
|
options: ["Icon", "Animation"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.ACCESSIBILITY,
|
||||||
|
requireReload: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Money_Format,
|
||||||
|
label: "Money Format",
|
||||||
|
options: ["Normal", "Abbreviated"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.ACCESSIBILITY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Sprite_Set,
|
||||||
|
label: "Sprite Set",
|
||||||
|
options: ["Consistent", "Mixed Animated"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL,
|
||||||
|
requireReload: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Move_Animations,
|
||||||
|
label: "Move Animations",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 1,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Show_Moveset_Flyout,
|
||||||
|
label: "Show Moveset Flyout",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 1,
|
||||||
|
type: SettingType.ACCESSIBILITY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Show_Stats_on_Level_Up,
|
||||||
|
label: "Show Stats on Level Up",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 1,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.EXP_Gains_Speed,
|
||||||
|
label: "EXP Gains Speed",
|
||||||
|
options: ["Normal", "Fast", "Faster", "Skip"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.EXP_Party_Display,
|
||||||
|
label: "EXP Party Display",
|
||||||
|
options: ["Normal", "Level Up Notification", "Skip"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.HP_Bar_Speed,
|
||||||
|
label: "HP Bar Speed",
|
||||||
|
options: ["Normal", "Fast", "Faster", "Skip"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Fusion_Palette_Swaps,
|
||||||
|
label: "Fusion Palette Swaps",
|
||||||
|
options: OFF_ON,
|
||||||
|
default: 1,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Player_Gender,
|
||||||
|
label: "Player Gender",
|
||||||
|
options: ["Boy", "Girl"],
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Touch_Controls,
|
||||||
|
label: "Touch Controls",
|
||||||
|
options: AUTO_DISABLED,
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: SettingKeys.Vibration,
|
||||||
|
label: "Vibration",
|
||||||
|
options: AUTO_DISABLED,
|
||||||
|
default: 0,
|
||||||
|
type: SettingType.GENERAL
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of a Setting
|
||||||
|
* @param key SettingKey
|
||||||
|
* @returns index or -1 if doesn't exist
|
||||||
|
*/
|
||||||
|
export function settingIndex(key: string) {
|
||||||
|
return Setting.findIndex(s => s.key === key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all settings to their defaults
|
||||||
|
* @param scene current BattleScene
|
||||||
|
*/
|
||||||
|
export function resetSettings(scene: BattleScene) {
|
||||||
|
Setting.forEach(s => setSetting(scene, s.key, s.default));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a setting for current BattleScene
|
||||||
|
* @param scene current BattleScene
|
||||||
|
* @param setting string ideally from SettingKeys
|
||||||
|
* @param value value to update setting with
|
||||||
|
* @returns true if successful, false if not
|
||||||
|
*/
|
||||||
|
export function setSetting(scene: BattleScene, setting: string, value: integer): boolean {
|
||||||
|
const index: number = settingIndex(setting);
|
||||||
|
if ( index === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (Setting[index].key) {
|
||||||
|
case SettingKeys.Game_Speed:
|
||||||
|
scene.gameSpeed = parseFloat(Setting[index].options[value].replace("x", ""));
|
||||||
|
break;
|
||||||
|
case SettingKeys.Master_Volume:
|
||||||
|
scene.masterVolume = value ? parseInt(Setting[index].options[value]) * 0.01 : 0;
|
||||||
|
scene.updateSoundVolume();
|
||||||
|
break;
|
||||||
|
case SettingKeys.BGM_Volume:
|
||||||
|
scene.bgmVolume = value ? parseInt(Setting[index].options[value]) * 0.01 : 0;
|
||||||
|
scene.updateSoundVolume();
|
||||||
|
break;
|
||||||
|
case SettingKeys.SE_Volume:
|
||||||
|
scene.seVolume = value ? parseInt(Setting[index].options[value]) * 0.01 : 0;
|
||||||
|
scene.updateSoundVolume();
|
||||||
|
break;
|
||||||
|
case SettingKeys.Damage_Numbers:
|
||||||
|
scene.damageNumbersMode = value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.UI_Theme:
|
||||||
|
scene.uiTheme = value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.Window_Type:
|
||||||
|
updateWindowType(scene, parseInt(Setting[index].options[value]));
|
||||||
|
break;
|
||||||
|
case SettingKeys.Tutorials:
|
||||||
|
scene.enableTutorials = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.Enable_Retries:
|
||||||
|
scene.enableRetries = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.Skip_Seen_Dialogues:
|
||||||
|
scene.skipSeenDialogues = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.Candy_Upgrade_Notification:
|
||||||
|
if (scene.candyUpgradeNotification === value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.candyUpgradeNotification = value;
|
||||||
|
scene.eventTarget.dispatchEvent(new CandyUpgradeNotificationChangedEvent(value));
|
||||||
|
break;
|
||||||
|
case SettingKeys.Candy_Upgrade_Display:
|
||||||
|
scene.candyUpgradeDisplay = value;
|
||||||
|
case SettingKeys.Money_Format:
|
||||||
|
switch (Setting[index].options[value]) {
|
||||||
|
case "Normal":
|
||||||
|
scene.moneyFormat = MoneyFormat.NORMAL;
|
||||||
|
break;
|
||||||
|
case "Abbreviated":
|
||||||
|
scene.moneyFormat = MoneyFormat.ABBREVIATED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scene.updateMoneyText(false);
|
||||||
|
break;
|
||||||
|
case SettingKeys.Sprite_Set:
|
||||||
|
scene.experimentalSprites = !!value;
|
||||||
|
if (value) {
|
||||||
|
scene.initExpSprites();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SettingKeys.Move_Animations:
|
||||||
|
scene.moveAnimations = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.Show_Moveset_Flyout:
|
||||||
|
scene.showMovesetFlyout = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.Show_Stats_on_Level_Up:
|
||||||
|
scene.showLevelUpStats = Setting[index].options[value] === "On";
|
||||||
|
break;
|
||||||
|
case SettingKeys.EXP_Gains_Speed:
|
||||||
|
scene.expGainsSpeed = value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.EXP_Party_Display:
|
||||||
|
scene.expParty = value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.HP_Bar_Speed:
|
||||||
|
scene.hpBarSpeed = value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.Fusion_Palette_Swaps:
|
||||||
|
scene.fusionPaletteSwaps = !!value;
|
||||||
|
break;
|
||||||
|
case SettingKeys.Player_Gender:
|
||||||
|
if (scene.gameData) {
|
||||||
|
const female = Setting[index].options[value] === "Girl";
|
||||||
|
scene.gameData.gender = female ? PlayerGender.FEMALE : PlayerGender.MALE;
|
||||||
|
scene.trainer.setTexture(scene.trainer.texture.key.replace(female ? "m" : "f", female ? "f" : "m"));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SettingKeys.Touch_Controls:
|
||||||
|
scene.enableTouchControls = Setting[index].options[value] !== "Disabled" && hasTouchscreen();
|
||||||
|
const touchControls = document.getElementById("touchControls");
|
||||||
|
if (touchControls) {
|
||||||
|
touchControls.classList.toggle("visible", scene.enableTouchControls);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SettingKeys.Vibration:
|
||||||
|
scene.enableVibration = Setting[index].options[value] !== "Disabled" && hasTouchscreen();
|
||||||
|
break;
|
||||||
|
case SettingKeys.Language:
|
||||||
|
if (value) {
|
||||||
|
if (scene.ui) {
|
||||||
|
const cancelHandler = () => {
|
||||||
|
scene.ui.revertMode();
|
||||||
|
const languageSetting = Setting.find(setting => setting.key === SettingKeys.Language);
|
||||||
|
(scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(Setting.indexOf(languageSetting), 0, true);
|
||||||
|
};
|
||||||
|
const changeLocaleHandler = (locale: string): boolean => {
|
||||||
|
try {
|
||||||
|
i18next.changeLanguage(locale);
|
||||||
|
localStorage.setItem("prLang", locale);
|
||||||
|
cancelHandler();
|
||||||
|
// Reload the whole game to apply the new locale since also some constants are translated
|
||||||
|
window.location.reload();
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error changing locale:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "English",
|
||||||
|
handler: () => changeLocaleHandler("en")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Español",
|
||||||
|
handler: () => changeLocaleHandler("es")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Italiano",
|
||||||
|
handler: () => changeLocaleHandler("it")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Français",
|
||||||
|
handler: () => changeLocaleHandler("fr")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Deutsch",
|
||||||
|
handler: () => changeLocaleHandler("de")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Português (BR)",
|
||||||
|
handler: () => changeLocaleHandler("pt_BR")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "简体中文",
|
||||||
|
handler: () => changeLocaleHandler("zh_CN")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "繁體中文",
|
||||||
|
handler: () => changeLocaleHandler("zh_TW")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "한국어",
|
||||||
|
handler: () => changeLocaleHandler("ko")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cancel",
|
||||||
|
handler: () => cancelHandler()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
maxOptions: 7
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -3,7 +3,7 @@ import {
|
|||||||
getSettingNameWithKeycode
|
getSettingNameWithKeycode
|
||||||
} from "#app/configs/inputs/configHandler";
|
} from "#app/configs/inputs/configHandler";
|
||||||
import {expect} from "vitest";
|
import {expect} from "vitest";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
|
|
||||||
export class InGameManip {
|
export class InGameManip {
|
||||||
private config;
|
private config;
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
assign,
|
assign,
|
||||||
getSettingNameWithKeycode, canIAssignThisKey, canIDeleteThisKey, canIOverrideThisSetting
|
getSettingNameWithKeycode, canIAssignThisKey, canIDeleteThisKey, canIOverrideThisSetting
|
||||||
} from "#app/configs/inputs/configHandler";
|
} from "#app/configs/inputs/configHandler";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
|
|
||||||
export class MenuManip {
|
export class MenuManip {
|
||||||
private config;
|
private config;
|
||||||
|
@ -10,7 +10,7 @@ import {InGameManip} from "#app/test/helpers/inGameManip";
|
|||||||
import {Device} from "#app/enums/devices";
|
import {Device} from "#app/enums/devices";
|
||||||
import {InterfaceConfig} from "#app/inputs-controller";
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty";
|
import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty";
|
||||||
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
|
|
||||||
|
|
||||||
describe("Test Rebinding", () => {
|
describe("Test Rebinding", () => {
|
||||||
|
@ -3,12 +3,13 @@ import {Mode} from "./ui/ui";
|
|||||||
import {InputsController} from "./inputs-controller";
|
import {InputsController} from "./inputs-controller";
|
||||||
import MessageUiHandler from "./ui/message-ui-handler";
|
import MessageUiHandler from "./ui/message-ui-handler";
|
||||||
import StarterSelectUiHandler from "./ui/starter-select-ui-handler";
|
import StarterSelectUiHandler from "./ui/starter-select-ui-handler";
|
||||||
import {Setting, settingOptions} from "./system/settings";
|
import {Setting, SettingKeys, settingIndex} from "./system/settings/settings";
|
||||||
import SettingsUiHandler from "./ui/settings/settings-ui-handler";
|
import SettingsUiHandler from "./ui/settings/settings-ui-handler";
|
||||||
import {Button} from "./enums/buttons";
|
import {Button} from "./enums/buttons";
|
||||||
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
||||||
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
|
import SettingsAccessibilityUiHandler from "./ui/settings/settings-accessiblity-ui-handler";
|
||||||
|
|
||||||
type ActionKeys = Record<Button, () => void>;
|
type ActionKeys = Record<Button, () => void>;
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ export class UiInputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonCycleOption(button: Button): void {
|
buttonCycleOption(button: Button): void {
|
||||||
const whitelist = [StarterSelectUiHandler, SettingsUiHandler, SettingsGamepadUiHandler, SettingsKeyboardUiHandler];
|
const whitelist = [StarterSelectUiHandler, SettingsUiHandler, SettingsAccessibilityUiHandler, SettingsGamepadUiHandler, SettingsKeyboardUiHandler];
|
||||||
const uiHandler = this.scene.ui?.getHandler();
|
const uiHandler = this.scene.ui?.getHandler();
|
||||||
if (whitelist.some(handler => uiHandler instanceof handler)) {
|
if (whitelist.some(handler => uiHandler instanceof handler)) {
|
||||||
this.scene.ui.processInput(button);
|
this.scene.ui.processInput(button);
|
||||||
@ -171,17 +172,14 @@ export class UiInputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonSpeedChange(up = true): void {
|
buttonSpeedChange(up = true): void {
|
||||||
if (up) {
|
const settingGameSpeed = settingIndex(SettingKeys.Game_Speed);
|
||||||
if (this.scene.gameSpeed < 5) {
|
if (up && this.scene.gameSpeed < 5) {
|
||||||
this.scene.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) + 1);
|
this.scene.gameData.saveSetting(SettingKeys.Game_Speed, Setting[settingGameSpeed].options.indexOf(`${this.scene.gameSpeed}x`) + 1);
|
||||||
if (this.scene.ui?.getMode() === Mode.SETTINGS) {
|
if (this.scene.ui?.getMode() === Mode.SETTINGS) {
|
||||||
(this.scene.ui.getHandler() as SettingsUiHandler).show([]);
|
(this.scene.ui.getHandler() as SettingsUiHandler).show([]);
|
||||||
}
|
}
|
||||||
}
|
} else if (!up && this.scene.gameSpeed > 1) {
|
||||||
return;
|
this.scene.gameData.saveSetting(SettingKeys.Game_Speed, Math.max(Setting[settingGameSpeed].options.indexOf(`${this.scene.gameSpeed}x`) - 1, 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) {
|
if (this.scene.ui?.getMode() === Mode.SETTINGS) {
|
||||||
(this.scene.ui.getHandler() as SettingsUiHandler).show([]);
|
(this.scene.ui.getHandler() as SettingsUiHandler).show([]);
|
||||||
}
|
}
|
||||||
|
660
src/ui/settings/abstract-control-settings-ui-handler.ts
Normal file
660
src/ui/settings/abstract-control-settings-ui-handler.ts
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
import UiHandler from "../ui-handler";
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import {InterfaceConfig} from "../../inputs-controller";
|
||||||
|
import {addWindow} from "../ui-theme";
|
||||||
|
import {addTextObject, TextStyle} from "../text";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
import {getIconWithSettingName} from "#app/configs/inputs/configHandler";
|
||||||
|
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
import { Device } from "#app/enums/devices.js";
|
||||||
|
|
||||||
|
export interface InputsIcons {
|
||||||
|
[key: string]: Phaser.GameObjects.Sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayoutConfig {
|
||||||
|
optionsContainer: Phaser.GameObjects.Container;
|
||||||
|
inputsIcons: InputsIcons;
|
||||||
|
settingLabels: Phaser.GameObjects.Text[];
|
||||||
|
optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
optionCursors: integer[];
|
||||||
|
keys: string[];
|
||||||
|
bindingSettings: Array<String>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Abstract class for handling UI elements related to control settings.
|
||||||
|
*/
|
||||||
|
export default abstract class AbstractControlSettingsUiHandler extends UiHandler {
|
||||||
|
protected settingsContainer: Phaser.GameObjects.Container;
|
||||||
|
protected optionsContainer: Phaser.GameObjects.Container;
|
||||||
|
protected navigationContainer: NavigationMenu;
|
||||||
|
|
||||||
|
protected scrollCursor: integer;
|
||||||
|
protected optionCursors: integer[];
|
||||||
|
protected cursorObj: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
|
protected optionsBg: Phaser.GameObjects.NineSlice;
|
||||||
|
protected actionsBg: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
|
protected settingLabels: Phaser.GameObjects.Text[];
|
||||||
|
protected optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
|
||||||
|
// layout will contain the 3 Gamepad tab for each config - dualshock, xbox, snes
|
||||||
|
protected layout: Map<string, LayoutConfig> = new Map<string, LayoutConfig>();
|
||||||
|
// Will contain the input icons from the selected layout
|
||||||
|
protected inputsIcons: InputsIcons;
|
||||||
|
protected navigationIcons: InputsIcons;
|
||||||
|
// list all the setting keys used in the selected layout (because dualshock has more buttons than xbox)
|
||||||
|
protected keys: Array<String>;
|
||||||
|
|
||||||
|
// Store the specific settings related to key bindings for the current gamepad configuration.
|
||||||
|
protected bindingSettings: Array<String>;
|
||||||
|
|
||||||
|
protected setting;
|
||||||
|
protected settingBlacklisted;
|
||||||
|
protected settingDeviceDefaults;
|
||||||
|
protected settingDeviceOptions;
|
||||||
|
protected configs;
|
||||||
|
protected commonSettingsCount;
|
||||||
|
protected textureOverride;
|
||||||
|
protected titleSelected;
|
||||||
|
protected localStoragePropertyName;
|
||||||
|
protected rowsToDisplay: number;
|
||||||
|
protected device: Device;
|
||||||
|
|
||||||
|
abstract saveSettingToLocalStorage(setting, cursor): void;
|
||||||
|
abstract setSetting(scene: BattleScene, setting, value: integer): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the AbstractSettingsUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.rowsToDisplay = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocalStorageSetting(): object {
|
||||||
|
// Retrieve the settings from local storage or use an empty object if none exist.
|
||||||
|
const settings: object = localStorage.hasOwnProperty(this.localStoragePropertyName) ? JSON.parse(localStorage.getItem(this.localStoragePropertyName)) : {};
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup UI elements.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
const ui = this.getUi();
|
||||||
|
this.navigationIcons = {};
|
||||||
|
|
||||||
|
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||||
|
|
||||||
|
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
||||||
|
|
||||||
|
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
||||||
|
|
||||||
|
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
||||||
|
this.optionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
this.actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
||||||
|
this.actionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconAction.setOrigin(0, -0.1);
|
||||||
|
iconAction.setPositionRelative(this.actionsBg, this.navigationContainer.width - 32, 4);
|
||||||
|
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
||||||
|
|
||||||
|
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
||||||
|
actionText.setOrigin(0, 0.15);
|
||||||
|
actionText.setPositionRelative(iconAction, -actionText.width/6-2, 0);
|
||||||
|
|
||||||
|
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconCancel.setOrigin(0, -0.1);
|
||||||
|
iconCancel.setPositionRelative(this.actionsBg, this.navigationContainer.width - 100, 4);
|
||||||
|
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
||||||
|
|
||||||
|
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
||||||
|
cancelText.setOrigin(0, 0.15);
|
||||||
|
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
||||||
|
|
||||||
|
const iconReset = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconReset.setOrigin(0, -0.1);
|
||||||
|
iconReset.setPositionRelative(this.actionsBg, this.navigationContainer.width - 180, 4);
|
||||||
|
this.navigationIcons["BUTTON_HOME"] = iconReset;
|
||||||
|
|
||||||
|
const resetText = addTextObject(this.scene, 0, 0, "Reset all", TextStyle.SETTINGS_LABEL);
|
||||||
|
resetText.setOrigin(0, 0.15);
|
||||||
|
resetText.setPositionRelative(iconReset, -resetText.width/6-2, 0);
|
||||||
|
|
||||||
|
this.settingsContainer.add(this.optionsBg);
|
||||||
|
this.settingsContainer.add(this.actionsBg);
|
||||||
|
this.settingsContainer.add(this.navigationContainer);
|
||||||
|
this.settingsContainer.add(iconAction);
|
||||||
|
this.settingsContainer.add(iconCancel);
|
||||||
|
this.settingsContainer.add(iconReset);
|
||||||
|
this.settingsContainer.add(actionText);
|
||||||
|
this.settingsContainer.add(cancelText);
|
||||||
|
this.settingsContainer.add(resetText);
|
||||||
|
|
||||||
|
/// Initialize a new configuration "screen" for each type of gamepad.
|
||||||
|
for (const config of this.configs) {
|
||||||
|
// Create a map to store layout settings based on the pad type.
|
||||||
|
this.layout[config.padType] = new Map();
|
||||||
|
// Create a container for gamepad options in the scene, initially hidden.
|
||||||
|
|
||||||
|
const optionsContainer = this.scene.add.container(0, 0);
|
||||||
|
optionsContainer.setVisible(false);
|
||||||
|
|
||||||
|
// Gather all binding settings from the configuration.
|
||||||
|
const bindingSettings = Object.keys(config.settings);
|
||||||
|
|
||||||
|
// Array to hold labels for different settings such as 'Controller', 'Gamepad Support', etc.
|
||||||
|
const settingLabels: Phaser.GameObjects.Text[] = [];
|
||||||
|
|
||||||
|
// Array to hold options for each setting, e.g., 'Auto', 'Disabled'.
|
||||||
|
const optionValueLabels: Phaser.GameObjects.GameObject[][] = [];
|
||||||
|
|
||||||
|
// Object to store sprites for each button configuration.
|
||||||
|
const inputsIcons: InputsIcons = {};
|
||||||
|
|
||||||
|
// Fetch common setting keys such as 'Controller' and 'Gamepad Support' from gamepad settings.
|
||||||
|
const commonSettingKeys = Object.keys(this.setting).slice(0, this.commonSettingsCount).map(key => this.setting[key]);
|
||||||
|
// Combine common and specific bindings into a single array.
|
||||||
|
const specificBindingKeys = [...commonSettingKeys, ...Object.keys(config.settings)];
|
||||||
|
// Fetch default values for these settings and prepare to highlight selected options.
|
||||||
|
const optionCursors = Object.values(Object.keys(this.settingDeviceDefaults).filter(s => specificBindingKeys.includes(s)).map(k => this.settingDeviceDefaults[k]));
|
||||||
|
// Filter out settings that are not relevant to the current gamepad configuration.
|
||||||
|
const settingFiltered = Object.keys(this.setting).filter(_key => specificBindingKeys.includes(this.setting[_key]));
|
||||||
|
// Loop through the filtered settings to manage display and options.
|
||||||
|
|
||||||
|
settingFiltered.forEach((setting, s) => {
|
||||||
|
// Convert the setting key from format 'Key_Name' to 'Key name' for display.
|
||||||
|
const settingName = setting.replace(/\_/g, " ");
|
||||||
|
|
||||||
|
// Create and add a text object for the setting name to the scene.
|
||||||
|
const isLock = this.settingBlacklisted.includes(this.setting[setting]);
|
||||||
|
const labelStyle = isLock ? TextStyle.SETTINGS_LOCKED : TextStyle.SETTINGS_LABEL;
|
||||||
|
settingLabels[s] = addTextObject(this.scene, 8, 28 + s * 16, settingName, labelStyle);
|
||||||
|
settingLabels[s].setOrigin(0, 0);
|
||||||
|
optionsContainer.add(settingLabels[s]);
|
||||||
|
|
||||||
|
// Initialize an array to store the option labels for this setting.
|
||||||
|
const valueLabels: Phaser.GameObjects.GameObject[] = [];
|
||||||
|
|
||||||
|
// Process each option for the current setting.
|
||||||
|
for (const [o, option] of this.settingDeviceOptions[this.setting[setting]].entries()) {
|
||||||
|
// Check if the current setting is for binding keys.
|
||||||
|
if (bindingSettings.includes(this.setting[setting])) {
|
||||||
|
// Create a label for non-null options, typically indicating actionable options like 'change'.
|
||||||
|
if (o) {
|
||||||
|
const valueLabel = addTextObject(this.scene, 0, 0, isLock ? "" : option, TextStyle.WINDOW);
|
||||||
|
valueLabel.setOrigin(0, 0);
|
||||||
|
optionsContainer.add(valueLabel);
|
||||||
|
valueLabels.push(valueLabel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// For null options, add an icon for the key.
|
||||||
|
const icon = this.scene.add.sprite(0, 0, this.textureOverride ? this.textureOverride : config.padType);
|
||||||
|
icon.setOrigin(0, -0.15);
|
||||||
|
inputsIcons[this.setting[setting]] = icon;
|
||||||
|
optionsContainer.add(icon);
|
||||||
|
valueLabels.push(icon);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// For regular settings like 'Gamepad support', create a label and determine if it is selected.
|
||||||
|
const valueLabel = addTextObject(this.scene, 0, 0, option, this.settingDeviceDefaults[this.setting[setting]] === o ? TextStyle.SETTINGS_SELECTED : TextStyle.WINDOW);
|
||||||
|
valueLabel.setOrigin(0, 0);
|
||||||
|
|
||||||
|
optionsContainer.add(valueLabel);
|
||||||
|
|
||||||
|
//if a setting has 2 options, valueLabels will be an array of 2 elements
|
||||||
|
valueLabels.push(valueLabel);
|
||||||
|
}
|
||||||
|
// Collect all option labels for this setting into the main array.
|
||||||
|
optionValueLabels.push(valueLabels);
|
||||||
|
|
||||||
|
// Calculate the total width of all option labels within a specific setting
|
||||||
|
// This is achieved by summing the width of each option label
|
||||||
|
const totalWidth = optionValueLabels[s].map((o) => (o as Phaser.GameObjects.Text).width).reduce((total, width) => total += width, 0);
|
||||||
|
|
||||||
|
// Define the minimum width for a label, ensuring it's at least 78 pixels wide or the width of the setting label plus some padding
|
||||||
|
const labelWidth = Math.max(130, settingLabels[s].displayWidth + 8);
|
||||||
|
|
||||||
|
// Calculate the total available space for placing option labels next to their setting label
|
||||||
|
// We reserve space for the setting label and then distribute the remaining space evenly
|
||||||
|
const totalSpace = (300 - labelWidth) - totalWidth / 6;
|
||||||
|
// Calculate the spacing between options based on the available space divided by the number of gaps between labels
|
||||||
|
const optionSpacing = Math.floor(totalSpace / (optionValueLabels[s].length - 1));
|
||||||
|
|
||||||
|
// Initialize xOffset to zero, which will be used to position each option label horizontally
|
||||||
|
let xOffset = 0;
|
||||||
|
|
||||||
|
// Start positioning each option label one by one
|
||||||
|
for (const value of optionValueLabels[s]) {
|
||||||
|
// Set the option label's position right next to the setting label, adjusted by xOffset
|
||||||
|
(value as Phaser.GameObjects.Text).setPositionRelative(settingLabels[s], labelWidth + xOffset, 0);
|
||||||
|
// Move the xOffset to the right for the next label, ensuring each label is spaced evenly
|
||||||
|
xOffset += (value as Phaser.GameObjects.Text).width / 6 + optionSpacing;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assigning the newly created components to the layout map under the specific gamepad type.
|
||||||
|
this.layout[config.padType].optionsContainer = optionsContainer; // Container for this pad's options.
|
||||||
|
this.layout[config.padType].inputsIcons = inputsIcons; // Icons for each input specific to this pad.
|
||||||
|
this.layout[config.padType].settingLabels = settingLabels; // Text labels for each setting available on this pad.
|
||||||
|
this.layout[config.padType].optionValueLabels = optionValueLabels; // Labels for values corresponding to each setting.
|
||||||
|
this.layout[config.padType].optionCursors = optionCursors; // Cursors to navigate through the options.
|
||||||
|
this.layout[config.padType].keys = specificBindingKeys; // Keys that identify each setting specifically bound to this pad.
|
||||||
|
this.layout[config.padType].bindingSettings = bindingSettings; // Settings that define how the keys are bound.
|
||||||
|
|
||||||
|
// Add the options container to the overall settings container to be displayed in the UI.
|
||||||
|
this.settingsContainer.add(optionsContainer);
|
||||||
|
}
|
||||||
|
// Add the settings container to the UI.
|
||||||
|
ui.add(this.settingsContainer);
|
||||||
|
|
||||||
|
// Initially hide the settings container until needed (e.g., when a gamepad is connected or a button is pressed).
|
||||||
|
this.settingsContainer.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the active configuration.
|
||||||
|
*
|
||||||
|
* @returns The active configuration for current device
|
||||||
|
*/
|
||||||
|
getActiveConfig(): InterfaceConfig {
|
||||||
|
return this.scene.inputController.getActiveConfig(this.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the bindings for the current active device configuration.
|
||||||
|
*/
|
||||||
|
updateBindings(): void {
|
||||||
|
// Hide the options container for all layouts to reset the UI visibility.
|
||||||
|
Object.keys(this.layout).forEach((key) => this.layout[key].optionsContainer.setVisible(false));
|
||||||
|
// Fetch the active gamepad configuration from the input controller.
|
||||||
|
const activeConfig = this.getActiveConfig();
|
||||||
|
|
||||||
|
// Set the UI layout for the active configuration. If unsuccessful, exit the function early.
|
||||||
|
if (!this.setLayout(activeConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
||||||
|
const settings: object = this.getLocalStorageSetting();
|
||||||
|
|
||||||
|
// Update the cursor for each key based on the stored settings or default cursors.
|
||||||
|
this.keys.forEach((key, index) => {
|
||||||
|
this.setOptionCursor(index, settings.hasOwnProperty(key as string) ? settings[key as string] : this.optionCursors[index]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the active configuration has no custom bindings set, exit the function early.
|
||||||
|
// by default, if custom does not exists, a default is assigned to it
|
||||||
|
// it only means the gamepad is not yet initalized
|
||||||
|
if (!activeConfig.custom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each element in the binding settings, update the icon according to the current assignment.
|
||||||
|
for (const elm of this.bindingSettings) {
|
||||||
|
const icon = getIconWithSettingName(activeConfig, elm);
|
||||||
|
if (icon) {
|
||||||
|
this.inputsIcons[elm as string].setFrame(icon);
|
||||||
|
this.inputsIcons[elm as string].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.inputsIcons[elm as string].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the cursor and scroll cursor to their initial positions.
|
||||||
|
this.setCursor(this.cursor);
|
||||||
|
this.setScrollCursor(this.scrollCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNavigationDisplay() {
|
||||||
|
const specialIcons = {
|
||||||
|
"BUTTON_HOME": "HOME.png",
|
||||||
|
"BUTTON_DELETE": "DEL.png",
|
||||||
|
};
|
||||||
|
for (const settingName of Object.keys(this.navigationIcons)) {
|
||||||
|
if (Object.keys(specialIcons).includes(settingName)) {
|
||||||
|
this.navigationIcons[settingName].setTexture("keyboard");
|
||||||
|
this.navigationIcons[settingName].setFrame(specialIcons[settingName]);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const icon = this.scene.inputController?.getIconForLatestInputRecorded(settingName);
|
||||||
|
if (icon) {
|
||||||
|
const type = this.scene.inputController?.getLastSourceType();
|
||||||
|
this.navigationIcons[settingName].setTexture(type);
|
||||||
|
this.navigationIcons[settingName].setFrame(icon);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.navigationIcons[settingName].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UI with the provided arguments.
|
||||||
|
*
|
||||||
|
* @param args - Arguments to be passed to the show method.
|
||||||
|
* @returns `true` if successful.
|
||||||
|
*/
|
||||||
|
show(args: any[]): boolean {
|
||||||
|
super.show(args);
|
||||||
|
|
||||||
|
this.updateNavigationDisplay();
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
// Update the bindings for the current active gamepad configuration.
|
||||||
|
this.updateBindings();
|
||||||
|
|
||||||
|
// Make the settings container visible to the user.
|
||||||
|
this.settingsContainer.setVisible(true);
|
||||||
|
// Reset the scroll cursor to the top of the settings container.
|
||||||
|
this.resetScroll();
|
||||||
|
|
||||||
|
// Move the settings container to the end of the UI stack to ensure it is displayed on top.
|
||||||
|
this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1);
|
||||||
|
|
||||||
|
// Hide any tooltips that might be visible before showing the settings container.
|
||||||
|
this.getUi().hideTooltip();
|
||||||
|
|
||||||
|
// Return true to indicate the UI was successfully shown.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the UI layout for the active device configuration.
|
||||||
|
*
|
||||||
|
* @param activeConfig - The active device configuration.
|
||||||
|
* @returns `true` if the layout was successfully applied, otherwise `false`.
|
||||||
|
*/
|
||||||
|
setLayout(activeConfig: InterfaceConfig): boolean {
|
||||||
|
// Check if there is no active configuration (e.g., no gamepad connected).
|
||||||
|
if (!activeConfig) {
|
||||||
|
// Retrieve the layout for when no gamepads are connected.
|
||||||
|
const layout = this.layout["noGamepads"];
|
||||||
|
// Make the options container visible to show message.
|
||||||
|
layout.optionsContainer.setVisible(true);
|
||||||
|
// Return false indicating the layout application was not successful due to lack of gamepad.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Extract the type of the gamepad from the active configuration.
|
||||||
|
const configType = activeConfig.padType;
|
||||||
|
|
||||||
|
// Retrieve the layout settings based on the type of the gamepad.
|
||||||
|
const layout = this.layout[configType];
|
||||||
|
// Update the main controller with configuration details from the selected layout.
|
||||||
|
this.keys = layout.keys;
|
||||||
|
this.optionsContainer = layout.optionsContainer;
|
||||||
|
this.optionsContainer.setVisible(true);
|
||||||
|
this.settingLabels = layout.settingLabels;
|
||||||
|
this.optionValueLabels = layout.optionValueLabels;
|
||||||
|
this.optionCursors = layout.optionCursors;
|
||||||
|
this.inputsIcons = layout.inputsIcons;
|
||||||
|
this.bindingSettings = layout.bindingSettings;
|
||||||
|
|
||||||
|
// Return true indicating the layout was successfully applied.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the input for the given button.
|
||||||
|
*
|
||||||
|
* @param button - The button to process.
|
||||||
|
* @returns `true` if the input was processed successfully.
|
||||||
|
*/
|
||||||
|
processInput(button: Button): boolean {
|
||||||
|
const ui = this.getUi();
|
||||||
|
// Defines the maximum number of rows that can be displayed on the screen.
|
||||||
|
let success = false;
|
||||||
|
this.updateNavigationDisplay();
|
||||||
|
|
||||||
|
// Handle the input based on the button pressed.
|
||||||
|
if (button === Button.CANCEL) {
|
||||||
|
// Handle cancel button press, reverting UI mode to previous state.
|
||||||
|
success = true;
|
||||||
|
NavigationManager.getInstance().reset();
|
||||||
|
this.scene.ui.revertMode();
|
||||||
|
} else {
|
||||||
|
const cursor = this.cursor + this.scrollCursor; // Calculate the absolute cursor position.
|
||||||
|
const setting = this.setting[Object.keys(this.setting)[cursor]];
|
||||||
|
switch (button) {
|
||||||
|
case Button.ACTION:
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || !setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
success = this.setSetting(this.scene, setting, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.UP: // Move up in the menu.
|
||||||
|
if (!this.optionValueLabels) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cursor) { // If not at the top, move the cursor up.
|
||||||
|
if (this.cursor) {
|
||||||
|
success = this.setCursor(this.cursor - 1);
|
||||||
|
} else {// If at the top of the visible items, scroll up.
|
||||||
|
success = this.setScrollCursor(this.scrollCursor - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When at the top of the menu and pressing UP, move to the bottommost item.
|
||||||
|
// First, set the cursor to the last visible element, preparing for the scroll to the end.
|
||||||
|
const successA = this.setCursor(this.rowsToDisplay - 1);
|
||||||
|
// Then, adjust the scroll to display the bottommost elements of the menu.
|
||||||
|
const successB = this.setScrollCursor(this.optionValueLabels.length - this.rowsToDisplay);
|
||||||
|
success = successA && successB; // success is just there to play the little validation sound effect
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.DOWN: // Move down in the menu.
|
||||||
|
if (!this.optionValueLabels) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cursor < this.optionValueLabels.length - 1) {
|
||||||
|
if (this.cursor < this.rowsToDisplay - 1) {
|
||||||
|
success = this.setCursor(this.cursor + 1);
|
||||||
|
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
||||||
|
success = this.setScrollCursor(this.scrollCursor + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When at the bottom of the menu and pressing DOWN, move to the topmost item.
|
||||||
|
// First, set the cursor to the first visible element, resetting the scroll to the top.
|
||||||
|
const successA = this.setCursor(0);
|
||||||
|
// Then, reset the scroll to start from the first element of the menu.
|
||||||
|
const successB = this.setScrollCursor(0);
|
||||||
|
success = successA && successB; // Indicates a successful cursor and scroll adjustment.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.LEFT: // Move selection left within the current option set.
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else if (this.optionCursors[cursor]) {
|
||||||
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.RIGHT: // Move selection right within the current option set.
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
|
||||||
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.CYCLE_FORM:
|
||||||
|
case Button.CYCLE_SHINY:
|
||||||
|
success = this.navigationContainer.navigate(button);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a change occurred, play the selection sound.
|
||||||
|
if (success) {
|
||||||
|
ui.playSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success; // Return whether the input resulted in a successful action.
|
||||||
|
}
|
||||||
|
|
||||||
|
resetScroll() {
|
||||||
|
this.cursorObj?.destroy();
|
||||||
|
this.cursorObj = null;
|
||||||
|
this.cursor = null;
|
||||||
|
this.setCursor(0);
|
||||||
|
this.setScrollCursor(0);
|
||||||
|
this.updateSettingsScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param cursor - The cursor position to set.
|
||||||
|
* @returns `true` if the cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setCursor(cursor: integer): boolean {
|
||||||
|
const ret = super.setCursor(cursor);
|
||||||
|
// If the optionsContainer is not initialized, return the result from the parent class directly.
|
||||||
|
if (!this.optionsContainer) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the cursor object exists, if not, create it.
|
||||||
|
if (!this.cursorObj) {
|
||||||
|
this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1);
|
||||||
|
this.cursorObj.setOrigin(0, 0); // Set the origin to the top-left corner.
|
||||||
|
this.optionsContainer.add(this.cursorObj); // Add the cursor to the options container.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the position of the cursor object relative to the options background based on the current cursor and scroll positions.
|
||||||
|
this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16);
|
||||||
|
|
||||||
|
return ret; // Return the result from the parent class's setCursor method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the scroll cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param scrollCursor - The scroll cursor position to set.
|
||||||
|
* @returns `true` if the scroll cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setScrollCursor(scrollCursor: integer): boolean {
|
||||||
|
// Check if the new scroll position is the same as the current one; if so, do not update.
|
||||||
|
if (scrollCursor === this.scrollCursor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the internal scroll cursor state
|
||||||
|
this.scrollCursor = scrollCursor;
|
||||||
|
|
||||||
|
// Apply the new scroll position to the settings UI.
|
||||||
|
this.updateSettingsScroll();
|
||||||
|
|
||||||
|
// Reset the cursor to its current position to adjust its visibility after scrolling.
|
||||||
|
this.setCursor(this.cursor);
|
||||||
|
|
||||||
|
return true; // Return true to indicate the scroll cursor was successfully updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the option cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param settingIndex - The index of the setting.
|
||||||
|
* @param cursor - The cursor position to set.
|
||||||
|
* @param save - Whether to save the setting to local storage.
|
||||||
|
* @returns `true` if the option cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
||||||
|
// Retrieve the specific setting using the settingIndex from the settingDevice enumeration.
|
||||||
|
const setting = this.setting[Object.keys(this.setting)[settingIndex]];
|
||||||
|
|
||||||
|
// Get the current cursor position for this setting.
|
||||||
|
const lastCursor = this.optionCursors[settingIndex];
|
||||||
|
|
||||||
|
// Check if the setting is not part of the bindings (i.e., it's a regular setting).
|
||||||
|
if (!this.bindingSettings.includes(setting) && !setting.includes("BUTTON_")) {
|
||||||
|
// Get the label of the last selected option and revert its color to the default.
|
||||||
|
const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor];
|
||||||
|
lastValueLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
||||||
|
lastValueLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
||||||
|
|
||||||
|
// Update the cursor for the setting to the new position.
|
||||||
|
this.optionCursors[settingIndex] = cursor;
|
||||||
|
|
||||||
|
// Change the color of the new selected option to indicate it's selected.
|
||||||
|
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
||||||
|
newValueLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||||
|
newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the save flag is set, save the setting to local storage
|
||||||
|
if (save) {
|
||||||
|
this.saveSettingToLocalStorage(setting, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Return true to indicate the cursor was successfully updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the scroll position of the settings UI.
|
||||||
|
*/
|
||||||
|
updateSettingsScroll(): void {
|
||||||
|
// Return immediately if the options container is not initialized.
|
||||||
|
if (!this.optionsContainer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the vertical position of the options container based on the current scroll cursor, multiplying by the item height.
|
||||||
|
this.optionsContainer.setY(-16 * this.scrollCursor);
|
||||||
|
|
||||||
|
// Iterate over all setting labels to update their visibility.
|
||||||
|
for (let s = 0; s < this.settingLabels.length; s++) {
|
||||||
|
// Determine if the current setting should be visible based on the scroll position.
|
||||||
|
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
||||||
|
|
||||||
|
// Set the visibility of the setting label and its corresponding options.
|
||||||
|
this.settingLabels[s].setVisible(visible);
|
||||||
|
for (const option of this.optionValueLabels[s]) {
|
||||||
|
option.setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the UI elements and state.
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
super.clear();
|
||||||
|
|
||||||
|
// Hide the settings container to remove it from the view.
|
||||||
|
this.settingsContainer.setVisible(false);
|
||||||
|
|
||||||
|
// Remove the cursor from the UI.
|
||||||
|
this.eraseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase the cursor from the UI.
|
||||||
|
*/
|
||||||
|
eraseCursor(): void {
|
||||||
|
// Check if a cursor object exists.
|
||||||
|
if (this.cursorObj) {
|
||||||
|
this.cursorObj.destroy();
|
||||||
|
} // Destroy the cursor object to clean up resources.
|
||||||
|
|
||||||
|
// Set the cursor object reference to null to fully dereference it.
|
||||||
|
this.cursorObj = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,107 +1,74 @@
|
|||||||
import UiHandler from "../ui-handler";
|
|
||||||
import BattleScene from "../../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
|
import { hasTouchscreen, isMobile } from "../../touch-controls";
|
||||||
|
import { TextStyle, addTextObject } from "../text";
|
||||||
import { Mode } from "../ui";
|
import { Mode } from "../ui";
|
||||||
import {InterfaceConfig} from "../../inputs-controller";
|
import UiHandler from "../ui-handler";
|
||||||
import { addWindow } from "../ui-theme";
|
import { addWindow } from "../ui-theme";
|
||||||
import {addTextObject, TextStyle} from "../text";
|
|
||||||
import {Button} from "../../enums/buttons";
|
import {Button} from "../../enums/buttons";
|
||||||
import {getIconWithSettingName} from "#app/configs/inputs/configHandler";
|
import {InputsIcons} from "#app/ui/settings/abstract-control-settings-ui-handler.js";
|
||||||
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
import { Setting, SettingKeys } from "#app/system/settings/settings";
|
||||||
|
|
||||||
export interface InputsIcons {
|
|
||||||
[key: string]: Phaser.GameObjects.Sprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LayoutConfig {
|
|
||||||
optionsContainer: Phaser.GameObjects.Container;
|
|
||||||
inputsIcons: InputsIcons;
|
|
||||||
settingLabels: Phaser.GameObjects.Text[];
|
|
||||||
optionValueLabels: Phaser.GameObjects.Text[][];
|
|
||||||
optionCursors: integer[];
|
|
||||||
keys: string[];
|
|
||||||
bindingSettings: Array<String>;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for handling UI elements related to settings.
|
* Abstract class for handling UI elements related to settings.
|
||||||
*/
|
*/
|
||||||
export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
export default class AbstractSettingsUiHandler extends UiHandler {
|
||||||
protected settingsContainer: Phaser.GameObjects.Container;
|
private settingsContainer: Phaser.GameObjects.Container;
|
||||||
protected optionsContainer: Phaser.GameObjects.Container;
|
private optionsContainer: Phaser.GameObjects.Container;
|
||||||
protected navigationContainer: NavigationMenu;
|
private navigationContainer: NavigationMenu;
|
||||||
|
|
||||||
protected scrollCursor: integer;
|
private scrollCursor: integer;
|
||||||
protected optionCursors: integer[];
|
|
||||||
protected cursorObj: Phaser.GameObjects.NineSlice;
|
|
||||||
|
|
||||||
protected optionsBg: Phaser.GameObjects.NineSlice;
|
private optionsBg: Phaser.GameObjects.NineSlice;
|
||||||
protected actionsBg: Phaser.GameObjects.NineSlice;
|
|
||||||
|
|
||||||
protected settingLabels: Phaser.GameObjects.Text[];
|
private optionCursors: integer[];
|
||||||
protected optionValueLabels: Phaser.GameObjects.Text[][];
|
|
||||||
|
private settingLabels: Phaser.GameObjects.Text[];
|
||||||
|
private optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
|
||||||
// layout will contain the 3 Gamepad tab for each config - dualshock, xbox, snes
|
|
||||||
protected layout: Map<string, LayoutConfig> = new Map<string, LayoutConfig>();
|
|
||||||
// Will contain the input icons from the selected layout
|
|
||||||
protected inputsIcons: InputsIcons;
|
|
||||||
protected navigationIcons: InputsIcons;
|
protected navigationIcons: InputsIcons;
|
||||||
// list all the setting keys used in the selected layout (because dualshock has more buttons than xbox)
|
|
||||||
protected keys: Array<String>;
|
|
||||||
|
|
||||||
// Store the specific settings related to key bindings for the current gamepad configuration.
|
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||||
protected bindingSettings: Array<String>;
|
|
||||||
|
|
||||||
protected settingDevice;
|
private reloadSettings: Array<Setting>;
|
||||||
protected settingBlacklisted;
|
private reloadRequired: boolean;
|
||||||
protected settingDeviceDefaults;
|
private rowsToDisplay: number;
|
||||||
protected settingDeviceOptions;
|
|
||||||
protected configs;
|
|
||||||
protected commonSettingsCount;
|
|
||||||
protected textureOverride;
|
|
||||||
protected titleSelected;
|
|
||||||
protected localStoragePropertyName;
|
|
||||||
protected rowsToDisplay: number;
|
|
||||||
|
|
||||||
abstract getLocalStorageSetting(): object;
|
protected title: string;
|
||||||
abstract navigateMenuLeft(): boolean;
|
protected settings: Array<Setting>;
|
||||||
abstract navigateMenuRight(): boolean;
|
protected localStorageKey: string;
|
||||||
abstract saveSettingToLocalStorage(setting, cursor): void;
|
|
||||||
abstract getActiveConfig(): InterfaceConfig;
|
|
||||||
abstract setSetting(scene: BattleScene, setting, value: integer): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the AbstractSettingsUiUiHandler.
|
|
||||||
*
|
|
||||||
* @param scene - The BattleScene instance.
|
|
||||||
* @param mode - The UI mode.
|
|
||||||
*/
|
|
||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
|
||||||
|
this.reloadRequired = false;
|
||||||
this.rowsToDisplay = 8;
|
this.rowsToDisplay = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup UI elements.
|
* Setup UI elements
|
||||||
*/
|
*/
|
||||||
setup() {
|
setup() {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
this.navigationIcons = {};
|
|
||||||
|
|
||||||
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||||
|
|
||||||
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6 - 20), Phaser.Geom.Rectangle.Contains);
|
||||||
|
|
||||||
|
this.navigationIcons = {};
|
||||||
|
|
||||||
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
||||||
|
|
||||||
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
||||||
this.optionsBg.setOrigin(0, 0);
|
this.optionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
const actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
||||||
this.actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
actionsBg.setOrigin(0, 0);
|
||||||
this.actionsBg.setOrigin(0, 0);
|
|
||||||
|
|
||||||
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
iconAction.setOrigin(0, -0.1);
|
iconAction.setOrigin(0, -0.1);
|
||||||
iconAction.setPositionRelative(this.actionsBg, this.navigationContainer.width - 32, 4);
|
iconAction.setPositionRelative(actionsBg, this.navigationContainer.width - 32, 4);
|
||||||
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
||||||
|
|
||||||
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
||||||
@ -110,207 +77,81 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
|
|
||||||
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
iconCancel.setOrigin(0, -0.1);
|
iconCancel.setOrigin(0, -0.1);
|
||||||
iconCancel.setPositionRelative(this.actionsBg, this.navigationContainer.width - 100, 4);
|
iconCancel.setPositionRelative(actionsBg, this.navigationContainer.width - 100, 4);
|
||||||
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
||||||
|
|
||||||
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
||||||
cancelText.setOrigin(0, 0.15);
|
cancelText.setOrigin(0, 0.15);
|
||||||
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
||||||
|
|
||||||
const iconReset = this.scene.add.sprite(0, 0, "keyboard");
|
this.optionsContainer = this.scene.add.container(0, 0);
|
||||||
iconReset.setOrigin(0, -0.1);
|
|
||||||
iconReset.setPositionRelative(this.actionsBg, this.navigationContainer.width - 180, 4);
|
|
||||||
this.navigationIcons["BUTTON_HOME"] = iconReset;
|
|
||||||
|
|
||||||
const resetText = addTextObject(this.scene, 0, 0, "Reset all", TextStyle.SETTINGS_LABEL);
|
this.settingLabels = [];
|
||||||
resetText.setOrigin(0, 0.15);
|
this.optionValueLabels = [];
|
||||||
resetText.setPositionRelative(iconReset, -resetText.width/6-2, 0);
|
|
||||||
|
|
||||||
this.settingsContainer.add(this.optionsBg);
|
this.reloadSettings = this.settings.filter(s => s?.requireReload);
|
||||||
this.settingsContainer.add(this.actionsBg);
|
|
||||||
this.settingsContainer.add(this.navigationContainer);
|
|
||||||
this.settingsContainer.add(iconAction);
|
|
||||||
this.settingsContainer.add(iconCancel);
|
|
||||||
this.settingsContainer.add(iconReset);
|
|
||||||
this.settingsContainer.add(actionText);
|
|
||||||
this.settingsContainer.add(cancelText);
|
|
||||||
this.settingsContainer.add(resetText);
|
|
||||||
|
|
||||||
/// Initialize a new configuration "screen" for each type of gamepad.
|
this.settings
|
||||||
for (const config of this.configs) {
|
.forEach((setting, s) => {
|
||||||
// Create a map to store layout settings based on the pad type.
|
let settingName = setting.label;
|
||||||
this.layout[config.padType] = new Map();
|
if (setting?.requireReload) {
|
||||||
// Create a container for gamepad options in the scene, initially hidden.
|
settingName += " (Requires Reload)";
|
||||||
|
|
||||||
const optionsContainer = this.scene.add.container(0, 0);
|
|
||||||
optionsContainer.setVisible(false);
|
|
||||||
|
|
||||||
// Gather all binding settings from the configuration.
|
|
||||||
const bindingSettings = Object.keys(config.settings);
|
|
||||||
|
|
||||||
// Array to hold labels for different settings such as 'Controller', 'Gamepad Support', etc.
|
|
||||||
const settingLabels: Phaser.GameObjects.Text[] = [];
|
|
||||||
|
|
||||||
// Array to hold options for each setting, e.g., 'Auto', 'Disabled'.
|
|
||||||
const optionValueLabels: Phaser.GameObjects.GameObject[][] = [];
|
|
||||||
|
|
||||||
// Object to store sprites for each button configuration.
|
|
||||||
const inputsIcons: InputsIcons = {};
|
|
||||||
|
|
||||||
// Fetch common setting keys such as 'Controller' and 'Gamepad Support' from gamepad settings.
|
|
||||||
const commonSettingKeys = Object.keys(this.settingDevice).slice(0, this.commonSettingsCount).map(key => this.settingDevice[key]);
|
|
||||||
// Combine common and specific bindings into a single array.
|
|
||||||
const specificBindingKeys = [...commonSettingKeys, ...Object.keys(config.settings)];
|
|
||||||
// Fetch default values for these settings and prepare to highlight selected options.
|
|
||||||
const optionCursors = Object.values(Object.keys(this.settingDeviceDefaults).filter(s => specificBindingKeys.includes(s)).map(k => this.settingDeviceDefaults[k]));
|
|
||||||
// Filter out settings that are not relevant to the current gamepad configuration.
|
|
||||||
const settingFiltered = Object.keys(this.settingDevice).filter(_key => specificBindingKeys.includes(this.settingDevice[_key]));
|
|
||||||
// Loop through the filtered settings to manage display and options.
|
|
||||||
|
|
||||||
settingFiltered.forEach((setting, s) => {
|
|
||||||
// Convert the setting key from format 'Key_Name' to 'Key name' for display.
|
|
||||||
const settingName = setting.replace(/\_/g, " ");
|
|
||||||
|
|
||||||
// Create and add a text object for the setting name to the scene.
|
|
||||||
const isLock = this.settingBlacklisted.includes(this.settingDevice[setting]);
|
|
||||||
const labelStyle = isLock ? TextStyle.SETTINGS_LOCKED : TextStyle.SETTINGS_LABEL;
|
|
||||||
settingLabels[s] = addTextObject(this.scene, 8, 28 + s * 16, settingName, labelStyle);
|
|
||||||
settingLabels[s].setOrigin(0, 0);
|
|
||||||
optionsContainer.add(settingLabels[s]);
|
|
||||||
|
|
||||||
// Initialize an array to store the option labels for this setting.
|
|
||||||
const valueLabels: Phaser.GameObjects.GameObject[] = [];
|
|
||||||
|
|
||||||
// Process each option for the current setting.
|
|
||||||
for (const [o, option] of this.settingDeviceOptions[this.settingDevice[setting]].entries()) {
|
|
||||||
// Check if the current setting is for binding keys.
|
|
||||||
if (bindingSettings.includes(this.settingDevice[setting])) {
|
|
||||||
// Create a label for non-null options, typically indicating actionable options like 'change'.
|
|
||||||
if (o) {
|
|
||||||
const valueLabel = addTextObject(this.scene, 0, 0, isLock ? "" : option, TextStyle.WINDOW);
|
|
||||||
valueLabel.setOrigin(0, 0);
|
|
||||||
optionsContainer.add(valueLabel);
|
|
||||||
valueLabels.push(valueLabel);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// For null options, add an icon for the key.
|
|
||||||
const icon = this.scene.add.sprite(0, 0, this.textureOverride ? this.textureOverride : config.padType);
|
this.settingLabels[s] = addTextObject(this.scene, 8, 28 + s * 16, settingName, TextStyle.SETTINGS_LABEL);
|
||||||
icon.setOrigin(0, -0.15);
|
this.settingLabels[s].setOrigin(0, 0);
|
||||||
inputsIcons[this.settingDevice[setting]] = icon;
|
|
||||||
optionsContainer.add(icon);
|
this.optionsContainer.add(this.settingLabels[s]);
|
||||||
valueLabels.push(icon);
|
this.optionValueLabels.push(setting.options.map((option, o) => {
|
||||||
continue;
|
const valueLabel = addTextObject(this.scene, 0, 0, option, setting.default === o ? TextStyle.SETTINGS_SELECTED : TextStyle.WINDOW);
|
||||||
}
|
|
||||||
// For regular settings like 'Gamepad support', create a label and determine if it is selected.
|
|
||||||
const valueLabel = addTextObject(this.scene, 0, 0, option, this.settingDeviceDefaults[this.settingDevice[setting]] === o ? TextStyle.SETTINGS_SELECTED : TextStyle.WINDOW);
|
|
||||||
valueLabel.setOrigin(0, 0);
|
valueLabel.setOrigin(0, 0);
|
||||||
|
|
||||||
optionsContainer.add(valueLabel);
|
this.optionsContainer.add(valueLabel);
|
||||||
|
|
||||||
//if a setting has 2 options, valueLabels will be an array of 2 elements
|
return valueLabel;
|
||||||
valueLabels.push(valueLabel);
|
}));
|
||||||
}
|
|
||||||
// Collect all option labels for this setting into the main array.
|
|
||||||
optionValueLabels.push(valueLabels);
|
|
||||||
|
|
||||||
// Calculate the total width of all option labels within a specific setting
|
const totalWidth = this.optionValueLabels[s].map(o => o.width).reduce((total, width) => total += width, 0);
|
||||||
// This is achieved by summing the width of each option label
|
|
||||||
const totalWidth = optionValueLabels[s].map((o) => (o as Phaser.GameObjects.Text).width).reduce((total, width) => total += width, 0);
|
|
||||||
|
|
||||||
// Define the minimum width for a label, ensuring it's at least 78 pixels wide or the width of the setting label plus some padding
|
const labelWidth = Math.max(78, this.settingLabels[s].displayWidth + 8);
|
||||||
const labelWidth = Math.max(130, settingLabels[s].displayWidth + 8);
|
|
||||||
|
|
||||||
// Calculate the total available space for placing option labels next to their setting label
|
|
||||||
// We reserve space for the setting label and then distribute the remaining space evenly
|
|
||||||
const totalSpace = (300 - labelWidth) - totalWidth / 6;
|
const totalSpace = (300 - labelWidth) - totalWidth / 6;
|
||||||
// Calculate the spacing between options based on the available space divided by the number of gaps between labels
|
const optionSpacing = Math.floor(totalSpace / (this.optionValueLabels[s].length - 1));
|
||||||
const optionSpacing = Math.floor(totalSpace / (optionValueLabels[s].length - 1));
|
|
||||||
|
|
||||||
// Initialize xOffset to zero, which will be used to position each option label horizontally
|
|
||||||
let xOffset = 0;
|
let xOffset = 0;
|
||||||
|
|
||||||
// Start positioning each option label one by one
|
for (const value of this.optionValueLabels[s]) {
|
||||||
for (const value of optionValueLabels[s]) {
|
value.setPositionRelative(this.settingLabels[s], labelWidth + xOffset, 0);
|
||||||
// Set the option label's position right next to the setting label, adjusted by xOffset
|
xOffset += value.width / 6 + optionSpacing;
|
||||||
(value as Phaser.GameObjects.Text).setPositionRelative(settingLabels[s], labelWidth + xOffset, 0);
|
|
||||||
// Move the xOffset to the right for the next label, ensuring each label is spaced evenly
|
|
||||||
xOffset += (value as Phaser.GameObjects.Text).width / 6 + optionSpacing;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assigning the newly created components to the layout map under the specific gamepad type.
|
this.optionCursors = this.settings.map(setting => setting.default);
|
||||||
this.layout[config.padType].optionsContainer = optionsContainer; // Container for this pad's options.
|
|
||||||
this.layout[config.padType].inputsIcons = inputsIcons; // Icons for each input specific to this pad.
|
this.settingsContainer.add(this.optionsBg);
|
||||||
this.layout[config.padType].settingLabels = settingLabels; // Text labels for each setting available on this pad.
|
this.settingsContainer.add(this.navigationContainer);
|
||||||
this.layout[config.padType].optionValueLabels = optionValueLabels; // Labels for values corresponding to each setting.
|
this.settingsContainer.add(actionsBg);
|
||||||
this.layout[config.padType].optionCursors = optionCursors; // Cursors to navigate through the options.
|
this.settingsContainer.add(this.optionsContainer);
|
||||||
this.layout[config.padType].keys = specificBindingKeys; // Keys that identify each setting specifically bound to this pad.
|
this.settingsContainer.add(iconAction);
|
||||||
this.layout[config.padType].bindingSettings = bindingSettings; // Settings that define how the keys are bound.
|
this.settingsContainer.add(iconCancel);
|
||||||
|
this.settingsContainer.add(actionText);
|
||||||
|
this.settingsContainer.add(cancelText);
|
||||||
|
|
||||||
// Add the options container to the overall settings container to be displayed in the UI.
|
|
||||||
this.settingsContainer.add(optionsContainer);
|
|
||||||
}
|
|
||||||
// Add the settings container to the UI.
|
|
||||||
ui.add(this.settingsContainer);
|
ui.add(this.settingsContainer);
|
||||||
|
|
||||||
// Initially hide the settings container until needed (e.g., when a gamepad is connected or a button is pressed).
|
this.setCursor(0);
|
||||||
|
this.setScrollCursor(0);
|
||||||
|
|
||||||
this.settingsContainer.setVisible(false);
|
this.settingsContainer.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the bindings for the current active device configuration.
|
* Update the bindings for the current active device configuration.
|
||||||
*/
|
*/
|
||||||
updateBindings(): void {
|
updateBindings(): void {
|
||||||
// Hide the options container for all layouts to reset the UI visibility.
|
|
||||||
Object.keys(this.layout).forEach((key) => this.layout[key].optionsContainer.setVisible(false));
|
|
||||||
// Fetch the active gamepad configuration from the input controller.
|
|
||||||
const activeConfig = this.getActiveConfig();
|
|
||||||
|
|
||||||
// Set the UI layout for the active configuration. If unsuccessful, exit the function early.
|
|
||||||
if (!this.setLayout(activeConfig)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
|
||||||
const settings: object = this.getLocalStorageSetting();
|
|
||||||
|
|
||||||
// Update the cursor for each key based on the stored settings or default cursors.
|
|
||||||
this.keys.forEach((key, index) => {
|
|
||||||
this.setOptionCursor(index, settings.hasOwnProperty(key as string) ? settings[key as string] : this.optionCursors[index]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the active configuration has no custom bindings set, exit the function early.
|
|
||||||
// by default, if custom does not exists, a default is assigned to it
|
|
||||||
// it only means the gamepad is not yet initalized
|
|
||||||
if (!activeConfig.custom) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each element in the binding settings, update the icon according to the current assignment.
|
|
||||||
for (const elm of this.bindingSettings) {
|
|
||||||
const icon = getIconWithSettingName(activeConfig, elm);
|
|
||||||
if (icon) {
|
|
||||||
this.inputsIcons[elm as string].setFrame(icon);
|
|
||||||
this.inputsIcons[elm as string].alpha = 1;
|
|
||||||
} else {
|
|
||||||
this.inputsIcons[elm as string].alpha = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the cursor and scroll cursor to their initial positions.
|
|
||||||
this.setCursor(this.cursor);
|
|
||||||
this.setScrollCursor(this.scrollCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNavigationDisplay() {
|
|
||||||
const specialIcons = {
|
|
||||||
"BUTTON_HOME": "HOME.png",
|
|
||||||
"BUTTON_DELETE": "DEL.png",
|
|
||||||
};
|
|
||||||
for (const settingName of Object.keys(this.navigationIcons)) {
|
for (const settingName of Object.keys(this.navigationIcons)) {
|
||||||
if (Object.keys(specialIcons).includes(settingName)) {
|
if (settingName === "BUTTON_HOME") {
|
||||||
this.navigationIcons[settingName].setTexture("keyboard");
|
this.navigationIcons[settingName].setTexture("keyboard");
|
||||||
this.navigationIcons[settingName].setFrame(specialIcons[settingName]);
|
this.navigationIcons[settingName].setFrame("HOME.png");
|
||||||
this.navigationIcons[settingName].alpha = 1;
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -324,6 +165,7 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
this.navigationIcons[settingName].alpha = 0;
|
this.navigationIcons[settingName].alpha = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,102 +176,50 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
*/
|
*/
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
super.show(args);
|
super.show(args);
|
||||||
|
|
||||||
this.updateNavigationDisplay();
|
|
||||||
NavigationManager.getInstance().updateIcons();
|
|
||||||
// Update the bindings for the current active gamepad configuration.
|
|
||||||
this.updateBindings();
|
this.updateBindings();
|
||||||
|
|
||||||
// Make the settings container visible to the user.
|
const settings: object = localStorage.hasOwnProperty(this.localStorageKey) ? JSON.parse(localStorage.getItem(this.localStorageKey)) : {};
|
||||||
this.settingsContainer.setVisible(true);
|
|
||||||
// Reset the scroll cursor to the top of the settings container.
|
this.settings.forEach((setting, s) => this.setOptionCursor(s, settings.hasOwnProperty(setting.key) ? settings[setting.key] : this.settings[s].default));
|
||||||
this.resetScroll();
|
|
||||||
|
this.settingsContainer.setVisible(true);
|
||||||
|
this.setCursor(0);
|
||||||
|
|
||||||
// Move the settings container to the end of the UI stack to ensure it is displayed on top.
|
|
||||||
this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1);
|
this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1);
|
||||||
|
|
||||||
// Hide any tooltips that might be visible before showing the settings container.
|
|
||||||
this.getUi().hideTooltip();
|
this.getUi().hideTooltip();
|
||||||
|
|
||||||
// Return true to indicate the UI was successfully shown.
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the UI layout for the active device configuration.
|
* Processes input from a specified button.
|
||||||
|
* This method handles navigation through a UI menu, including movement through menu items
|
||||||
|
* and handling special actions like cancellation. Each button press may adjust the cursor
|
||||||
|
* position or the menu scroll, and plays a sound effect if the action was successful.
|
||||||
*
|
*
|
||||||
* @param activeConfig - The active device configuration.
|
* @param button - The button pressed by the user.
|
||||||
* @returns `true` if the layout was successfully applied, otherwise `false`.
|
* @returns `true` if the action associated with the button was successfully processed, `false` otherwise.
|
||||||
*/
|
|
||||||
setLayout(activeConfig: InterfaceConfig): boolean {
|
|
||||||
// Check if there is no active configuration (e.g., no gamepad connected).
|
|
||||||
if (!activeConfig) {
|
|
||||||
// Retrieve the layout for when no gamepads are connected.
|
|
||||||
const layout = this.layout["noGamepads"];
|
|
||||||
// Make the options container visible to show message.
|
|
||||||
layout.optionsContainer.setVisible(true);
|
|
||||||
// Return false indicating the layout application was not successful due to lack of gamepad.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Extract the type of the gamepad from the active configuration.
|
|
||||||
const configType = activeConfig.padType;
|
|
||||||
|
|
||||||
// Retrieve the layout settings based on the type of the gamepad.
|
|
||||||
const layout = this.layout[configType];
|
|
||||||
// Update the main controller with configuration details from the selected layout.
|
|
||||||
this.keys = layout.keys;
|
|
||||||
this.optionsContainer = layout.optionsContainer;
|
|
||||||
this.optionsContainer.setVisible(true);
|
|
||||||
this.settingLabels = layout.settingLabels;
|
|
||||||
this.optionValueLabels = layout.optionValueLabels;
|
|
||||||
this.optionCursors = layout.optionCursors;
|
|
||||||
this.inputsIcons = layout.inputsIcons;
|
|
||||||
this.bindingSettings = layout.bindingSettings;
|
|
||||||
|
|
||||||
// Return true indicating the layout was successfully applied.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process the input for the given button.
|
|
||||||
*
|
|
||||||
* @param button - The button to process.
|
|
||||||
* @returns `true` if the input was processed successfully.
|
|
||||||
*/
|
*/
|
||||||
processInput(button: Button): boolean {
|
processInput(button: Button): boolean {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
// Defines the maximum number of rows that can be displayed on the screen.
|
// Defines the maximum number of rows that can be displayed on the screen.
|
||||||
let success = false;
|
|
||||||
this.updateNavigationDisplay();
|
|
||||||
|
|
||||||
// Handle the input based on the button pressed.
|
let success = false;
|
||||||
|
|
||||||
if (button === Button.CANCEL) {
|
if (button === Button.CANCEL) {
|
||||||
// Handle cancel button press, reverting UI mode to previous state.
|
|
||||||
success = true;
|
success = true;
|
||||||
NavigationManager.getInstance().reset();
|
NavigationManager.getInstance().reset();
|
||||||
|
// Reverts UI to its previous state on cancel.
|
||||||
this.scene.ui.revertMode();
|
this.scene.ui.revertMode();
|
||||||
} else {
|
} else {
|
||||||
const cursor = this.cursor + this.scrollCursor; // Calculate the absolute cursor position.
|
const cursor = this.cursor + this.scrollCursor;
|
||||||
const setting = this.settingDevice[Object.keys(this.settingDevice)[cursor]];
|
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case Button.ACTION:
|
case Button.UP:
|
||||||
if (!this.optionCursors || !this.optionValueLabels) {
|
if (cursor) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.settingBlacklisted.includes(setting) || !setting.includes("BUTTON_")) {
|
|
||||||
success = false;
|
|
||||||
} else {
|
|
||||||
success = this.setSetting(this.scene, setting, 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button.UP: // Move up in the menu.
|
|
||||||
if (!this.optionValueLabels) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (cursor) { // If not at the top, move the cursor up.
|
|
||||||
if (this.cursor) {
|
if (this.cursor) {
|
||||||
success = this.setCursor(this.cursor - 1);
|
success = this.setCursor(this.cursor - 1);
|
||||||
} else {// If at the top of the visible items, scroll up.
|
} else {
|
||||||
success = this.setScrollCursor(this.scrollCursor - 1);
|
success = this.setScrollCursor(this.scrollCursor - 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -441,12 +231,9 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
success = successA && successB; // success is just there to play the little validation sound effect
|
success = successA && successB; // success is just there to play the little validation sound effect
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.DOWN: // Move down in the menu.
|
case Button.DOWN:
|
||||||
if (!this.optionValueLabels) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (cursor < this.optionValueLabels.length - 1) {
|
if (cursor < this.optionValueLabels.length - 1) {
|
||||||
if (this.cursor < this.rowsToDisplay - 1) {
|
if (this.cursor < this.rowsToDisplay - 1) {// if the visual cursor is in the frame of 0 to 8
|
||||||
success = this.setCursor(this.cursor + 1);
|
success = this.setCursor(this.cursor + 1);
|
||||||
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
||||||
success = this.setScrollCursor(this.scrollCursor + 1);
|
success = this.setScrollCursor(this.scrollCursor + 1);
|
||||||
@ -460,23 +247,14 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
success = successA && successB; // Indicates a successful cursor and scroll adjustment.
|
success = successA && successB; // Indicates a successful cursor and scroll adjustment.
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.LEFT: // Move selection left within the current option set.
|
case Button.LEFT:
|
||||||
if (!this.optionCursors || !this.optionValueLabels) {
|
if (this.optionCursors[cursor]) {// Moves the option cursor left, if possible.
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
|
||||||
success = false;
|
|
||||||
} else if (this.optionCursors[cursor]) {
|
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.RIGHT: // Move selection right within the current option set.
|
case Button.RIGHT:
|
||||||
if (!this.optionCursors || !this.optionValueLabels) {
|
// Moves the option cursor right, if possible.
|
||||||
return;
|
if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
|
||||||
}
|
|
||||||
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
|
||||||
success = false;
|
|
||||||
} else if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
|
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -487,21 +265,12 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a change occurred, play the selection sound.
|
// Plays a select sound effect if an action was successfully processed.
|
||||||
if (success) {
|
if (success) {
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
}
|
}
|
||||||
|
|
||||||
return success; // Return whether the input resulted in a successful action.
|
return success;
|
||||||
}
|
|
||||||
|
|
||||||
resetScroll() {
|
|
||||||
this.cursorObj?.destroy();
|
|
||||||
this.cursorObj = null;
|
|
||||||
this.cursor = null;
|
|
||||||
this.setCursor(0);
|
|
||||||
this.setScrollCursor(0);
|
|
||||||
this.updateSettingsScroll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -512,46 +281,16 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
*/
|
*/
|
||||||
setCursor(cursor: integer): boolean {
|
setCursor(cursor: integer): boolean {
|
||||||
const ret = super.setCursor(cursor);
|
const ret = super.setCursor(cursor);
|
||||||
// If the optionsContainer is not initialized, return the result from the parent class directly.
|
|
||||||
if (!this.optionsContainer) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the cursor object exists, if not, create it.
|
|
||||||
if (!this.cursorObj) {
|
if (!this.cursorObj) {
|
||||||
this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1);
|
this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1);
|
||||||
this.cursorObj.setOrigin(0, 0); // Set the origin to the top-left corner.
|
this.cursorObj.setOrigin(0, 0);
|
||||||
this.optionsContainer.add(this.cursorObj); // Add the cursor to the options container.
|
this.optionsContainer.add(this.cursorObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the position of the cursor object relative to the options background based on the current cursor and scroll positions.
|
|
||||||
this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16);
|
this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16);
|
||||||
|
|
||||||
return ret; // Return the result from the parent class's setCursor method.
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the scroll cursor to the specified position.
|
|
||||||
*
|
|
||||||
* @param scrollCursor - The scroll cursor position to set.
|
|
||||||
* @returns `true` if the scroll cursor was set successfully.
|
|
||||||
*/
|
|
||||||
setScrollCursor(scrollCursor: integer): boolean {
|
|
||||||
// Check if the new scroll position is the same as the current one; if so, do not update.
|
|
||||||
if (scrollCursor === this.scrollCursor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the internal scroll cursor state
|
|
||||||
this.scrollCursor = scrollCursor;
|
|
||||||
|
|
||||||
// Apply the new scroll position to the settings UI.
|
|
||||||
this.updateSettingsScroll();
|
|
||||||
|
|
||||||
// Reset the cursor to its current position to adjust its visibility after scrolling.
|
|
||||||
this.setCursor(this.cursor);
|
|
||||||
|
|
||||||
return true; // Return true to indicate the scroll cursor was successfully updated.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -563,54 +302,63 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
* @returns `true` if the option cursor was set successfully.
|
* @returns `true` if the option cursor was set successfully.
|
||||||
*/
|
*/
|
||||||
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
||||||
// Retrieve the specific setting using the settingIndex from the settingDevice enumeration.
|
const setting = this.settings[settingIndex];
|
||||||
const setting = this.settingDevice[Object.keys(this.settingDevice)[settingIndex]];
|
|
||||||
|
if (setting.key === SettingKeys.Touch_Controls && cursor && hasTouchscreen() && isMobile()) {
|
||||||
|
this.getUi().playError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current cursor position for this setting.
|
|
||||||
const lastCursor = this.optionCursors[settingIndex];
|
const lastCursor = this.optionCursors[settingIndex];
|
||||||
|
|
||||||
// Check if the setting is not part of the bindings (i.e., it's a regular setting).
|
|
||||||
if (!this.bindingSettings.includes(setting) && !setting.includes("BUTTON_")) {
|
|
||||||
// Get the label of the last selected option and revert its color to the default.
|
|
||||||
const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor];
|
const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor];
|
||||||
lastValueLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
lastValueLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
||||||
lastValueLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
lastValueLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
||||||
|
|
||||||
// Update the cursor for the setting to the new position.
|
|
||||||
this.optionCursors[settingIndex] = cursor;
|
this.optionCursors[settingIndex] = cursor;
|
||||||
|
|
||||||
// Change the color of the new selected option to indicate it's selected.
|
|
||||||
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
||||||
newValueLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
newValueLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||||
newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||||
}
|
|
||||||
|
|
||||||
// If the save flag is set, save the setting to local storage
|
|
||||||
if (save) {
|
if (save) {
|
||||||
this.saveSettingToLocalStorage(setting, cursor);
|
this.scene.gameData.saveSetting(setting.key, cursor);
|
||||||
|
if (this.reloadSettings.includes(setting)) {
|
||||||
|
this.reloadRequired = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // Return true to indicate the cursor was successfully updated.
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the scroll cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param scrollCursor - The scroll cursor position to set.
|
||||||
|
* @returns `true` if the scroll cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setScrollCursor(scrollCursor: integer): boolean {
|
||||||
|
if (scrollCursor === this.scrollCursor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollCursor = scrollCursor;
|
||||||
|
|
||||||
|
this.updateSettingsScroll();
|
||||||
|
|
||||||
|
this.setCursor(this.cursor);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the scroll position of the settings UI.
|
* Update the scroll position of the settings UI.
|
||||||
*/
|
*/
|
||||||
updateSettingsScroll(): void {
|
updateSettingsScroll(): void {
|
||||||
// Return immediately if the options container is not initialized.
|
|
||||||
if (!this.optionsContainer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the vertical position of the options container based on the current scroll cursor, multiplying by the item height.
|
|
||||||
this.optionsContainer.setY(-16 * this.scrollCursor);
|
this.optionsContainer.setY(-16 * this.scrollCursor);
|
||||||
|
|
||||||
// Iterate over all setting labels to update their visibility.
|
|
||||||
for (let s = 0; s < this.settingLabels.length; s++) {
|
for (let s = 0; s < this.settingLabels.length; s++) {
|
||||||
// Determine if the current setting should be visible based on the scroll position.
|
|
||||||
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
||||||
|
|
||||||
// Set the visibility of the setting label and its corresponding options.
|
|
||||||
this.settingLabels[s].setVisible(visible);
|
this.settingLabels[s].setVisible(visible);
|
||||||
for (const option of this.optionValueLabels[s]) {
|
for (const option of this.optionValueLabels[s]) {
|
||||||
option.setVisible(visible);
|
option.setVisible(visible);
|
||||||
@ -621,27 +369,23 @@ export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
|||||||
/**
|
/**
|
||||||
* Clear the UI elements and state.
|
* Clear the UI elements and state.
|
||||||
*/
|
*/
|
||||||
clear(): void {
|
clear() {
|
||||||
super.clear();
|
super.clear();
|
||||||
|
|
||||||
// Hide the settings container to remove it from the view.
|
|
||||||
this.settingsContainer.setVisible(false);
|
this.settingsContainer.setVisible(false);
|
||||||
|
|
||||||
// Remove the cursor from the UI.
|
|
||||||
this.eraseCursor();
|
this.eraseCursor();
|
||||||
|
if (this.reloadRequired) {
|
||||||
|
this.reloadRequired = false;
|
||||||
|
this.scene.reset(true, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erase the cursor from the UI.
|
* Erase the cursor from the UI.
|
||||||
*/
|
*/
|
||||||
eraseCursor(): void {
|
eraseCursor() {
|
||||||
// Check if a cursor object exists.
|
|
||||||
if (this.cursorObj) {
|
if (this.cursorObj) {
|
||||||
this.cursorObj.destroy();
|
this.cursorObj.destroy();
|
||||||
} // Destroy the cursor object to clean up resources.
|
}
|
||||||
|
|
||||||
// Set the cursor object reference to null to fully dereference it.
|
|
||||||
this.cursorObj = null;
|
this.cursorObj = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import {Mode} from "#app/ui/ui";
|
import {Mode} from "#app/ui/ui";
|
||||||
import {InputsIcons} from "#app/ui/settings/abstract-settings-ui-handler";
|
import {InputsIcons} from "#app/ui/settings/abstract-control-settings-ui-handler.js";
|
||||||
import {addTextObject, setTextStyle, TextStyle} from "#app/ui/text";
|
import {addTextObject, setTextStyle, TextStyle} from "#app/ui/text";
|
||||||
import {addWindow} from "#app/ui/ui-theme";
|
import {addWindow} from "#app/ui/ui-theme";
|
||||||
import {Button} from "#app/enums/buttons";
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
|
const LEFT = "LEFT";
|
||||||
|
const RIGHT = "RIGHT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages navigation and menus tabs within the setting menu.
|
* Manages navigation and menus tabs within the setting menu.
|
||||||
*/
|
*/
|
||||||
@ -24,14 +27,16 @@ export class NavigationManager {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.modes = [
|
this.modes = [
|
||||||
Mode.SETTINGS,
|
Mode.SETTINGS,
|
||||||
|
Mode.SETTINGS_ACCESSIBILITY,
|
||||||
Mode.SETTINGS_GAMEPAD,
|
Mode.SETTINGS_GAMEPAD,
|
||||||
Mode.SETTINGS_KEYBOARD,
|
Mode.SETTINGS_KEYBOARD,
|
||||||
];
|
];
|
||||||
this.labels = ["General", "Gamepad", "Keyboard"];
|
this.labels = ["General", "Accessibility", "Gamepad", "Keyboard"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset() {
|
public reset() {
|
||||||
this.selectedMode = Mode.SETTINGS;
|
this.selectedMode = Mode.SETTINGS;
|
||||||
|
this.updateNavigationMenus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,32 +51,20 @@ export class NavigationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the previous mode in the modes array.
|
* Navigates modes based on given direction
|
||||||
* @param scene The current BattleScene instance.
|
* @param scene The current BattleScene instance
|
||||||
|
* @param direction LEFT or RIGHT
|
||||||
*/
|
*/
|
||||||
public navigateLeft(scene) {
|
public navigate(scene, direction) {
|
||||||
const pos = this.modes.indexOf(this.selectedMode);
|
const pos = this.modes.indexOf(this.selectedMode);
|
||||||
const maxPos = this.modes.length - 1;
|
const maxPos = this.modes.length - 1;
|
||||||
if (pos === 0) {
|
const increment = direction === LEFT ? -1 : 1;
|
||||||
|
if (pos === 0 && direction === LEFT) {
|
||||||
this.selectedMode = this.modes[maxPos];
|
this.selectedMode = this.modes[maxPos];
|
||||||
} else {
|
} else if (pos === maxPos && direction === RIGHT) {
|
||||||
this.selectedMode = this.modes[pos - 1];
|
|
||||||
}
|
|
||||||
scene.ui.setMode(this.selectedMode);
|
|
||||||
this.updateNavigationMenus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigates to the next mode in the modes array.
|
|
||||||
* @param scene The current BattleScene instance.
|
|
||||||
*/
|
|
||||||
public navigateRight(scene) {
|
|
||||||
const pos = this.modes.indexOf(this.selectedMode);
|
|
||||||
const maxPos = this.modes.length - 1;
|
|
||||||
if (pos === maxPos) {
|
|
||||||
this.selectedMode = this.modes[0];
|
this.selectedMode = this.modes[0];
|
||||||
} else {
|
} else {
|
||||||
this.selectedMode = this.modes[pos + 1];
|
this.selectedMode = this.modes[pos + increment];
|
||||||
}
|
}
|
||||||
scene.ui.setMode(this.selectedMode);
|
scene.ui.setMode(this.selectedMode);
|
||||||
this.updateNavigationMenus();
|
this.updateNavigationMenus();
|
||||||
@ -204,13 +197,11 @@ export default class NavigationMenu extends Phaser.GameObjects.Container {
|
|||||||
const navigationManager = NavigationManager.getInstance();
|
const navigationManager = NavigationManager.getInstance();
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case Button.CYCLE_FORM:
|
case Button.CYCLE_FORM:
|
||||||
navigationManager.navigateLeft(this.scene);
|
navigationManager.navigate(this.scene, LEFT);
|
||||||
return true;
|
return true;
|
||||||
break;
|
|
||||||
case Button.CYCLE_SHINY:
|
case Button.CYCLE_SHINY:
|
||||||
navigationManager.navigateRight(this.scene);
|
navigationManager.navigate(this.scene, RIGHT);
|
||||||
return true;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
20
src/ui/settings/settings-accessiblity-ui-handler.ts
Normal file
20
src/ui/settings/settings-accessiblity-ui-handler.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import { Mode } from "../ui";
|
||||||
|
"#app/inputs-controller.js";
|
||||||
|
import AbstractSettingsUiHandler from "./abstract-settings-ui-handler";
|
||||||
|
import { Setting, SettingType } from "#app/system/settings/settings";
|
||||||
|
|
||||||
|
export default class SettingsAccessibilityUiHandler extends AbstractSettingsUiHandler {
|
||||||
|
/**
|
||||||
|
* Creates an instance of SettingsGamepadUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode, optional.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.title = "Accessibility";
|
||||||
|
this.settings = Setting.filter(s => s.type === SettingType.ACCESSIBILITY);
|
||||||
|
this.localStorageKey = "settings";
|
||||||
|
}
|
||||||
|
}
|
@ -7,22 +7,22 @@ import {
|
|||||||
settingGamepadBlackList,
|
settingGamepadBlackList,
|
||||||
settingGamepadDefaults,
|
settingGamepadDefaults,
|
||||||
settingGamepadOptions
|
settingGamepadOptions
|
||||||
} from "../../system/settings-gamepad";
|
} from "../../system/settings/settings-gamepad";
|
||||||
import pad_xbox360 from "#app/configs/inputs/pad_xbox360";
|
import pad_xbox360 from "#app/configs/inputs/pad_xbox360";
|
||||||
import pad_dualshock from "#app/configs/inputs/pad_dualshock";
|
import pad_dualshock from "#app/configs/inputs/pad_dualshock";
|
||||||
import pad_unlicensedSNES from "#app/configs/inputs/pad_unlicensedSNES";
|
import pad_unlicensedSNES from "#app/configs/inputs/pad_unlicensedSNES";
|
||||||
import {InterfaceConfig} from "#app/inputs-controller";
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
import AbstractSettingsUiUiHandler from "#app/ui/settings/abstract-settings-ui-handler";
|
import AbstractControlSettingsUiHandler from "#app/ui/settings/abstract-control-settings-ui-handler.js";
|
||||||
import {Device} from "#app/enums/devices";
|
import {Device} from "#app/enums/devices";
|
||||||
import {truncateString} from "#app/utils";
|
import {truncateString} from "#app/utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the settings UI handler for gamepads.
|
* Class representing the settings UI handler for gamepads.
|
||||||
*
|
*
|
||||||
* @extends AbstractSettingsUiUiHandler
|
* @extends AbstractControlSettingsUiHandler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandler {
|
export default class SettingsGamepadUiHandler extends AbstractControlSettingsUiHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of SettingsGamepadUiHandler.
|
* Creates an instance of SettingsGamepadUiHandler.
|
||||||
@ -33,18 +33,17 @@ export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandle
|
|||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
this.titleSelected = "Gamepad";
|
this.titleSelected = "Gamepad";
|
||||||
this.settingDevice = SettingGamepad;
|
this.setting = SettingGamepad;
|
||||||
this.settingDeviceDefaults = settingGamepadDefaults;
|
this.settingDeviceDefaults = settingGamepadDefaults;
|
||||||
this.settingDeviceOptions = settingGamepadOptions;
|
this.settingDeviceOptions = settingGamepadOptions;
|
||||||
this.configs = [pad_xbox360, pad_dualshock, pad_unlicensedSNES];
|
this.configs = [pad_xbox360, pad_dualshock, pad_unlicensedSNES];
|
||||||
this.commonSettingsCount = 2;
|
this.commonSettingsCount = 2;
|
||||||
this.localStoragePropertyName = "settingsGamepad";
|
this.localStoragePropertyName = "settingsGamepad";
|
||||||
this.settingBlacklisted = settingGamepadBlackList;
|
this.settingBlacklisted = settingGamepadBlackList;
|
||||||
|
this.device = Device.GAMEPAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSetting(scene: BattleScene, setting, value: integer): boolean {
|
setSetting = setSettingGamepad;
|
||||||
return setSettingGamepad(scene, setting, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup UI elements.
|
* Setup UI elements.
|
||||||
@ -65,26 +64,6 @@ export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandle
|
|||||||
this.layout["noGamepads"].label = label;
|
this.layout["noGamepads"].label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the active configuration.
|
|
||||||
*
|
|
||||||
* @returns The active gamepad configuration.
|
|
||||||
*/
|
|
||||||
getActiveConfig(): InterfaceConfig {
|
|
||||||
return this.scene.inputController.getActiveConfig(Device.GAMEPAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the gamepad settings from local storage.
|
|
||||||
*
|
|
||||||
* @returns The gamepad settings from local storage.
|
|
||||||
*/
|
|
||||||
getLocalStorageSetting(): object {
|
|
||||||
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
|
||||||
const settings: object = localStorage.hasOwnProperty("settingsGamepad") ? JSON.parse(localStorage.getItem("settingsGamepad")) : {};
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the layout for the active configuration.
|
* Set the layout for the active configuration.
|
||||||
*
|
*
|
||||||
@ -105,27 +84,6 @@ export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandle
|
|||||||
return super.setLayout(activeConfig);
|
return super.setLayout(activeConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate to the left menu tab.
|
|
||||||
*
|
|
||||||
* @returns `true` indicating the navigation was successful.
|
|
||||||
*/
|
|
||||||
navigateMenuLeft(): boolean {
|
|
||||||
this.scene.ui.setMode(Mode.SETTINGS);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate to the right menu tab.
|
|
||||||
*
|
|
||||||
* @returns `true` indicating the navigation was successful.
|
|
||||||
*/
|
|
||||||
navigateMenuRight(): boolean {
|
|
||||||
this.scene.ui.setMode(Mode.SETTINGS_KEYBOARD);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the display of the chosen gamepad.
|
* Update the display of the chosen gamepad.
|
||||||
*/
|
*/
|
||||||
@ -135,11 +93,11 @@ export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandle
|
|||||||
this.resetScroll();
|
this.resetScroll();
|
||||||
|
|
||||||
// Iterate over the keys in the settingDevice enumeration.
|
// Iterate over the keys in the settingDevice enumeration.
|
||||||
for (const [index, key] of Object.keys(this.settingDevice).entries()) {
|
for (const [index, key] of Object.keys(this.setting).entries()) {
|
||||||
const setting = this.settingDevice[key]; // Get the actual setting value using the key.
|
const setting = this.setting[key]; // Get the actual setting value using the key.
|
||||||
|
|
||||||
// Check if the current setting corresponds to the controller setting.
|
// Check if the current setting corresponds to the controller setting.
|
||||||
if (setting === this.settingDevice.Controller) {
|
if (setting === this.setting.Controller) {
|
||||||
// Iterate over all layouts excluding the 'noGamepads' special case.
|
// Iterate over all layouts excluding the 'noGamepads' special case.
|
||||||
for (const _key of Object.keys(this.layout)) {
|
for (const _key of Object.keys(this.layout)) {
|
||||||
if (_key === "noGamepads") {
|
if (_key === "noGamepads") {
|
||||||
@ -157,12 +115,12 @@ export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandle
|
|||||||
/**
|
/**
|
||||||
* Save the setting to local storage.
|
* Save the setting to local storage.
|
||||||
*
|
*
|
||||||
* @param setting - The setting to save.
|
* @param settingName - The setting to save.
|
||||||
* @param cursor - The cursor position to save.
|
* @param cursor - The cursor position to save.
|
||||||
*/
|
*/
|
||||||
saveSettingToLocalStorage(setting, cursor): void {
|
saveSettingToLocalStorage(settingName, cursor): void {
|
||||||
if (this.settingDevice[setting] !== this.settingDevice.Controller) {
|
if (this.setting[settingName] !== this.setting.Controller) {
|
||||||
this.scene.gameData.saveGamepadSetting(setting, cursor);
|
this.scene.gameData.saveControlSetting(this.device, this.localStoragePropertyName, settingName, this.settingDeviceDefaults, cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import {
|
|||||||
settingKeyboardBlackList,
|
settingKeyboardBlackList,
|
||||||
settingKeyboardDefaults,
|
settingKeyboardDefaults,
|
||||||
settingKeyboardOptions
|
settingKeyboardOptions
|
||||||
} from "#app/system/settings-keyboard";
|
} from "#app/system/settings/settings-keyboard";
|
||||||
import {reverseValueToKeySetting, truncateString} from "#app/utils";
|
import {reverseValueToKeySetting, truncateString} from "#app/utils";
|
||||||
import AbstractSettingsUiUiHandler from "#app/ui/settings/abstract-settings-ui-handler";
|
import AbstractControlSettingsUiHandler from "#app/ui/settings/abstract-control-settings-ui-handler.js";
|
||||||
import {InterfaceConfig} from "#app/inputs-controller";
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
import {addTextObject, TextStyle} from "#app/ui/text";
|
import {addTextObject, TextStyle} from "#app/ui/text";
|
||||||
import {deleteBind} from "#app/configs/inputs/configHandler";
|
import {deleteBind} from "#app/configs/inputs/configHandler";
|
||||||
@ -19,9 +19,9 @@ import {NavigationManager} from "#app/ui/settings/navigationMenu";
|
|||||||
/**
|
/**
|
||||||
* Class representing the settings UI handler for keyboards.
|
* Class representing the settings UI handler for keyboards.
|
||||||
*
|
*
|
||||||
* @extends AbstractSettingsUiUiHandler
|
* @extends AbstractControlSettingsUiHandler
|
||||||
*/
|
*/
|
||||||
export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandler {
|
export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUiHandler {
|
||||||
/**
|
/**
|
||||||
* Creates an instance of SettingsKeyboardUiHandler.
|
* Creates an instance of SettingsKeyboardUiHandler.
|
||||||
*
|
*
|
||||||
@ -31,7 +31,7 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
this.titleSelected = "Keyboard";
|
this.titleSelected = "Keyboard";
|
||||||
this.settingDevice = SettingKeyboard;
|
this.setting = SettingKeyboard;
|
||||||
this.settingDeviceDefaults = settingKeyboardDefaults;
|
this.settingDeviceDefaults = settingKeyboardDefaults;
|
||||||
this.settingDeviceOptions = settingKeyboardOptions;
|
this.settingDeviceOptions = settingKeyboardOptions;
|
||||||
this.configs = [cfg_keyboard_qwerty];
|
this.configs = [cfg_keyboard_qwerty];
|
||||||
@ -39,6 +39,7 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
this.textureOverride = "keyboard";
|
this.textureOverride = "keyboard";
|
||||||
this.localStoragePropertyName = "settingsKeyboard";
|
this.localStoragePropertyName = "settingsKeyboard";
|
||||||
this.settingBlacklisted = settingKeyboardBlackList;
|
this.settingBlacklisted = settingKeyboardBlackList;
|
||||||
|
this.device = Device.KEYBOARD;
|
||||||
|
|
||||||
const deleteEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DELETE);
|
const deleteEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DELETE);
|
||||||
const restoreDefaultEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.HOME);
|
const restoreDefaultEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.HOME);
|
||||||
@ -46,9 +47,7 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
restoreDefaultEvent.on("up", this.onHomeDown, this);
|
restoreDefaultEvent.on("up", this.onHomeDown, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSetting(scene: BattleScene, setting, value: integer): boolean {
|
setSetting = setSettingKeyboard;
|
||||||
return setSettingKeyboard(scene, setting, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup UI elements.
|
* Setup UI elements.
|
||||||
@ -114,26 +113,6 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the active configuration.
|
|
||||||
*
|
|
||||||
* @returns The active keyboard configuration.
|
|
||||||
*/
|
|
||||||
getActiveConfig(): InterfaceConfig {
|
|
||||||
return this.scene.inputController.getActiveConfig(Device.KEYBOARD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the keyboard settings from local storage.
|
|
||||||
*
|
|
||||||
* @returns The keyboard settings from local storage.
|
|
||||||
*/
|
|
||||||
getLocalStorageSetting(): object {
|
|
||||||
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
|
||||||
const settings: object = localStorage.hasOwnProperty("settingsKeyboard") ? JSON.parse(localStorage.getItem("settingsKeyboard")) : {};
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the layout for the active configuration.
|
* Set the layout for the active configuration.
|
||||||
*
|
*
|
||||||
@ -154,26 +133,6 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
return super.setLayout(activeConfig);
|
return super.setLayout(activeConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate to the left menu tab.
|
|
||||||
*
|
|
||||||
* @returns `true` indicating the navigation was successful.
|
|
||||||
*/
|
|
||||||
navigateMenuLeft(): boolean {
|
|
||||||
this.scene.ui.setMode(Mode.SETTINGS_GAMEPAD);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate to the right menu tab.
|
|
||||||
*
|
|
||||||
* @returns `true` indicating the navigation was successful.
|
|
||||||
*/
|
|
||||||
navigateMenuRight(): boolean {
|
|
||||||
this.scene.ui.setMode(Mode.SETTINGS);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the display of the chosen keyboard layout.
|
* Update the display of the chosen keyboard layout.
|
||||||
*/
|
*/
|
||||||
@ -182,11 +141,11 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
this.updateBindings();
|
this.updateBindings();
|
||||||
|
|
||||||
// Iterate over the keys in the settingDevice enumeration.
|
// Iterate over the keys in the settingDevice enumeration.
|
||||||
for (const [index, key] of Object.keys(this.settingDevice).entries()) {
|
for (const [index, key] of Object.keys(this.setting).entries()) {
|
||||||
const setting = this.settingDevice[key]; // Get the actual setting value using the key.
|
const setting = this.setting[key]; // Get the actual setting value using the key.
|
||||||
|
|
||||||
// Check if the current setting corresponds to the layout setting.
|
// Check if the current setting corresponds to the layout setting.
|
||||||
if (setting === this.settingDevice.Default_Layout) {
|
if (setting === this.setting.Default_Layout) {
|
||||||
// Iterate over all layouts excluding the 'noGamepads' special case.
|
// Iterate over all layouts excluding the 'noGamepads' special case.
|
||||||
for (const _key of Object.keys(this.layout)) {
|
for (const _key of Object.keys(this.layout)) {
|
||||||
if (_key === "noKeyboard") {
|
if (_key === "noKeyboard") {
|
||||||
@ -217,8 +176,8 @@ export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandl
|
|||||||
* @param cursor - The cursor position to save.
|
* @param cursor - The cursor position to save.
|
||||||
*/
|
*/
|
||||||
saveSettingToLocalStorage(settingName, cursor): void {
|
saveSettingToLocalStorage(settingName, cursor): void {
|
||||||
if (this.settingDevice[settingName] !== this.settingDevice.Default_Layout) {
|
if (this.setting[settingName] !== this.setting.Default_Layout) {
|
||||||
this.scene.gameData.saveKeyboardSetting(settingName, cursor);
|
this.scene.gameData.saveControlSetting(this.device, this.localStoragePropertyName, settingName, this.settingDeviceDefaults, cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,345 +1,19 @@
|
|||||||
import BattleScene from "../../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import {Setting, reloadSettings, settingDefaults, settingOptions} from "../../system/settings";
|
import {Setting, SettingType} from "../../system/settings/settings";
|
||||||
import { hasTouchscreen, isMobile } from "../../touch-controls";
|
|
||||||
import { TextStyle, addTextObject } from "../text";
|
|
||||||
import { Mode } from "../ui";
|
import { Mode } from "../ui";
|
||||||
import UiHandler from "../ui-handler";
|
import AbstractSettingsUiHandler from "./abstract-settings-ui-handler";
|
||||||
import { addWindow } from "../ui-theme";
|
|
||||||
import {Button} from "../../enums/buttons";
|
|
||||||
import {InputsIcons} from "#app/ui/settings/abstract-settings-ui-handler";
|
|
||||||
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
|
||||||
|
|
||||||
export default class SettingsUiHandler extends UiHandler {
|
|
||||||
private settingsContainer: Phaser.GameObjects.Container;
|
|
||||||
private optionsContainer: Phaser.GameObjects.Container;
|
|
||||||
private navigationContainer: NavigationMenu;
|
|
||||||
|
|
||||||
private scrollCursor: integer;
|
|
||||||
|
|
||||||
private optionsBg: Phaser.GameObjects.NineSlice;
|
|
||||||
|
|
||||||
private optionCursors: integer[];
|
|
||||||
|
|
||||||
private settingLabels: Phaser.GameObjects.Text[];
|
|
||||||
private optionValueLabels: Phaser.GameObjects.Text[][];
|
|
||||||
|
|
||||||
protected navigationIcons: InputsIcons;
|
|
||||||
|
|
||||||
private cursorObj: Phaser.GameObjects.NineSlice;
|
|
||||||
|
|
||||||
private reloadRequired: boolean;
|
|
||||||
private reloadI18n: boolean;
|
|
||||||
private rowsToDisplay: number;
|
|
||||||
|
|
||||||
|
export default class SettingsUiHandler extends AbstractSettingsUiHandler {
|
||||||
|
/**
|
||||||
|
* Creates an instance of SettingsGamepadUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode, optional.
|
||||||
|
*/
|
||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
this.title = "General";
|
||||||
this.reloadRequired = false;
|
this.settings = Setting.filter(s => s.type === SettingType.GENERAL);
|
||||||
this.reloadI18n = false;
|
this.localStorageKey = "settings";
|
||||||
this.rowsToDisplay = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const ui = this.getUi();
|
|
||||||
|
|
||||||
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
|
||||||
|
|
||||||
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6 - 20), Phaser.Geom.Rectangle.Contains);
|
|
||||||
|
|
||||||
this.navigationIcons = {};
|
|
||||||
|
|
||||||
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
|
||||||
|
|
||||||
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
|
||||||
this.optionsBg.setOrigin(0, 0);
|
|
||||||
|
|
||||||
const actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
|
||||||
actionsBg.setOrigin(0, 0);
|
|
||||||
|
|
||||||
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
|
||||||
iconAction.setOrigin(0, -0.1);
|
|
||||||
iconAction.setPositionRelative(actionsBg, this.navigationContainer.width - 32, 4);
|
|
||||||
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
|
||||||
|
|
||||||
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
|
||||||
actionText.setOrigin(0, 0.15);
|
|
||||||
actionText.setPositionRelative(iconAction, -actionText.width/6-2, 0);
|
|
||||||
|
|
||||||
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
|
||||||
iconCancel.setOrigin(0, -0.1);
|
|
||||||
iconCancel.setPositionRelative(actionsBg, this.navigationContainer.width - 100, 4);
|
|
||||||
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
|
||||||
|
|
||||||
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
|
||||||
cancelText.setOrigin(0, 0.15);
|
|
||||||
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
|
||||||
|
|
||||||
this.optionsContainer = this.scene.add.container(0, 0);
|
|
||||||
|
|
||||||
this.settingLabels = [];
|
|
||||||
this.optionValueLabels = [];
|
|
||||||
|
|
||||||
Object.keys(Setting).forEach((setting, s) => {
|
|
||||||
let settingName = setting.replace(/\_/g, " ");
|
|
||||||
if (reloadSettings.includes(Setting[setting])) {
|
|
||||||
settingName += " (Requires Reload)";
|
|
||||||
}
|
|
||||||
|
|
||||||
this.settingLabels[s] = addTextObject(this.scene, 8, 28 + s * 16, settingName, TextStyle.SETTINGS_LABEL);
|
|
||||||
this.settingLabels[s].setOrigin(0, 0);
|
|
||||||
|
|
||||||
this.optionsContainer.add(this.settingLabels[s]);
|
|
||||||
|
|
||||||
this.optionValueLabels.push(settingOptions[Setting[setting]].map((option, o) => {
|
|
||||||
const valueLabel = addTextObject(this.scene, 0, 0, option, settingDefaults[Setting[setting]] === o ? TextStyle.SETTINGS_SELECTED : TextStyle.WINDOW);
|
|
||||||
valueLabel.setOrigin(0, 0);
|
|
||||||
|
|
||||||
this.optionsContainer.add(valueLabel);
|
|
||||||
|
|
||||||
return valueLabel;
|
|
||||||
}));
|
|
||||||
|
|
||||||
const totalWidth = this.optionValueLabels[s].map(o => o.width).reduce((total, width) => total += width, 0);
|
|
||||||
|
|
||||||
const labelWidth = Math.max(78, this.settingLabels[s].displayWidth + 8);
|
|
||||||
|
|
||||||
const totalSpace = (300 - labelWidth) - totalWidth / 6;
|
|
||||||
const optionSpacing = Math.floor(totalSpace / (this.optionValueLabels[s].length - 1));
|
|
||||||
|
|
||||||
let xOffset = 0;
|
|
||||||
|
|
||||||
for (const value of this.optionValueLabels[s]) {
|
|
||||||
value.setPositionRelative(this.settingLabels[s], labelWidth + xOffset, 0);
|
|
||||||
xOffset += value.width / 6 + optionSpacing;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.optionCursors = Object.values(settingDefaults);
|
|
||||||
|
|
||||||
this.settingsContainer.add(this.optionsBg);
|
|
||||||
this.settingsContainer.add(this.navigationContainer);
|
|
||||||
this.settingsContainer.add(actionsBg);
|
|
||||||
this.settingsContainer.add(this.optionsContainer);
|
|
||||||
this.settingsContainer.add(iconAction);
|
|
||||||
this.settingsContainer.add(iconCancel);
|
|
||||||
this.settingsContainer.add(actionText);
|
|
||||||
this.settingsContainer.add(cancelText);
|
|
||||||
|
|
||||||
ui.add(this.settingsContainer);
|
|
||||||
|
|
||||||
this.setCursor(0);
|
|
||||||
this.setScrollCursor(0);
|
|
||||||
|
|
||||||
this.settingsContainer.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateBindings(): void {
|
|
||||||
for (const settingName of Object.keys(this.navigationIcons)) {
|
|
||||||
if (settingName === "BUTTON_HOME") {
|
|
||||||
this.navigationIcons[settingName].setTexture("keyboard");
|
|
||||||
this.navigationIcons[settingName].setFrame("HOME.png");
|
|
||||||
this.navigationIcons[settingName].alpha = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const icon = this.scene.inputController?.getIconForLatestInputRecorded(settingName);
|
|
||||||
if (icon) {
|
|
||||||
const type = this.scene.inputController?.getLastSourceType();
|
|
||||||
this.navigationIcons[settingName].setTexture(type);
|
|
||||||
this.navigationIcons[settingName].setFrame(icon);
|
|
||||||
this.navigationIcons[settingName].alpha = 1;
|
|
||||||
} else {
|
|
||||||
this.navigationIcons[settingName].alpha = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NavigationManager.getInstance().updateIcons();
|
|
||||||
}
|
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
|
||||||
super.show(args);
|
|
||||||
this.updateBindings();
|
|
||||||
|
|
||||||
const settings: object = localStorage.hasOwnProperty("settings") ? JSON.parse(localStorage.getItem("settings")) : {};
|
|
||||||
|
|
||||||
Object.keys(settingDefaults).forEach((setting, s) => this.setOptionCursor(s, settings.hasOwnProperty(setting) ? settings[setting] : settingDefaults[setting]));
|
|
||||||
|
|
||||||
this.settingsContainer.setVisible(true);
|
|
||||||
this.setCursor(0);
|
|
||||||
|
|
||||||
this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1);
|
|
||||||
|
|
||||||
this.getUi().hideTooltip();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes input from a specified button.
|
|
||||||
* This method handles navigation through a UI menu, including movement through menu items
|
|
||||||
* and handling special actions like cancellation. Each button press may adjust the cursor
|
|
||||||
* position or the menu scroll, and plays a sound effect if the action was successful.
|
|
||||||
*
|
|
||||||
* @param button - The button pressed by the user.
|
|
||||||
* @returns `true` if the action associated with the button was successfully processed, `false` otherwise.
|
|
||||||
*/
|
|
||||||
processInput(button: Button): boolean {
|
|
||||||
const ui = this.getUi();
|
|
||||||
// Defines the maximum number of rows that can be displayed on the screen.
|
|
||||||
|
|
||||||
let success = false;
|
|
||||||
|
|
||||||
if (button === Button.CANCEL) {
|
|
||||||
success = true;
|
|
||||||
NavigationManager.getInstance().reset();
|
|
||||||
// Reverts UI to its previous state on cancel.
|
|
||||||
this.scene.ui.revertMode();
|
|
||||||
} else {
|
|
||||||
const cursor = this.cursor + this.scrollCursor;
|
|
||||||
switch (button) {
|
|
||||||
case Button.UP:
|
|
||||||
if (cursor) {
|
|
||||||
if (this.cursor) {
|
|
||||||
success = this.setCursor(this.cursor - 1);
|
|
||||||
} else {
|
|
||||||
success = this.setScrollCursor(this.scrollCursor - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// When at the top of the menu and pressing UP, move to the bottommost item.
|
|
||||||
// First, set the cursor to the last visible element, preparing for the scroll to the end.
|
|
||||||
const successA = this.setCursor(this.rowsToDisplay - 1);
|
|
||||||
// Then, adjust the scroll to display the bottommost elements of the menu.
|
|
||||||
const successB = this.setScrollCursor(this.optionValueLabels.length - this.rowsToDisplay);
|
|
||||||
success = successA && successB; // success is just there to play the little validation sound effect
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button.DOWN:
|
|
||||||
if (cursor < this.optionValueLabels.length - 1) {
|
|
||||||
if (this.cursor < this.rowsToDisplay - 1) {// if the visual cursor is in the frame of 0 to 8
|
|
||||||
success = this.setCursor(this.cursor + 1);
|
|
||||||
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
|
||||||
success = this.setScrollCursor(this.scrollCursor + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// When at the bottom of the menu and pressing DOWN, move to the topmost item.
|
|
||||||
// First, set the cursor to the first visible element, resetting the scroll to the top.
|
|
||||||
const successA = this.setCursor(0);
|
|
||||||
// Then, reset the scroll to start from the first element of the menu.
|
|
||||||
const successB = this.setScrollCursor(0);
|
|
||||||
success = successA && successB; // Indicates a successful cursor and scroll adjustment.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button.LEFT:
|
|
||||||
if (this.optionCursors[cursor]) {// Moves the option cursor left, if possible.
|
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button.RIGHT:
|
|
||||||
// Moves the option cursor right, if possible.
|
|
||||||
if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
|
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button.CYCLE_FORM:
|
|
||||||
case Button.CYCLE_SHINY:
|
|
||||||
success = this.navigationContainer.navigate(button);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plays a select sound effect if an action was successfully processed.
|
|
||||||
if (success) {
|
|
||||||
ui.playSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCursor(cursor: integer): boolean {
|
|
||||||
const ret = super.setCursor(cursor);
|
|
||||||
|
|
||||||
if (!this.cursorObj) {
|
|
||||||
this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1);
|
|
||||||
this.cursorObj.setOrigin(0, 0);
|
|
||||||
this.optionsContainer.add(this.cursorObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
|
||||||
const setting = Setting[Object.keys(Setting)[settingIndex]];
|
|
||||||
|
|
||||||
if (setting === Setting.Touch_Controls && cursor && hasTouchscreen() && isMobile()) {
|
|
||||||
this.getUi().playError();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastCursor = this.optionCursors[settingIndex];
|
|
||||||
|
|
||||||
const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor];
|
|
||||||
lastValueLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
|
||||||
lastValueLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
|
||||||
|
|
||||||
this.optionCursors[settingIndex] = cursor;
|
|
||||||
|
|
||||||
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
|
||||||
newValueLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
|
||||||
newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
|
||||||
|
|
||||||
if (save) {
|
|
||||||
this.scene.gameData.saveSetting(setting, cursor);
|
|
||||||
if (reloadSettings.includes(setting)) {
|
|
||||||
this.reloadRequired = true;
|
|
||||||
if (setting === Setting.Language) {
|
|
||||||
this.reloadI18n = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
setScrollCursor(scrollCursor: integer): boolean {
|
|
||||||
if (scrollCursor === this.scrollCursor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.scrollCursor = scrollCursor;
|
|
||||||
|
|
||||||
this.updateSettingsScroll();
|
|
||||||
|
|
||||||
this.setCursor(this.cursor);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSettingsScroll(): void {
|
|
||||||
this.optionsContainer.setY(-16 * this.scrollCursor);
|
|
||||||
|
|
||||||
for (let s = 0; s < this.settingLabels.length; s++) {
|
|
||||||
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
|
||||||
this.settingLabels[s].setVisible(visible);
|
|
||||||
for (const option of this.optionValueLabels[s]) {
|
|
||||||
option.setVisible(visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
super.clear();
|
|
||||||
this.settingsContainer.setVisible(false);
|
|
||||||
this.eraseCursor();
|
|
||||||
if (this.reloadRequired) {
|
|
||||||
this.reloadRequired = false;
|
|
||||||
this.scene.reset(true, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eraseCursor() {
|
|
||||||
if (this.cursorObj) {
|
|
||||||
this.cursorObj.destroy();
|
|
||||||
}
|
|
||||||
this.cursorObj = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ import {PlayerGender} from "#app/system/game-data";
|
|||||||
import GamepadBindingUiHandler from "./settings/gamepad-binding-ui-handler";
|
import GamepadBindingUiHandler from "./settings/gamepad-binding-ui-handler";
|
||||||
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||||
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";
|
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";
|
||||||
|
import SettingsAccessibilityUiHandler from "./settings/settings-accessiblity-ui-handler";
|
||||||
|
|
||||||
export enum Mode {
|
export enum Mode {
|
||||||
MESSAGE,
|
MESSAGE,
|
||||||
@ -62,6 +63,7 @@ export enum Mode {
|
|||||||
MENU,
|
MENU,
|
||||||
MENU_OPTION_SELECT,
|
MENU_OPTION_SELECT,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
SETTINGS_ACCESSIBILITY,
|
||||||
SETTINGS_GAMEPAD,
|
SETTINGS_GAMEPAD,
|
||||||
GAMEPAD_BINDING,
|
GAMEPAD_BINDING,
|
||||||
SETTINGS_KEYBOARD,
|
SETTINGS_KEYBOARD,
|
||||||
@ -99,6 +101,7 @@ const noTransitionModes = [
|
|||||||
Mode.GAMEPAD_BINDING,
|
Mode.GAMEPAD_BINDING,
|
||||||
Mode.KEYBOARD_BINDING,
|
Mode.KEYBOARD_BINDING,
|
||||||
Mode.SETTINGS,
|
Mode.SETTINGS,
|
||||||
|
Mode.SETTINGS_ACCESSIBILITY,
|
||||||
Mode.SETTINGS_GAMEPAD,
|
Mode.SETTINGS_GAMEPAD,
|
||||||
Mode.SETTINGS_KEYBOARD,
|
Mode.SETTINGS_KEYBOARD,
|
||||||
Mode.ACHIEVEMENTS,
|
Mode.ACHIEVEMENTS,
|
||||||
@ -151,6 +154,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||||||
new MenuUiHandler(scene),
|
new MenuUiHandler(scene),
|
||||||
new OptionSelectUiHandler(scene, Mode.MENU_OPTION_SELECT),
|
new OptionSelectUiHandler(scene, Mode.MENU_OPTION_SELECT),
|
||||||
new SettingsUiHandler(scene),
|
new SettingsUiHandler(scene),
|
||||||
|
new SettingsAccessibilityUiHandler(scene),
|
||||||
new SettingsGamepadUiHandler(scene),
|
new SettingsGamepadUiHandler(scene),
|
||||||
new GamepadBindingUiHandler(scene),
|
new GamepadBindingUiHandler(scene),
|
||||||
new SettingsKeyboardUiHandler(scene),
|
new SettingsKeyboardUiHandler(scene),
|
||||||
|
Loading…
Reference in New Issue
Block a user