diff --git a/public/images/arenas/loading_bg.png b/public/images/arenas/loading_bg.png new file mode 100644 index 000000000..79c249f68 Binary files /dev/null and b/public/images/arenas/loading_bg.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 7cd5e8dfd..163dcd654 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -57,6 +57,7 @@ import { biomeDepths } from './data/biomes'; import { initTouchControls } from './touch-controls'; import { UiTheme } from './enums/ui-theme'; import CacheBustedLoaderPlugin from './plugins/cache-busted-loader-plugin'; +import { SceneBase } from './scene-base'; export const bypassLogin = false; @@ -72,7 +73,6 @@ const DEBUG_RNG = false; export const startingWave = STARTING_WAVE_OVERRIDE || 1; -export const legacyCompatibleImages: string[] = []; const expSpriteKeys: string[] = []; export enum Button { @@ -99,7 +99,7 @@ export interface PokeballCounts { export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound | Phaser.Sound.NoAudioSound; -export default class BattleScene extends Phaser.Scene { +export default class BattleScene extends SceneBase { public rexUI: UIPlugin; public sessionPlayTime: integer = null; @@ -199,30 +199,6 @@ export default class BattleScene extends Phaser.Scene { Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load'); } - loadImage(key: string, folder: string, filename?: string) { - if (!filename) - filename = `${key}.png`; - this.load.image(key, `images/${folder}/${filename}`); - if (folder.startsWith('ui')) { - legacyCompatibleImages.push(key); - folder = folder.replace('ui', 'ui/legacy'); - this.load.image(`${key}_legacy`, `images/${folder}/${filename}`); - } - } - - loadAtlas(key: string, folder: string, filenameRoot?: string) { - if (!filenameRoot) - filenameRoot = key; - if (folder) - folder += '/'; - this.load.atlas(key, `images/${folder}${filenameRoot}.png`, `images/${folder}/${filenameRoot}.json`); - if (folder.startsWith('ui')) { - legacyCompatibleImages.push(key); - folder = folder.replace('ui', 'ui/legacy'); - this.load.atlas(`${key}_legacy`, `images/${folder}${filenameRoot}.png`, `images/${folder}/${filenameRoot}.json`); - } - } - loadPokemonAtlas(key: string, atlasPath: string, experimental?: boolean) { if (experimental === undefined) experimental = this.experimentalSprites; @@ -243,45 +219,7 @@ export default class BattleScene extends Phaser.Scene { this.load.atlas(key, `images/pokemon/${experimental ? 'exp/' : ''}${atlasPath}.png`, `images/pokemon/${experimental ? 'exp/' : ''}${atlasPath}.json`); } - loadSpritesheet(key: string, folder: string, size: integer, filename?: string) { - if (!filename) - filename = `${key}.png`; - this.load.spritesheet(key, `images/${folder}/${filename}`, { frameWidth: size, frameHeight: size }); - if (folder.startsWith('ui')) { - legacyCompatibleImages.push(key); - folder = folder.replace('ui', 'ui/legacy'); - this.load.spritesheet(`${key}_legacy`, `images/${folder}/${filename}`, { frameWidth: size, frameHeight: size }); - } - } - - loadSe(key: string, folder?: string, filenames?: string | string[]) { - if (!filenames) - filenames = `${key}.wav`; - if (!folder) - folder = ''; - else - folder += '/'; - if (!Array.isArray(filenames)) - filenames = [ filenames ]; - for (let f of filenames as string[]) { - this.load.audio(key, `audio/se/${folder}${f}`); - } - } - - loadBgm(key: string, filename?: string) { - if (!filename) - filename = `${key}.mp3`; - this.load.audio(key, `audio/bgm/${filename}`); - } - preload() { - const indexFile = Array.from(document.querySelectorAll('script')).map(s => s.src).find(s => /\/index/.test(s)); - if (indexFile) { - const buildIdMatch = /index\-(.*?)\.js$/.exec(indexFile); - if (buildIdMatch) - this.load['cacheBuster'] = buildIdMatch[1]; - } - if (DEBUG_RNG) { const scene = this; const originalRealInRange = Phaser.Math.RND.realInRange; @@ -295,219 +233,8 @@ export default class BattleScene extends Phaser.Scene { return ret; }; } - - // Load menu images - this.loadAtlas('bg', 'ui'); - this.loadImage('command_fight_labels', 'ui'); - this.loadAtlas('prompt', 'ui'); - this.loadImage('cursor', 'ui'); - this.loadImage('cursor_reverse', 'ui'); - for (let wv of Utils.getEnumValues(WindowVariant)) { - for (let w = 1; w <= 5; w++) - this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, 'ui/windows'); - } - this.loadAtlas('namebox', 'ui'); - this.loadImage('pbinfo_player', 'ui'); - this.loadImage('pbinfo_player_mini', 'ui'); - this.loadImage('pbinfo_enemy_mini', 'ui'); - this.loadImage('pbinfo_enemy_boss', 'ui'); - this.loadImage('overlay_lv', 'ui'); - this.loadAtlas('numbers', 'ui'); - this.loadAtlas('numbers_red', 'ui'); - this.loadAtlas('overlay_hp', 'ui'); - this.loadAtlas('overlay_hp_boss', 'ui'); - this.loadImage('overlay_exp', 'ui'); - this.loadImage('icon_owned', 'ui'); - this.loadImage('ability_bar_left', 'ui'); - this.loadImage('party_exp_bar', 'ui'); - this.loadImage('achv_bar', 'ui'); - this.loadImage('achv_bar_2', 'ui'); - this.loadImage('achv_bar_3', 'ui'); - this.loadImage('achv_bar_4', 'ui'); - this.loadImage('shiny_star', 'ui', 'shiny.png'); - this.loadImage('icon_spliced', 'ui'); - this.loadImage('icon_tera', 'ui'); - this.loadImage('type_tera', 'ui'); - this.loadAtlas('type_bgs', 'ui'); - - this.loadImage('pb_tray_overlay_player', 'ui'); - this.loadImage('pb_tray_overlay_enemy', 'ui'); - this.loadAtlas('pb_tray_ball', 'ui'); - - this.loadImage('party_bg', 'ui'); - this.loadImage('party_bg_double', 'ui'); - this.loadAtlas('party_slot_main', 'ui'); - this.loadAtlas('party_slot', 'ui'); - this.loadImage('party_slot_overlay_lv', 'ui'); - this.loadImage('party_slot_hp_bar', 'ui'); - this.loadAtlas('party_slot_hp_overlay', 'ui'); - this.loadAtlas('party_pb', 'ui'); - this.loadAtlas('party_cancel', 'ui'); - - this.loadImage('summary_bg', 'ui'); - this.loadImage('summary_overlay_shiny', 'ui'); - this.loadImage('summary_profile', 'ui'); - this.loadImage('summary_status', 'ui'); - this.loadImage('summary_stats', 'ui'); - this.loadImage('summary_stats_overlay_exp', 'ui'); - this.loadImage('summary_moves', 'ui'); - this.loadImage('summary_moves_effect', 'ui'); - this.loadImage('summary_moves_overlay_row', 'ui'); - this.loadImage('summary_moves_overlay_pp', 'ui'); - this.loadAtlas('summary_moves_cursor', 'ui'); - for (let t = 1; t <= 3; t++) - this.loadImage(`summary_tabs_${t}`, 'ui'); - - this.loadImage('starter_select_bg', 'ui'); - this.loadImage('select_cursor', 'ui'); - this.loadImage('select_cursor_highlight', 'ui'); - this.loadImage('select_cursor_highlight_thick', 'ui'); - this.loadImage('select_cursor_pokerus', 'ui'); - this.loadImage('select_gen_cursor', 'ui'); - this.loadImage('select_gen_cursor_highlight', 'ui'); - - this.loadImage('default_bg', 'arenas'); - - this.loadImage('logo', ''); - - // Load arena images - Utils.getEnumValues(Biome).map(bt => { - const btKey = Biome[bt].toLowerCase(); - const isBaseAnimated = btKey === 'end'; - const baseAKey = `${btKey}_a`; - const baseBKey = `${btKey}_b`; - this.loadImage(`${btKey}_bg`, 'arenas'); - if (!isBaseAnimated) - this.loadImage(baseAKey, 'arenas'); - else - this.loadAtlas(baseAKey, 'arenas'); - if (!isBaseAnimated) - this.loadImage(baseBKey, 'arenas'); - else - this.loadAtlas(baseBKey, 'arenas'); - if (getBiomeHasProps(bt)) { - for (let p = 1; p <= 3; p++) { - const isPropAnimated = p === 3 && [ 'power_plant', 'end' ].find(b => b === btKey); - const propKey = `${btKey}_b_${p}`; - if (!isPropAnimated) - this.loadImage(propKey, 'arenas'); - else - this.loadAtlas(propKey, 'arenas'); - } - } - }); - - // Load trainer images - this.loadAtlas('trainer_m_back', 'trainer'); - this.loadAtlas('trainer_m_back_pb', 'trainer'); - this.loadAtlas('trainer_f_back', 'trainer'); - this.loadAtlas('trainer_f_back_pb', 'trainer'); - - Utils.getEnumValues(TrainerType).map(tt => { - const config = trainerConfigs[tt]; - this.loadAtlas(config.getSpriteKey(), 'trainer'); - if (config.doubleOnly || config.hasDouble) - this.loadAtlas(config.getSpriteKey(true), 'trainer'); - }); - - // Load character sprites - this.loadAtlas('c_rival_m', 'character', 'rival_m'); - this.loadAtlas('c_rival_f', 'character', 'rival_f'); - - // Load pokemon-related images - this.loadImage(`pkmn__back__sub`, 'pokemon/back', 'sub.png'); - this.loadImage(`pkmn__sub`, 'pokemon', 'sub.png'); - this.loadAtlas('battle_stats', 'effects'); - this.loadAtlas('shiny', 'effects'); - this.loadImage('tera', 'effects'); - this.loadAtlas('pb_particles', 'effects'); - this.loadImage('evo_sparkle', 'effects'); - this.loadAtlas('tera_sparkle', 'effects'); - this.load.video('evo_bg', 'images/effects/evo_bg.mp4', true); - - this.loadAtlas('pb', ''); - this.loadAtlas('items', ''); - this.loadAtlas('types', ''); - this.loadAtlas('statuses', ''); - this.loadAtlas('categories', ''); - - this.loadAtlas('egg', 'egg'); - this.loadAtlas('egg_crack', 'egg'); - this.loadAtlas('egg_icons', 'egg'); - this.loadAtlas('egg_shard', 'egg'); - this.loadAtlas('egg_lightrays', 'egg'); - Utils.getEnumKeys(GachaType).forEach(gt => { - const key = gt.toLowerCase(); - this.loadImage(`gacha_${key}`, 'egg'); - this.loadAtlas(`gacha_underlay_${key}`, 'egg'); - }); - this.loadImage('gacha_glass', 'egg'); - this.loadImage('gacha_eggs', 'egg'); - this.loadAtlas('gacha_hatch', 'egg'); - this.loadImage('gacha_knob', 'egg'); - - this.loadImage('egg_list_bg', 'ui'); - - for (let i = 0; i < 10; i++) - this.loadAtlas(`pokemon_icons_${i}`, ''); - - this.loadSe('select'); - this.loadSe('menu_open'); - this.loadSe('hit'); - this.loadSe('hit_strong'); - this.loadSe('hit_weak'); - this.loadSe('stat_up'); - this.loadSe('stat_down'); - this.loadSe('faint'); - this.loadSe('flee'); - this.loadSe('low_hp'); - this.loadSe('exp'); - this.loadSe('level_up'); - this.loadSe('sparkle'); - this.loadSe('restore'); - this.loadSe('shine'); - this.loadSe('charge'); - this.loadSe('beam'); - this.loadSe('upgrade'); - this.loadSe('buy'); - this.loadSe('achv'); - this.loadSe('error'); - - this.loadSe('pb_rel'); - this.loadSe('pb_throw'); - this.loadSe('pb_bounce_1'); - this.loadSe('pb_bounce_2'); - this.loadSe('pb_move'); - this.loadSe('pb_catch'); - this.loadSe('pb_lock'); - - this.loadSe('pb_tray_enter'); - this.loadSe('pb_tray_ball'); - this.loadSe('pb_tray_empty'); - - this.loadSe('egg_crack'); - this.loadSe('egg_hatch'); - this.loadSe('gacha_dial'); - this.loadSe('gacha_running'); - this.loadSe('gacha_dispense'); - - this.loadSe('PRSFX- Transform', 'battle_anims'); - - this.loadBgm('menu'); - - this.loadBgm('level_up_fanfare', 'bw/level_up_fanfare.mp3'); - this.loadBgm('item_fanfare', 'bw/item_fanfare.mp3'); - this.loadBgm('minor_fanfare', 'bw/minor_fanfare.mp3'); - this.loadBgm('heal', 'bw/heal.mp3'); - this.loadBgm('victory_trainer', 'bw/victory_trainer.mp3'); - this.loadBgm('victory_gym', 'bw/victory_gym.mp3'); - this.loadBgm('victory_champion', 'bw/victory_champion.mp3'); - this.loadBgm('evolution', 'bw/evolution.mp3'); - this.loadBgm('evolution_fanfare', 'bw/evolution_fanfare.mp3'); populateAnims(); - - this.load.plugin('rextexteditplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rextexteditplugin.min.js', true); } create() { @@ -557,6 +284,23 @@ export default class BattleScene extends Phaser.Scene { this.fieldUI = fieldUI; + const transition = this.make.rexTransitionImagePack({ + x: 0, + y: 0, + scale: 6, + key: 'loading_bg', + origin: { x: 0, y: 0 } + }, true); + + transition.transit({ + mode: 'blinds', + ease: 'Cubic.easeInOut', + duration: 1250, + oncomplete: () => transition.destroy() + }); + + this.add.existing(transition); + const uiContainer = this.add.container(0, 0); uiContainer.setDepth(2); uiContainer.setScale(6); diff --git a/src/loading-scene.ts b/src/loading-scene.ts new file mode 100644 index 000000000..9bffdb044 --- /dev/null +++ b/src/loading-scene.ts @@ -0,0 +1,328 @@ +import { GachaType } from "./data/egg"; +import { Biome } from "./data/enums/biome"; +import { TrainerType } from "./data/enums/trainer-type"; +import { trainerConfigs } from "./data/trainer-config"; +import { getBiomeHasProps } from "./field/arena"; +import { SceneBase } from "./scene-base"; +import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme"; +import * as Utils from "./utils"; + +export class LoadingScene extends SceneBase { + constructor() { + super('loading'); + } + + preload() { + const indexFile = Array.from(document.querySelectorAll('script')).map(s => s.src).find(s => /\/index/.test(s)); + if (indexFile) { + const buildIdMatch = /index\-(.*?)\.js$/.exec(indexFile); + if (buildIdMatch) + this.load['cacheBuster'] = buildIdMatch[1]; + } + + this.loadImage('loading_bg', 'arenas'); + this.loadImage('logo', ''); + + // Load menu images + this.loadAtlas('bg', 'ui'); + this.loadImage('command_fight_labels', 'ui'); + this.loadAtlas('prompt', 'ui'); + this.loadImage('cursor', 'ui'); + this.loadImage('cursor_reverse', 'ui'); + for (let wv of Utils.getEnumValues(WindowVariant)) { + for (let w = 1; w <= 5; w++) + this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, 'ui/windows'); + } + this.loadAtlas('namebox', 'ui'); + this.loadImage('pbinfo_player', 'ui'); + this.loadImage('pbinfo_player_mini', 'ui'); + this.loadImage('pbinfo_enemy_mini', 'ui'); + this.loadImage('pbinfo_enemy_boss', 'ui'); + this.loadImage('overlay_lv', 'ui'); + this.loadAtlas('numbers', 'ui'); + this.loadAtlas('numbers_red', 'ui'); + this.loadAtlas('overlay_hp', 'ui'); + this.loadAtlas('overlay_hp_boss', 'ui'); + this.loadImage('overlay_exp', 'ui'); + this.loadImage('icon_owned', 'ui'); + this.loadImage('ability_bar_left', 'ui'); + this.loadImage('party_exp_bar', 'ui'); + this.loadImage('achv_bar', 'ui'); + this.loadImage('achv_bar_2', 'ui'); + this.loadImage('achv_bar_3', 'ui'); + this.loadImage('achv_bar_4', 'ui'); + this.loadImage('shiny_star', 'ui', 'shiny.png'); + this.loadImage('icon_spliced', 'ui'); + this.loadImage('icon_tera', 'ui'); + this.loadImage('type_tera', 'ui'); + this.loadAtlas('type_bgs', 'ui'); + + this.loadImage('pb_tray_overlay_player', 'ui'); + this.loadImage('pb_tray_overlay_enemy', 'ui'); + this.loadAtlas('pb_tray_ball', 'ui'); + + this.loadImage('party_bg', 'ui'); + this.loadImage('party_bg_double', 'ui'); + this.loadAtlas('party_slot_main', 'ui'); + this.loadAtlas('party_slot', 'ui'); + this.loadImage('party_slot_overlay_lv', 'ui'); + this.loadImage('party_slot_hp_bar', 'ui'); + this.loadAtlas('party_slot_hp_overlay', 'ui'); + this.loadAtlas('party_pb', 'ui'); + this.loadAtlas('party_cancel', 'ui'); + + this.loadImage('summary_bg', 'ui'); + this.loadImage('summary_overlay_shiny', 'ui'); + this.loadImage('summary_profile', 'ui'); + this.loadImage('summary_status', 'ui'); + this.loadImage('summary_stats', 'ui'); + this.loadImage('summary_stats_overlay_exp', 'ui'); + this.loadImage('summary_moves', 'ui'); + this.loadImage('summary_moves_effect', 'ui'); + this.loadImage('summary_moves_overlay_row', 'ui'); + this.loadImage('summary_moves_overlay_pp', 'ui'); + this.loadAtlas('summary_moves_cursor', 'ui'); + for (let t = 1; t <= 3; t++) + this.loadImage(`summary_tabs_${t}`, 'ui'); + + this.loadImage('starter_select_bg', 'ui'); + this.loadImage('select_cursor', 'ui'); + this.loadImage('select_cursor_highlight', 'ui'); + this.loadImage('select_cursor_highlight_thick', 'ui'); + this.loadImage('select_cursor_pokerus', 'ui'); + this.loadImage('select_gen_cursor', 'ui'); + this.loadImage('select_gen_cursor_highlight', 'ui'); + + this.loadImage('default_bg', 'arenas'); + // Load arena images + Utils.getEnumValues(Biome).map(bt => { + const btKey = Biome[bt].toLowerCase(); + const isBaseAnimated = btKey === 'end'; + const baseAKey = `${btKey}_a`; + const baseBKey = `${btKey}_b`; + this.loadImage(`${btKey}_bg`, 'arenas'); + if (!isBaseAnimated) + this.loadImage(baseAKey, 'arenas'); + else + this.loadAtlas(baseAKey, 'arenas'); + if (!isBaseAnimated) + this.loadImage(baseBKey, 'arenas'); + else + this.loadAtlas(baseBKey, 'arenas'); + if (getBiomeHasProps(bt)) { + for (let p = 1; p <= 3; p++) { + const isPropAnimated = p === 3 && [ 'power_plant', 'end' ].find(b => b === btKey); + const propKey = `${btKey}_b_${p}`; + if (!isPropAnimated) + this.loadImage(propKey, 'arenas'); + else + this.loadAtlas(propKey, 'arenas'); + } + } + }); + + // Load trainer images + this.loadAtlas('trainer_m_back', 'trainer'); + this.loadAtlas('trainer_m_back_pb', 'trainer'); + this.loadAtlas('trainer_f_back', 'trainer'); + this.loadAtlas('trainer_f_back_pb', 'trainer'); + + Utils.getEnumValues(TrainerType).map(tt => { + const config = trainerConfigs[tt]; + this.loadAtlas(config.getSpriteKey(), 'trainer'); + if (config.doubleOnly || config.hasDouble) + this.loadAtlas(config.getSpriteKey(true), 'trainer'); + }); + + // Load character sprites + this.loadAtlas('c_rival_m', 'character', 'rival_m'); + this.loadAtlas('c_rival_f', 'character', 'rival_f'); + + // Load pokemon-related images + this.loadImage(`pkmn__back__sub`, 'pokemon/back', 'sub.png'); + this.loadImage(`pkmn__sub`, 'pokemon', 'sub.png'); + this.loadAtlas('battle_stats', 'effects'); + this.loadAtlas('shiny', 'effects'); + this.loadImage('tera', 'effects'); + this.loadAtlas('pb_particles', 'effects'); + this.loadImage('evo_sparkle', 'effects'); + this.loadAtlas('tera_sparkle', 'effects'); + this.load.video('evo_bg', 'images/effects/evo_bg.mp4', true); + + this.loadAtlas('pb', ''); + this.loadAtlas('items', ''); + this.loadAtlas('types', ''); + this.loadAtlas('statuses', ''); + this.loadAtlas('categories', ''); + + this.loadAtlas('egg', 'egg'); + this.loadAtlas('egg_crack', 'egg'); + this.loadAtlas('egg_icons', 'egg'); + this.loadAtlas('egg_shard', 'egg'); + this.loadAtlas('egg_lightrays', 'egg'); + Utils.getEnumKeys(GachaType).forEach(gt => { + const key = gt.toLowerCase(); + this.loadImage(`gacha_${key}`, 'egg'); + this.loadAtlas(`gacha_underlay_${key}`, 'egg'); + }); + this.loadImage('gacha_glass', 'egg'); + this.loadImage('gacha_eggs', 'egg'); + this.loadAtlas('gacha_hatch', 'egg'); + this.loadImage('gacha_knob', 'egg'); + + this.loadImage('egg_list_bg', 'ui'); + + for (let i = 0; i < 10; i++) + this.loadAtlas(`pokemon_icons_${i}`, ''); + + this.loadSe('select'); + this.loadSe('menu_open'); + this.loadSe('hit'); + this.loadSe('hit_strong'); + this.loadSe('hit_weak'); + this.loadSe('stat_up'); + this.loadSe('stat_down'); + this.loadSe('faint'); + this.loadSe('flee'); + this.loadSe('low_hp'); + this.loadSe('exp'); + this.loadSe('level_up'); + this.loadSe('sparkle'); + this.loadSe('restore'); + this.loadSe('shine'); + this.loadSe('charge'); + this.loadSe('beam'); + this.loadSe('upgrade'); + this.loadSe('buy'); + this.loadSe('achv'); + this.loadSe('error'); + + this.loadSe('pb_rel'); + this.loadSe('pb_throw'); + this.loadSe('pb_bounce_1'); + this.loadSe('pb_bounce_2'); + this.loadSe('pb_move'); + this.loadSe('pb_catch'); + this.loadSe('pb_lock'); + + this.loadSe('pb_tray_enter'); + this.loadSe('pb_tray_ball'); + this.loadSe('pb_tray_empty'); + + this.loadSe('egg_crack'); + this.loadSe('egg_hatch'); + this.loadSe('gacha_dial'); + this.loadSe('gacha_running'); + this.loadSe('gacha_dispense'); + + this.loadSe('PRSFX- Transform', 'battle_anims'); + + this.loadBgm('menu'); + + this.loadBgm('level_up_fanfare', 'bw/level_up_fanfare.mp3'); + this.loadBgm('item_fanfare', 'bw/item_fanfare.mp3'); + this.loadBgm('minor_fanfare', 'bw/minor_fanfare.mp3'); + this.loadBgm('heal', 'bw/heal.mp3'); + this.loadBgm('victory_trainer', 'bw/victory_trainer.mp3'); + this.loadBgm('victory_gym', 'bw/victory_gym.mp3'); + this.loadBgm('victory_champion', 'bw/victory_champion.mp3'); + this.loadBgm('evolution', 'bw/evolution.mp3'); + this.loadBgm('evolution_fanfare', 'bw/evolution_fanfare.mp3'); + + this.load.plugin('rextexteditplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rextexteditplugin.min.js', true); + + this.loadLoadingScreen(); + } + + loadLoadingScreen() { + const bg = this.add.image(0, 0, ''); + bg.setOrigin(0, 0); + bg.setScale(6); + bg.setVisible(false); + + const graphics = this.add.graphics(); + + graphics.lineStyle(4, 0xff00ff, 1).setDepth(10); + + const progressBar = this.add.graphics(); + const progressBox = this.add.graphics(); + progressBox.lineStyle(5, 0xff00ff, 1.0); + progressBox.fillStyle(0x222222, 0.8); + + const width = this.cameras.main.width; + const height = this.cameras.main.height; + + const logo = this.add.image(width / 2, 240, ''); + logo.setVisible(false); + logo.setOrigin(0.5, 0.5); + logo.setScale(4); + + const percentText = this.make.text({ + x: width / 2, + y: height / 2 - 24, + text: '0%', + style: { + font: "72px emerald", + color: "#ffffff", + }, + }); + percentText.setOrigin(0.5, 0.5); + + const assetText = this.make.text({ + x: width / 2, + y: height / 2 + 48, + text: "", + style: { + font: "48px emerald", + color: "#ffffff", + }, + }); + assetText.setOrigin(0.5, 0.5); + + this.load.on("progress", (value: string) => { + const parsedValue = parseFloat(value); + percentText.setText(`${Math.floor(parsedValue * 100)}%`); + progressBar.clear(); + progressBar.fillStyle(0xffffff, 0.8); + progressBar.fillRect(width / 2 - 320, 360, 640 * parsedValue, 64); + }); + + this.load.on("fileprogress", file => { + assetText.setText(`Loading asset: ${file.key}`); + }); + + this.load.on('filecomplete', key => { + switch (key) { + case 'loading_bg': + bg.setVisible(true); + bg.setTexture('loading_bg'); + break; + case 'logo': + logo.setVisible(true); + logo.setTexture('logo'); + break; + } + }); + + this.load.on("complete", () => { + bg.destroy(); + logo.destroy(); + progressBar.destroy(); + progressBox.destroy(); + percentText.destroy(); + assetText.destroy(); + }); + } + + get gameHeight() { + return this.game.config.height as number; + } + + get gameWidth() { + return this.game.config.width as number; + } + + async create() { + this.scene.start("battle"); + } +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index befb6abd5..fce9a3dca 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,8 @@ import UIPlugin from 'phaser3-rex-plugins/templates/ui/ui-plugin'; import BBCodeTextPlugin from 'phaser3-rex-plugins/plugins/bbcodetext-plugin'; import InputTextPlugin from 'phaser3-rex-plugins/plugins/inputtext-plugin.js'; import BBCodeText from 'phaser3-rex-plugins/plugins/bbcodetext'; +import TransitionImagePackPlugin from 'phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js'; +import { LoadingScene } from './loading-scene'; const config: Phaser.Types.Core.GameConfig = { type: Phaser.WEBGL, @@ -24,6 +26,10 @@ const config: Phaser.Types.Core.GameConfig = { key: 'rexBBCodeTextPlugin', plugin: BBCodeTextPlugin, start: true + }, { + key: 'rexTransitionImagePackPlugin', + plugin: TransitionImagePackPlugin, + start: true }], scene: [{ key: 'rexUI', @@ -44,7 +50,7 @@ const config: Phaser.Types.Core.GameConfig = { }, pixelArt: true, pipeline: [ InvertPostFX ] as unknown as Phaser.Types.Core.PipelineConfig, - scene: [ BattleScene ], + scene: [ LoadingScene, BattleScene ], version: version }; diff --git a/src/scene-base.ts b/src/scene-base.ts new file mode 100644 index 000000000..1098788c4 --- /dev/null +++ b/src/scene-base.ts @@ -0,0 +1,62 @@ +export const legacyCompatibleImages: string[] = []; + +export class SceneBase extends Phaser.Scene { + constructor(config?: string | Phaser.Types.Scenes.SettingsConfig) { + super(config); + } + + loadImage(key: string, folder: string, filename?: string) { + if (!filename) + filename = `${key}.png`; + this.load.image(key, `images/${folder}/${filename}`); + if (folder.startsWith('ui')) { + legacyCompatibleImages.push(key); + folder = folder.replace('ui', 'ui/legacy'); + this.load.image(`${key}_legacy`, `images/${folder}/${filename}`); + } + } + + loadSpritesheet(key: string, folder: string, size: integer, filename?: string) { + if (!filename) + filename = `${key}.png`; + this.load.spritesheet(key, `images/${folder}/${filename}`, { frameWidth: size, frameHeight: size }); + if (folder.startsWith('ui')) { + legacyCompatibleImages.push(key); + folder = folder.replace('ui', 'ui/legacy'); + this.load.spritesheet(`${key}_legacy`, `images/${folder}/${filename}`, { frameWidth: size, frameHeight: size }); + } + } + + loadAtlas(key: string, folder: string, filenameRoot?: string) { + if (!filenameRoot) + filenameRoot = key; + if (folder) + folder += '/'; + this.load.atlas(key, `images/${folder}${filenameRoot}.png`, `images/${folder}/${filenameRoot}.json`); + if (folder.startsWith('ui')) { + legacyCompatibleImages.push(key); + folder = folder.replace('ui', 'ui/legacy'); + this.load.atlas(`${key}_legacy`, `images/${folder}${filenameRoot}.png`, `images/${folder}/${filenameRoot}.json`); + } + } + + loadSe(key: string, folder?: string, filenames?: string | string[]) { + if (!filenames) + filenames = `${key}.wav`; + if (!folder) + folder = ''; + else + folder += '/'; + if (!Array.isArray(filenames)) + filenames = [ filenames ]; + for (let f of filenames as string[]) { + this.load.audio(key, `audio/se/${folder}${f}`); + } + } + + loadBgm(key: string, filename?: string) { + if (!filename) + filename = `${key}.mp3`; + this.load.audio(key, `audio/bgm/${filename}`); + } +} \ No newline at end of file diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index d992f0166..ba5ddc859 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -1,9 +1,10 @@ import BattleScene, { Button } from "../battle-scene"; import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; import { Mode } from "./ui"; -import { TextStyle, addTextInputObject, addTextObject, getTextColor } from "./text"; +import { TextStyle, addTextInputObject, addTextObject } from "./text"; import { WindowVariant, addWindow } from "./ui-theme"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; +import * as Utils from "../utils"; export interface FormModalConfig extends ModalConfig { errorMessage?: string; @@ -90,6 +91,17 @@ export abstract class FormModalUiHandler extends ModalUiHandler { }); } + this.modalContainer.y += 24; + this.modalContainer.setAlpha(0); + + this.scene.tweens.add({ + targets: this.modalContainer, + duration: Utils.fixedInt(1000), + ease: 'Sine.easeInOut', + y: '-=24', + alpha: 1 + }); + return true; } diff --git a/src/ui/ui-theme.ts b/src/ui/ui-theme.ts index 26ba4be70..ebae817b1 100644 --- a/src/ui/ui-theme.ts +++ b/src/ui/ui-theme.ts @@ -1,5 +1,6 @@ import { UiTheme } from "#app/enums/ui-theme"; -import BattleScene, { legacyCompatibleImages } from "../battle-scene"; +import { legacyCompatibleImages } from "#app/scene-base"; +import BattleScene from "../battle-scene"; export enum WindowVariant { NORMAL,