Add game settings
parent
23a21af173
commit
d3f55ad4ae
|
@ -99,7 +99,7 @@ export class SelectStarterPhase extends BattlePhase {
|
|||
start() {
|
||||
super.start();
|
||||
|
||||
this.scene.playSound('menu', { loop: true });
|
||||
this.scene.playBgm('menu');
|
||||
|
||||
this.scene.ui.setMode(Mode.STARTER_SELECT, (starters: Starter[]) => {
|
||||
const party = this.scene.getParty();
|
||||
|
@ -2209,7 +2209,7 @@ export class UnlockPhase extends BattlePhase {
|
|||
this.scene.time.delayedCall(2000, () => {
|
||||
this.scene.gameData.unlocks[this.unlockable] = true;
|
||||
this.scene.gameData.saveSystem();
|
||||
this.scene.playSound('level_up_fanfare');
|
||||
this.scene.playSoundWithoutBgm('level_up_fanfare');
|
||||
this.scene.ui.setMode(Mode.MESSAGE);
|
||||
this.scene.arenaBg.setVisible(false);
|
||||
this.scene.ui.fadeIn(250).then(() => {
|
||||
|
@ -2857,8 +2857,7 @@ export class PartyHealPhase extends BattlePhase {
|
|||
move.ppUsed = 0;
|
||||
pokemon.updateInfo(true);
|
||||
}
|
||||
const healSong = this.scene.sound.add('heal');
|
||||
healSong.play({ volume: this.scene.gameVolume });
|
||||
const healSong = this.scene.playSoundWithoutBgm('heal');
|
||||
this.scene.time.delayedCall(healSong.totalDuration * 1000, () => {
|
||||
healSong.destroy();
|
||||
if (this.resumeBgm && bgmPlaying)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Phaser from 'phaser';
|
||||
import { Biome } from './data/biome';
|
||||
import UI from './ui/ui';
|
||||
import UI, { Mode } from './ui/ui';
|
||||
import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, ToggleDoublePositionPhase, CheckSwitchPhase, LevelCapPhase, TestMessagePhase, ShowTrainerPhase } from './battle-phases';
|
||||
import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon';
|
||||
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
|
||||
|
@ -29,6 +29,9 @@ import TrainerData from './system/trainer-data';
|
|||
import SoundFade from 'phaser3-rex-plugins/plugins/soundfade';
|
||||
import { pokemonPrevolutions } from './data/pokemon-evolutions';
|
||||
import PokeballTray from './ui/pokeball-tray';
|
||||
import { Setting, settingOptions } from './system/settings';
|
||||
import SettingsUiHandler from './ui/settings-ui-handler';
|
||||
import MessageUiHandler from './ui/message-ui-handler';
|
||||
|
||||
const enableAuto = true;
|
||||
const quickStart = false;
|
||||
|
@ -44,6 +47,7 @@ export enum Button {
|
|||
RIGHT,
|
||||
ACTION,
|
||||
CANCEL,
|
||||
MENU,
|
||||
CYCLE_SHINY,
|
||||
CYCLE_FORM,
|
||||
CYCLE_GENDER,
|
||||
|
@ -58,9 +62,13 @@ export interface PokeballCounts {
|
|||
[pb: string]: integer;
|
||||
}
|
||||
|
||||
export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound | Phaser.Sound.NoAudioSound;
|
||||
|
||||
export default class BattleScene extends Phaser.Scene {
|
||||
public auto: boolean;
|
||||
public gameVolume: number = 0.5;
|
||||
public masterVolume: number = 0.5;
|
||||
public bgmVolume: number = 1;
|
||||
public seVolume: number = 1;
|
||||
public gameSpeed: integer = 1;
|
||||
public quickStart: boolean = quickStart;
|
||||
public finalWave: integer = 200;
|
||||
|
@ -105,8 +113,9 @@ export default class BattleScene extends Phaser.Scene {
|
|||
|
||||
public spritePipeline: SpritePipeline;
|
||||
|
||||
private bgm: Phaser.Sound.BaseSound;
|
||||
private bgm: AnySound;
|
||||
private bgmResumeTimer: Phaser.Time.TimerEvent;
|
||||
private bgmCache: Set<string> = new Set();
|
||||
|
||||
private buttonKeys: Phaser.Input.Keyboard.Key[][];
|
||||
|
||||
|
@ -484,7 +493,8 @@ export default class BattleScene extends Phaser.Scene {
|
|||
[Button.LEFT]: [keyCodes.LEFT, keyCodes.A],
|
||||
[Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
|
||||
[Button.ACTION]: [keyCodes.ENTER, keyCodes.SPACE, keyCodes.Z],
|
||||
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.ESC, keyCodes.X],
|
||||
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X],
|
||||
[Button.MENU]: [keyCodes.ESC, keyCodes.M],
|
||||
[Button.CYCLE_SHINY]: [keyCodes.R],
|
||||
[Button.CYCLE_FORM]: [keyCodes.F],
|
||||
[Button.CYCLE_GENDER]: [keyCodes.G],
|
||||
|
@ -813,6 +823,32 @@ export default class BattleScene extends Phaser.Scene {
|
|||
this.ui.processInput(Button.ACTION);
|
||||
else if (this.isButtonPressed(Button.CANCEL))
|
||||
this.ui.processInput(Button.CANCEL);
|
||||
else if (this.isButtonPressed(Button.MENU)) {
|
||||
switch (this.ui.getMode()) {
|
||||
case Mode.MESSAGE:
|
||||
if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt)
|
||||
return;
|
||||
case Mode.COMMAND:
|
||||
case Mode.FIGHT:
|
||||
case Mode.BALL:
|
||||
case Mode.TARGET_SELECT:
|
||||
case Mode.PARTY:
|
||||
case Mode.SUMMARY:
|
||||
case Mode.BIOME_SELECT:
|
||||
case Mode.STARTER_SELECT:
|
||||
case Mode.CONFIRM:
|
||||
case Mode.GAME_MODE_SELECT:
|
||||
this.ui.setModeWithoutClear(Mode.SETTINGS);
|
||||
this.playSound('menu_open');
|
||||
break;
|
||||
case Mode.SETTINGS:
|
||||
this.ui.revertMode();
|
||||
this.playSound('select');
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
|
||||
if (this.isButtonPressed(Button.CYCLE_SHINY))
|
||||
this.ui.processInput(Button.CYCLE_SHINY);
|
||||
|
@ -826,25 +862,24 @@ export default class BattleScene extends Phaser.Scene {
|
|||
return;
|
||||
}
|
||||
else if (this.isButtonPressed(Button.SPEED_UP)) {
|
||||
if (!this.auto) {
|
||||
if (this.gameSpeed < 2.5)
|
||||
this.gameSpeed += 0.25;
|
||||
} else if (this.gameSpeed < 20)
|
||||
this.gameSpeed++;
|
||||
if (this.gameSpeed < 5) {
|
||||
this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1);
|
||||
if (this.ui.getMode() === Mode.SETTINGS)
|
||||
(this.ui.getHandler() as SettingsUiHandler).show([]);
|
||||
}
|
||||
} else if (this.isButtonPressed(Button.SLOW_DOWN)) {
|
||||
if (this.gameSpeed > 1) {
|
||||
if (!this.auto)
|
||||
this.gameSpeed -= 0.25;
|
||||
else
|
||||
this.gameSpeed--;
|
||||
this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0));
|
||||
if (this.ui.getMode() === Mode.SETTINGS)
|
||||
(this.ui.getHandler() as SettingsUiHandler).show([]);
|
||||
}
|
||||
} else if (enableAuto) {
|
||||
if (this.isButtonPressed(Button.AUTO)) {
|
||||
this.auto = !this.auto;
|
||||
if (this.auto)
|
||||
this.gameSpeed = Math.floor(this.gameSpeed);
|
||||
else if (this.gameSpeed > 2.5)
|
||||
this.gameSpeed = 2.5;
|
||||
else if (this.gameSpeed > 5)
|
||||
this.gameSpeed = 5;
|
||||
} else
|
||||
return;
|
||||
} else
|
||||
|
@ -867,13 +902,14 @@ export default class BattleScene extends Phaser.Scene {
|
|||
if (this.bgm && bgmName === this.bgm.key) {
|
||||
if (!this.bgm.isPlaying) {
|
||||
this.bgm.play({
|
||||
volume: this.gameVolume
|
||||
volume: this.masterVolume * this.bgmVolume
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fadeOut && !this.bgm)
|
||||
fadeOut = false;
|
||||
this.bgmCache.add(bgmName);
|
||||
this.loadBgm(bgmName);
|
||||
let loopPoint = 0;
|
||||
loopPoint = bgmName === this.arena.bgm
|
||||
|
@ -883,7 +919,7 @@ export default class BattleScene extends Phaser.Scene {
|
|||
const playNewBgm = () => {
|
||||
if (bgmName === null && this.bgm && !this.bgm.pendingRemove) {
|
||||
this.bgm.play({
|
||||
volume: this.gameVolume
|
||||
volume: this.masterVolume * this.bgmVolume
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -891,7 +927,7 @@ export default class BattleScene extends Phaser.Scene {
|
|||
this.bgm.stop();
|
||||
this.bgm = this.sound.add(bgmName, { loop: true });
|
||||
this.bgm.play({
|
||||
volume: this.gameVolume
|
||||
volume: this.masterVolume * this.bgmVolume
|
||||
});
|
||||
if (loopPoint)
|
||||
this.bgm.on('looped', () => this.bgm.play({ seek: loopPoint }));
|
||||
|
@ -912,14 +948,27 @@ export default class BattleScene extends Phaser.Scene {
|
|||
this.load.start();
|
||||
}
|
||||
|
||||
pauseBgm(): void {
|
||||
if (this.bgm && this.bgm.isPlaying)
|
||||
pauseBgm(): boolean {
|
||||
if (this.bgm && this.bgm.isPlaying) {
|
||||
this.bgm.pause();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resumeBgm(): void {
|
||||
if (this.bgm && this.bgm.isPaused)
|
||||
resumeBgm(): boolean {
|
||||
if (this.bgm && this.bgm.isPaused) {
|
||||
this.bgm.resume();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
updateSoundVolume(): void {
|
||||
if (this.sound) {
|
||||
for (let sound of this.sound.getAllPlaying())
|
||||
(sound as AnySound).setVolume(this.masterVolume * (this.bgmCache.has(sound.key) ? this.bgmVolume : this.seVolume));
|
||||
}
|
||||
}
|
||||
|
||||
fadeOutBgm(duration?: integer, destroy?: boolean): boolean {
|
||||
|
@ -938,28 +987,33 @@ export default class BattleScene extends Phaser.Scene {
|
|||
return false;
|
||||
}
|
||||
|
||||
playSound(soundName: string, config?: object) {
|
||||
playSound(soundName: string, config?: object): AnySound {
|
||||
if (config) {
|
||||
if (config.hasOwnProperty('volume'))
|
||||
config['volume'] *= this.gameVolume;
|
||||
config['volume'] *= this.masterVolume * this.seVolume;
|
||||
else
|
||||
config['volume'] = this.gameVolume;
|
||||
config['volume'] = this.masterVolume * this.seVolume;
|
||||
} else
|
||||
config = { volume: this.gameVolume };
|
||||
config = { volume: this.masterVolume * this.seVolume };
|
||||
this.sound.play(soundName, config);
|
||||
return this.sound.get(soundName) as AnySound;
|
||||
}
|
||||
|
||||
playSoundWithoutBgm(soundName: string, pauseDuration?: integer): void {
|
||||
this.pauseBgm();
|
||||
playSoundWithoutBgm(soundName: string, pauseDuration?: integer): AnySound {
|
||||
this.bgmCache.add(soundName);
|
||||
const resumeBgm = this.pauseBgm();
|
||||
this.playSound(soundName);
|
||||
const sound = this.sound.get(soundName);
|
||||
const sound = this.sound.get(soundName) as AnySound;
|
||||
if (this.bgmResumeTimer)
|
||||
this.bgmResumeTimer.destroy();
|
||||
if (resumeBgm) {
|
||||
this.bgmResumeTimer = this.time.delayedCall((pauseDuration || Utils.fixedInt(sound.totalDuration * 1000)), () => {
|
||||
this.resumeBgm();
|
||||
this.bgmResumeTimer = null;
|
||||
});
|
||||
}
|
||||
return sound;
|
||||
}
|
||||
|
||||
getBgmLoopPoint(bgmName: string): number {
|
||||
switch (bgmName) {
|
||||
|
|
|
@ -101,8 +101,8 @@ export class EvolutionPhase extends BattlePhase {
|
|||
this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
|
||||
|
||||
this.scene.time.delayedCall(1000, () => {
|
||||
const evolutionBgm = this.scene.sound.add('evolution');
|
||||
evolutionBgm.play({ volume: this.scene.gameVolume });
|
||||
const evolutionBgm = this.scene.playSoundWithoutBgm('evolution');
|
||||
evolutionBgm.play({ volume: this.scene.masterVolume });
|
||||
this.scene.tweens.add({
|
||||
targets: this.evolutionBgOverlay,
|
||||
alpha: 1,
|
||||
|
@ -167,7 +167,7 @@ export class EvolutionPhase extends BattlePhase {
|
|||
this.scene.time.delayedCall(250, () => {
|
||||
pokemon.cry();
|
||||
this.scene.time.delayedCall(1250, () => {
|
||||
this.scene.playSound('evolution_fanfare');
|
||||
this.scene.playSoundWithoutBgm('evolution_fanfare');
|
||||
this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000);
|
||||
this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Phaser from 'phaser';
|
||||
import BattleScene from './battle-scene';
|
||||
import BattleScene, { AnySound } from './battle-scene';
|
||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './ui/battle-info';
|
||||
import Move, { StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, Moves, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, AttackMove, AddBattlerTagAttr } from "./data/move";
|
||||
import { pokemonLevelMoves } from './data/pokemon-level-moves';
|
||||
|
@ -885,7 +885,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const key = this.species.speciesId.toString();
|
||||
let i = 0;
|
||||
let rate = 0.85;
|
||||
this.scene.playSound(key, { rate: rate });
|
||||
const crySound = this.scene.playSound(key, { rate: rate }) as AnySound;
|
||||
const sprite = this.getSprite();
|
||||
const tintSprite = this.getTintSprite();
|
||||
const delay = Math.max(this.scene.sound.get(key).totalDuration * 50, 25);
|
||||
|
@ -894,7 +894,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
sprite.anims.pause();
|
||||
tintSprite.anims.pause();
|
||||
let faintCryTimer = this.scene.time.addEvent({
|
||||
delay: delay,
|
||||
delay: Utils.fixedInt(delay),
|
||||
repeat: -1,
|
||||
callback: () => {
|
||||
++i;
|
||||
|
@ -907,14 +907,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
}
|
||||
frameProgress -= frameThreshold;
|
||||
}
|
||||
const crySound = this.scene.sound.get(key);
|
||||
if (crySound && !crySound.pendingRemove) {
|
||||
rate *= 0.99;
|
||||
crySound.play({
|
||||
rate: rate,
|
||||
seek: (i * delay * 0.001) * rate,
|
||||
volume: this.scene.gameVolume
|
||||
});
|
||||
crySound.setRate(rate);
|
||||
}
|
||||
else {
|
||||
faintCryTimer.destroy();
|
||||
|
@ -925,10 +920,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
}
|
||||
});
|
||||
// Failsafe
|
||||
this.scene.time.delayedCall(3000, () => {
|
||||
this.scene.time.delayedCall(Utils.fixedInt(3000), () => {
|
||||
if (!faintCryTimer || !this.scene)
|
||||
return;
|
||||
const crySound = this.scene.sound.get(key);
|
||||
if (crySound?.isPlaying)
|
||||
crySound.stop();
|
||||
faintCryTimer.destroy();
|
||||
|
|
|
@ -14,6 +14,7 @@ import { GameMode } from "../game-mode";
|
|||
import { BattleType } from "../battle";
|
||||
import TrainerData from "./trainer-data";
|
||||
import { trainerConfigs } from "../data/trainer-type";
|
||||
import { Setting, setSetting, settingDefaults } from "./settings";
|
||||
|
||||
interface SystemSaveData {
|
||||
trainerId: integer;
|
||||
|
@ -81,8 +82,9 @@ export class GameData {
|
|||
|
||||
constructor(scene: BattleScene) {
|
||||
this.scene = scene;
|
||||
this.trainerId = Utils.randInt(65536);
|
||||
this.secretId = Utils.randInt(65536);
|
||||
this.loadSettings();
|
||||
this.trainerId = Utils.randSeedInt(65536);
|
||||
this.secretId = Utils.randSeedInt(65536);
|
||||
this.unlocks = {
|
||||
[Unlockables.ENDLESS_MODE]: false,
|
||||
[Unlockables.MINI_BLACK_HOLE]: false
|
||||
|
@ -109,7 +111,7 @@ export class GameData {
|
|||
}
|
||||
|
||||
private loadSystem(): boolean {
|
||||
if (!localStorage.getItem('data'))
|
||||
if (!localStorage.hasOwnProperty('data'))
|
||||
return false;
|
||||
|
||||
const data = JSON.parse(atob(localStorage.getItem('data'))) as SystemSaveData;
|
||||
|
@ -133,6 +135,33 @@ export class GameData {
|
|||
return true;
|
||||
}
|
||||
|
||||
public saveSetting(setting: Setting, valueIndex: integer): boolean {
|
||||
let settings: object = {};
|
||||
if (localStorage.hasOwnProperty('settings'))
|
||||
settings = JSON.parse(localStorage.getItem('settings'));
|
||||
|
||||
setSetting(this.scene, setting as Setting, valueIndex);
|
||||
|
||||
Object.keys(settingDefaults).forEach(s => {
|
||||
if (s === setting)
|
||||
settings[s] = valueIndex;
|
||||
});
|
||||
|
||||
localStorage.setItem('settings', JSON.stringify(settings));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private loadSettings(): boolean {
|
||||
if (!localStorage.hasOwnProperty('settings'))
|
||||
return false;
|
||||
|
||||
const settings = JSON.parse(localStorage.getItem('settings'));
|
||||
|
||||
for (let setting of Object.keys(settings))
|
||||
setSetting(this.scene, setting as Setting, settings[setting]);
|
||||
}
|
||||
|
||||
saveSession(scene: BattleScene): boolean {
|
||||
const sessionData = {
|
||||
seed: scene.seed,
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import BattleScene from "../battle-scene";
|
||||
|
||||
export enum Setting {
|
||||
Game_Speed = "GAME_SPEED",
|
||||
Master_Volume = "MASTER_VOLUME",
|
||||
BGM_Volume = "BGM_VOLUME",
|
||||
SE_Volume = "SE_VOLUME"
|
||||
}
|
||||
|
||||
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')
|
||||
};
|
||||
|
||||
export const settingDefaults: SettingDefaults = {
|
||||
[Setting.Game_Speed]: 0,
|
||||
[Setting.Master_Volume]: 5,
|
||||
[Setting.BGM_Volume]: 10,
|
||||
[Setting.SE_Volume]: 10
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -6,7 +6,7 @@ import * as Utils from "../utils";
|
|||
export default abstract class MessageUiHandler extends AwaitableUiHandler {
|
||||
protected textTimer: Phaser.Time.TimerEvent;
|
||||
protected textCallbackTimer: Phaser.Time.TimerEvent;
|
||||
protected pendingPrompt: boolean;
|
||||
public pendingPrompt: boolean;
|
||||
|
||||
public message: Phaser.GameObjects.Text;
|
||||
public prompt: Phaser.GameObjects.Sprite;
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Setting, settingDefaults, settingOptions } from "../system/settings";
|
||||
import { TextStyle, addTextObject, getTextColor } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
import UiHandler from "./uiHandler";
|
||||
|
||||
export default class SettingsUiHandler extends UiHandler {
|
||||
private settingsContainer: Phaser.GameObjects.Container;
|
||||
private optionsContainer: Phaser.GameObjects.Container;
|
||||
|
||||
private optionsBg: Phaser.GameObjects.NineSlice;
|
||||
|
||||
private optionCursors: integer[];
|
||||
|
||||
private optionValueLabels: Phaser.GameObjects.Text[][];
|
||||
|
||||
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||
|
||||
constructor(scene: BattleScene, mode?: Mode) {
|
||||
super(scene, mode);
|
||||
}
|
||||
|
||||
setup() {
|
||||
const ui = this.getUi();
|
||||
|
||||
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||
|
||||
const headerBg = this.scene.add.nineslice(0, 0, 'window', null, (this.scene.game.canvas.width / 6) - 2, 24, 6, 6, 6, 6);
|
||||
headerBg.setOrigin(0, 0);
|
||||
|
||||
const headerText = addTextObject(this.scene, 0, 0, 'Options', TextStyle.SETTINGS_LABEL);
|
||||
headerText.setOrigin(0, 0);
|
||||
headerText.setPositionRelative(headerBg, 8, 4);
|
||||
|
||||
this.optionsBg = this.scene.add.nineslice(0, headerBg.height, 'window', null, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 2, 6, 6, 6, 6);
|
||||
this.optionsBg.setOrigin(0, 0);
|
||||
|
||||
this.optionsContainer = this.scene.add.container(0, 0);
|
||||
|
||||
this.optionValueLabels = [];
|
||||
|
||||
Object.keys(Setting).forEach((setting, s) => {
|
||||
const settingLabel = addTextObject(this.scene, 8, 28 + s * 16, setting.replace(/\_/g, ' '), TextStyle.SETTINGS_LABEL);
|
||||
settingLabel.setOrigin(0, 0);
|
||||
|
||||
this.optionsContainer.add(settingLabel);
|
||||
|
||||
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 totalSpace = 220 - totalWidth / 6;
|
||||
const optionSpacing = Math.floor(totalSpace / (this.optionValueLabels[s].length - 1));
|
||||
|
||||
let xOffset = 0;
|
||||
|
||||
for (let value of this.optionValueLabels[s]) {
|
||||
value.setPositionRelative(settingLabel, 82 + xOffset, 0);
|
||||
xOffset += value.width / 6 + optionSpacing;
|
||||
}
|
||||
});
|
||||
|
||||
this.optionCursors = Object.values(settingDefaults);
|
||||
|
||||
this.settingsContainer.add(headerBg);
|
||||
this.settingsContainer.add(headerText);
|
||||
this.settingsContainer.add(this.optionsBg);
|
||||
this.settingsContainer.add(this.optionsContainer);
|
||||
|
||||
ui.add(this.settingsContainer);
|
||||
|
||||
this.setCursor(0);
|
||||
|
||||
this.settingsContainer.setVisible(false);
|
||||
}
|
||||
|
||||
show(args: any[]) {
|
||||
super.show(args);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
processInput(button: Button) {
|
||||
const ui = this.getUi();
|
||||
|
||||
let success = false;
|
||||
|
||||
if (button === Button.CANCEL) {
|
||||
success = true;
|
||||
this.scene.ui.revertMode();
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (this.cursor)
|
||||
success = this.setCursor(this.cursor - 1);
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (this.cursor < this.optionValueLabels.length - 1)
|
||||
success = this.setCursor(this.cursor + 1);
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (this.optionCursors[this.cursor])
|
||||
success = this.setOptionCursor(this.cursor, this.optionCursors[this.cursor] - 1, true);
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (this.optionCursors[this.cursor] < this.optionValueLabels[this.cursor].length - 1)
|
||||
success = this.setOptionCursor(this.cursor, this.optionCursors[this.cursor] + 1, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
ui.playSelect();
|
||||
}
|
||||
|
||||
setCursor(cursor: integer): boolean {
|
||||
const ret = super.setCursor(cursor);
|
||||
|
||||
if (!this.cursorObj) {
|
||||
this.cursorObj = this.scene.add.nineslice(0, 0, 'starter_select_cursor_highlight', 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 * 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
||||
const lastValueLabel = this.optionValueLabels[settingIndex][this.optionCursors[settingIndex]];
|
||||
lastValueLabel.setColor(getTextColor(TextStyle.WINDOW));
|
||||
lastValueLabel.setShadowColor(getTextColor(TextStyle.WINDOW, true));
|
||||
|
||||
this.optionCursors[settingIndex] = cursor;
|
||||
|
||||
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
||||
newValueLabel.setColor(getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||
newValueLabel.setShadowColor(getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||
|
||||
if (save)
|
||||
this.scene.gameData.saveSetting(Setting[Object.keys(Setting)[settingIndex]], cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.settingsContainer.setVisible(false);
|
||||
this.eraseCursor();
|
||||
}
|
||||
|
||||
eraseCursor() {
|
||||
if (this.cursorObj)
|
||||
this.cursorObj.destroy();
|
||||
this.cursorObj = null;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,9 @@ export enum TextStyle {
|
|||
SUMMARY,
|
||||
SUMMARY_RED,
|
||||
SUMMARY_GOLD,
|
||||
MONEY
|
||||
MONEY,
|
||||
SETTINGS_LABEL,
|
||||
SETTINGS_SELECTED
|
||||
};
|
||||
|
||||
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) {
|
||||
|
@ -29,6 +31,8 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content
|
|||
case TextStyle.SUMMARY_GOLD:
|
||||
case TextStyle.WINDOW:
|
||||
case TextStyle.MESSAGE:
|
||||
case TextStyle.SETTINGS_LABEL:
|
||||
case TextStyle.SETTINGS_SELECTED:
|
||||
styleOptions.fontSize = '96px';
|
||||
break;
|
||||
case TextStyle.BATTLE_INFO:
|
||||
|
@ -80,5 +84,9 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean) {
|
|||
case TextStyle.SUMMARY_GOLD:
|
||||
case TextStyle.MONEY:
|
||||
return !shadow ? '#e8e8a8' : '#a0a060'
|
||||
case TextStyle.SETTINGS_LABEL:
|
||||
return !shadow ? '#f8b050' : '#c07800';
|
||||
case TextStyle.SETTINGS_SELECTED:
|
||||
return !shadow ? '#f88880' : '#f83018';
|
||||
}
|
||||
}
|
25
src/ui/ui.ts
25
src/ui/ui.ts
|
@ -14,6 +14,7 @@ import EvolutionSceneHandler from './evolution-scene-handler';
|
|||
import BiomeSelectUiHandler from './biome-select-ui-handler';
|
||||
import TargetSelectUiHandler from './target-select-ui-handler';
|
||||
import GameModeSelectUiHandler from './game-mode-select-ui-handler';
|
||||
import SettingsUiHandler from './settings-ui-handler';
|
||||
|
||||
export enum Mode {
|
||||
MESSAGE,
|
||||
|
@ -28,7 +29,8 @@ export enum Mode {
|
|||
STARTER_SELECT,
|
||||
EVOLUTION_SCENE,
|
||||
CONFIRM,
|
||||
GAME_MODE_SELECT
|
||||
GAME_MODE_SELECT,
|
||||
SETTINGS
|
||||
};
|
||||
|
||||
const transitionModes = [
|
||||
|
@ -40,11 +42,13 @@ const transitionModes = [
|
|||
|
||||
const noTransitionModes = [
|
||||
Mode.CONFIRM,
|
||||
Mode.GAME_MODE_SELECT
|
||||
Mode.GAME_MODE_SELECT,
|
||||
Mode.SETTINGS
|
||||
];
|
||||
|
||||
export default class UI extends Phaser.GameObjects.Container {
|
||||
private mode: Mode;
|
||||
private lastMode: Mode;
|
||||
private handlers: UiHandler[];
|
||||
private overlay: Phaser.GameObjects.Rectangle;
|
||||
|
||||
|
@ -67,7 +71,8 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
new StarterSelectUiHandler(scene),
|
||||
new EvolutionSceneHandler(scene),
|
||||
new ConfirmUiHandler(scene),
|
||||
new GameModeSelectUiHandler(scene)
|
||||
new GameModeSelectUiHandler(scene),
|
||||
new SettingsUiHandler(scene)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -181,6 +186,7 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
if (this.mode !== mode) {
|
||||
if (clear)
|
||||
this.getHandler().clear();
|
||||
this.lastMode = this.mode && !clear ? this.mode : undefined;
|
||||
this.mode = mode;
|
||||
this.getHandler().show(args);
|
||||
}
|
||||
|
@ -199,6 +205,10 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
});
|
||||
}
|
||||
|
||||
getMode(): Mode {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
setMode(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, true, false, args);
|
||||
}
|
||||
|
@ -210,4 +220,13 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
setModeWithoutClear(mode: Mode, ...args: any[]): Promise<void> {
|
||||
return this.setModeInternal(mode, false, false, args);
|
||||
}
|
||||
|
||||
revertMode(): void {
|
||||
if (!this.lastMode)
|
||||
return;
|
||||
|
||||
this.getHandler().clear();
|
||||
this.mode = this.lastMode;
|
||||
this.lastMode = undefined;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue