src/loading-scene.ts
Rama beta · réplica de lectura del repositorio original.
import { timedEventManager } from "#app/global-event-manager";
import { globalScene } from "#app/global-scene";
import { activeOverrides } from "#app/overrides";
import { SceneBase } from "#app/scene-base";
import { isMobile } from "#app/touch-controls";
import { BiomeId } from "#enums/biome-id";
import { GachaType } from "#enums/gacha-types";
import { getBiomeHasProps } from "#field/arena";
import { initializeGame } from "#init/init";
import { CacheBustedLoaderPlugin } from "#plugins/cache-busted-loader-plugin";
import { getWindowVariantSuffix, WindowVariant } from "#ui/ui-theme";
import { hasAllLocalizedSprites, localPing } from "#utils/common";
import { enumValueToKey, getEnumValues } from "#utils/enums";
import i18next from "i18next";
import type { GameObjects } from "phaser";
import Phaser from "phaser";
export class LoadingScene extends SceneBase {
public static readonly KEY = "loading";
readonly LOAD_EVENTS = Phaser.Loader.Events;
constructor() {
super(LoadingScene.KEY);
Phaser.Plugins.PluginCache.register("Loader", CacheBustedLoaderPlugin, "load");
}
preload() {
localPing();
const startingBiome = activeOverrides.STARTING_BIOME_OVERRIDE ?? globalScene?.arena?.biomeId ?? BiomeId.TOWN;
// TODO: Categorize these into sub-methods that make sense
// I'm 99.9% sure the order doesn't matter here,
// so we should organize these based on type more strongly
// Load menu images
this.loadImage("loading_bg", "arenas")
.loadImage("logo", "")
.loadImage("logo_fake", "")
.loadImage("snow", "")
.loadAtlas("bg", "ui")
.loadAtlas("prompt", "ui")
.loadImage("candy", "ui")
.loadImage("candy_overlay", "ui")
.loadImage("friendship", "ui")
.loadImage("friendship_overlay", "ui")
.loadImage("cursor", "ui")
.loadImage("cursor_reverse", "ui")
.loadWindowVariants()
.loadAtlas("namebox", "ui")
.loadImage("pbinfo_player", "ui")
.loadImage("pbinfo_player_stats", "ui")
.loadImage("pbinfo_player_mini", "ui")
.loadImage("pbinfo_player_mini_stats", "ui")
.loadAtlas("pbinfo_player_type", "ui")
.loadAtlas("pbinfo_player_type1", "ui")
.loadAtlas("pbinfo_player_type2", "ui")
.loadImage("pbinfo_enemy_mini", "ui")
.loadImage("pbinfo_enemy_mini_stats", "ui")
.loadImage("pbinfo_enemy_boss", "ui")
.loadImage("pbinfo_enemy_boss_stats", "ui")
.loadAtlas("pbinfo_enemy_type", "ui")
.loadAtlas("pbinfo_enemy_type1", "ui")
.loadAtlas("pbinfo_enemy_type2", "ui")
.loadAtlas("pbinfo_stat_numbers", "ui")
.loadAtlas("numbers", "ui")
.loadAtlas("numbers_red", "ui")
.loadAtlas("overlay_hp", "ui")
.loadAtlas("overlay_hp_boss", "ui")
.loadImage("overlay_exp", "ui")
.loadImage("icon_owned", "ui")
.loadImage("icon_egg_move", "ui")
.loadImage("ability_bar_left", "ui")
.loadImage("ability_bar_right", "ui")
.loadImage("bgm_bar", "ui")
.loadImage("party_exp_bar", "ui")
.loadImage("achv_bar", "ui")
.loadImage("achv_bar_2", "ui")
.loadImage("achv_bar_3", "ui")
.loadImage("achv_bar_4", "ui")
.loadImage("achv_bar_5", "ui")
.loadImage("shiny_star", "ui", "shiny.png")
.loadImage("shiny_star_1", "ui", "shiny_1.png")
.loadImage("shiny_star_2", "ui", "shiny_2.png")
.loadImage("shiny_star_small", "ui", "shiny_small.png")
.loadImage("shiny_star_small_1", "ui", "shiny_small_1.png")
.loadImage("shiny_star_small_2", "ui", "shiny_small_2.png")
.loadImage("favorite", "ui", "favorite.png")
.loadImage("passive_bg", "ui", "passive_bg.png")
.loadAtlas("shiny_icons", "ui")
.loadImage("ha_capsule", "ui", "ha_capsule.png")
.loadImage("champion_ribbon", "ui", "champion_ribbon.png")
.loadImage("champion_ribbon_emerald", "ui", "champion_ribbon_emerald.png")
.loadImage("icon_spliced", "ui")
.loadImage("icon_lock", "ui", "icon_lock.png")
.loadImage("icon_stop", "ui", "icon_stop.png")
.loadImage("icon_tera", "ui")
.loadImage("cursor_tera", "ui")
.loadImage("type_tera", "ui")
.loadAtlas("type_bgs", "ui")
.loadAtlas("button_tera", "ui")
.loadImage("common_egg", "ui")
.loadImage("normal_memory", "ui")
.loadImage("dawn_icon_fg", "ui")
.loadImage("dawn_icon_mg", "ui")
.loadImage("dawn_icon_bg", "ui")
.loadImage("day_icon_fg", "ui")
.loadImage("day_icon_mg", "ui")
.loadImage("day_icon_bg", "ui")
.loadImage("dusk_icon_fg", "ui")
.loadImage("dusk_icon_mg", "ui")
.loadImage("dusk_icon_bg", "ui")
.loadImage("night_icon_fg", "ui")
.loadImage("night_icon_mg", "ui")
.loadImage("night_icon_bg", "ui")
.loadImage("pb_tray_overlay_player", "ui")
.loadImage("pb_tray_overlay_enemy", "ui")
.loadAtlas("pb_tray_ball", "ui")
.loadImage("party_bg", "ui")
.loadImage("party_bg_double", "ui")
.loadImage("party_bg_double_manage", "ui")
.loadAtlas("party_slot_main", "ui")
.loadAtlas("party_slot_main_short", "ui")
.loadAtlas("party_slot", "ui")
.loadImage("party_slot_hp_bar", "ui")
.loadAtlas("party_slot_hp_overlay", "ui")
.loadAtlas("party_pb", "ui")
.loadAtlas("party_cancel", "ui")
.loadAtlas("party_discard", "ui")
.loadAtlas("party_transfer", "ui")
.loadImage("summary_bg", "ui")
.loadImage("summary_profile", "ui")
.loadImage("summary_profile_prompt_z", "ui") // The pixel Z button prompt
.loadImage("summary_profile_prompt_a", "ui") // The pixel A button prompt
.loadImage("summary_status", "ui")
.loadImage("summary_stats", "ui")
.loadImage("summary_stats_overlay_exp", "ui")
.loadImage("summary_moves", "ui")
.loadImage("summary_moves_effect", "ui")
.loadImage("summary_moves_overlay_row", "ui")
.loadAtlas("summary_moves_cursor", "ui")
.loadImage("scroll_bar", "ui")
.loadImage("scroll_bar_handle", "ui")
.loadImage("starter_container_bg", "ui")
.loadImage("starter_select_bg", "ui")
.loadImage("pokedex_summary_bg", "ui")
.loadImage("select_cursor", "ui")
.loadImage("select_cursor_highlight", "ui")
.loadImage("select_cursor_highlight_thick", "ui")
.loadImage("select_cursor_pokerus", "ui")
.loadImage("select_gen_cursor", "ui")
.loadImage("select_gen_cursor_highlight", "ui")
.loadImage("language_icon", "ui")
.loadImage("saving_icon", "ui")
.loadImage("discord_oauth", "ui")
.loadImage("google_oauth", "ui")
.loadImage("settings_icon", "ui")
.loadImage("link_icon", "ui")
.loadImage("unlink_icon", "ui")
.loadImage("default_bg", "arenas")
.loadBiomeImages(startingBiome)
// Load trainer images
.loadAtlas("trainer_m_back", "trainer")
.loadAtlas("trainer_m_back_pb", "trainer")
.loadAtlas("trainer_f_back", "trainer")
.loadAtlas("trainer_f_back_pb", "trainer")
// Load character sprites
.loadAtlas("c_rival_m", "character", "rival_m")
.loadAtlas("c_rival_f", "character", "rival_f")
.loadAtlas("c_halloween_rival_m", "events", "halloween_rival_m")
.loadAtlas("c_halloween_rival_f", "events", "halloween_rival_f")
// Load pokemon-related images
.loadImage("pkmn__back__sub", "pokemon/back", "sub.png")
.loadImage("pkmn__sub", "pokemon", "sub.png")
.loadAtlas("battle_stats", "effects")
.loadAtlas("shiny", "effects")
.loadAtlas("shiny_2", "effects")
.loadAtlas("shiny_3", "effects")
.loadImage("tera", "effects")
.loadAtlas("pb_particles", "effects")
.loadImage("evo_sparkle", "effects")
.loadAtlas("tera_sparkle", "effects")
.loadAtlas("pb", "")
.loadAtlas("items", "");
this.load
.bitmapFont("item-count", "fonts/item-count.png", "fonts/item-count.xml")
.video("evo_bg", "images/effects/evo_bg.mp4", true);
// Get current lang and load the types atlas for it. English will only load types while all other languages will load types and types_<lang>
const lang = i18next.resolvedLanguage ?? "en";
const keySuffix = lang !== "en" && hasAllLocalizedSprites(lang) ? `_${lang}` : "";
this.loadAtlas(`statuses${keySuffix}`, "").loadAtlas(`types${keySuffix}`, "");
for (let t = 1; t <= 3; t++) {
this.loadImage(
`summary_tabs_${t}${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_tabs_${t}${keySuffix}.png`,
);
}
this.loadImage(
`summary_dexnb_label${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_dexnb_label${keySuffix}.png`,
)
.loadImage(
`summary_dexnb_label_overlay_shiny${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_dexnb_label_overlay_shiny${keySuffix}.png`,
)
.loadImage(
`summary_profile_profile_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_profile_profile_title${keySuffix}.png`,
)
.loadImage(
`summary_profile_ability${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_profile_ability${keySuffix}.png`,
)
.loadImage(
`summary_profile_passive${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_profile_passive${keySuffix}.png`,
)
.loadImage(
`summary_profile_memo_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_profile_memo_title${keySuffix}.png`,
)
.loadImage(
`summary_stats_item_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_stats_item_title${keySuffix}.png`,
)
.loadImage(
`summary_stats_stats_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_stats_stats_title${keySuffix}.png`,
)
.loadImage(
`summary_stats_exp_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_stats_exp_title${keySuffix}.png`,
)
.loadImage(
`summary_stats_expbar_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_stats_expbar_title${keySuffix}.png`,
)
.loadImage(
`summary_moves_moves_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_moves_moves_title${keySuffix}.png`,
)
.loadImage(
`summary_moves_descriptions_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_moves_descriptions_title${keySuffix}.png`,
)
.loadImage(
`summary_moves_overlay_pp${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_moves_overlay_pp${keySuffix}.png`,
)
.loadImage(
`summary_moves_effect_title${keySuffix}`,
"ui",
`text_images/${lang}/summary/summary_moves_effect_title${keySuffix}.png`,
)
// in-battle pixel texts
.loadAtlas(`pbinfo_stat${keySuffix}`, "ui", `text_images/${lang}/battle_ui/pbinfo_stat${keySuffix}`) // Pixel text for in-battle stats info tab
.loadImage(`overlay_lv${keySuffix}`, "ui", `text_images/${lang}/battle_ui/overlay_lv${keySuffix}.png`) // Pixel text in-battle 'Lv.'
.loadImage(`overlay_hp_label${keySuffix}`, "ui", `text_images/${lang}/battle_ui/overlay_hp_label${keySuffix}.png`)
.loadImage(
`overlay_hp_label_boss${keySuffix}`,
"ui",
`text_images/${lang}/battle_ui/overlay_hp_label_boss${keySuffix}.png`,
)
.loadImage(
`overlay_exp_label${keySuffix}`,
"ui",
`text_images/${lang}/battle_ui/overlay_exp_label${keySuffix}.png`,
)
.loadImage(
`party_slot_overlay_lv${keySuffix}`,
"ui",
`text_images/${lang}/party_ui/party_slot_overlay_lv${keySuffix}.png`,
)
.loadImage(
`party_slot_overlay_hp${keySuffix}`,
"ui",
`text_images/${lang}/party_ui/party_slot_overlay_hp${keySuffix}.png`,
)
// egg gacha stuff
.loadEventImages(lang)
.loadAtlas("categories", "")
.loadAtlas("egg", "egg")
.loadAtlas("egg_crack", "egg")
.loadAtlas("egg_icons", "egg")
.loadAtlas("egg_shard", "egg")
.loadAtlas("egg_lightrays", "egg")
.loadEggGachaImages()
.loadImage("gacha_glass", "egg")
.loadImage("gacha_eggs", "egg")
.loadAtlas("gacha_hatch", "egg")
.loadImage("gacha_knob", "egg")
.loadImage("egg_list_bg", "ui")
.loadImage("egg_summary_bg", "ui")
.loadImage("end_m", "cg")
.loadImage("end_f", "cg")
.loadPokemonIcons()
.loadImage("encounter_radar", "mystery-encounters") // Mystery Encounter dex progress icon
// settings atlases
.loadAtlas("dualshock", "inputs")
.loadAtlas("procon", "inputs")
.loadAtlas("xbox", "inputs")
.loadAtlas("keyboard", "inputs")
// sound effects
.loadSe("select", "ui")
.loadSe("menu_open", "ui")
.loadSe("error", "ui")
.loadSe("hit")
.loadSe("hit_strong")
.loadSe("hit_weak")
.loadSe("stat_up")
.loadSe("stat_down")
.loadSe("faint")
.loadSe("flee")
.loadSe("low_hp")
.loadSe("exp")
.loadSe("level_up")
.loadSe("sparkle")
.loadSe("restore")
.loadSe("shine")
.loadSe("shing")
.loadSe("charge")
.loadSe("beam")
.loadSe("upgrade")
.loadSe("buy")
.loadSe("achv")
.loadSe("pb_rel")
.loadSe("pb_throw")
.loadSe("pb_bounce_1")
.loadSe("pb_bounce_2")
.loadSe("pb_move")
.loadSe("pb_catch")
.loadSe("pb_lock")
.loadSe("crit_throw")
.loadSe("pb_tray_enter")
.loadSe("pb_tray_ball")
.loadSe("pb_tray_empty")
.loadSe("egg_crack")
.loadSe("egg_hatch")
.loadSe("gacha_dial")
.loadSe("gacha_running")
.loadSe("gacha_dispense")
.loadSe("item_fanfare")
.loadSe("level_up_fanfare")
.loadSe("PRSFX- Transform", "battle_anims");
this.loadLoadingScreen();
initializeGame();
}
private loadLoadingScreen() {
const mobile = isMobile();
const bg = this.add //
.image(0, 0, "")
.setOrigin(0)
.setScale(6)
.setVisible(false);
const graphics = this.add //
.graphics()
.lineStyle(4, 0xff00ff, 1)
.setDepth(10);
const progressBar = this.add.graphics();
const progressBox = this.add //
.graphics()
.lineStyle(5, 0xff00ff, 1.0)
.fillStyle(0x222222, 0.8);
const width = this.cameras.main.width;
const height = this.cameras.main.height;
const midWidth = width / 2;
const midHeight = height / 2;
const logo = this.add //
.image(midWidth, 240, "")
.setVisible(false)
.setOrigin(0.5, 0.5)
.setScale(4);
const percentText = this.make
.text({
x: midWidth,
y: midHeight - 24,
text: "0%",
style: {
font: "72px emerald",
color: "#ffffff",
},
})
.setOrigin(0.5, 0.5);
const assetText = this.make
.text({
x: midWidth,
y: midHeight + 48,
text: "",
style: {
font: "48px emerald",
color: "#ffffff",
},
})
.setOrigin(0.5, 0.5);
const disclaimerText = this.make
.text({
x: midWidth,
y: assetText.y + 152,
text: i18next.t("menu:disclaimer"),
style: {
font: "72px emerald",
color: "#DA3838",
},
})
.setOrigin(0.5, 0.5);
const disclaimerDescriptionText = this.make
.text({
x: midWidth,
y: disclaimerText.y + 120,
text: i18next.t("menu:disclaimerDescription"),
style: {
font: "48px emerald",
color: "#ffffff",
align: "center",
},
})
.setOrigin(0.5, 0.5);
const loadingGraphics: (GameObjects.Image | GameObjects.Graphics | GameObjects.Text)[] = [];
loadingGraphics.push(
bg,
graphics,
progressBar,
progressBox,
logo,
percentText,
assetText,
disclaimerText,
disclaimerDescriptionText,
);
if (!mobile) {
loadingGraphics.forEach(g => {
g.setVisible(false);
});
}
const intro = this.add
.video(0, 0)
.setOrigin(0)
.setScale(3)
.once(Phaser.GameObjects.Events.VIDEO_COMPLETE, (video: Phaser.GameObjects.Video) => {
this.tweens.add({
targets: intro,
duration: 500,
alpha: 0,
ease: "Sine.easeIn",
onComplete: () => video.destroy(),
});
for (const g of loadingGraphics) {
g.setVisible(true);
}
});
this.load
.once(this.LOAD_EVENTS.START, () => {
// videos do not need to be preloaded
intro.loadURL("images/intro_dark.mp4", true);
if (mobile) {
intro.video?.setAttribute("webkit-playsinline", "webkit-playsinline");
intro.video?.setAttribute("playsinline", "playsinline");
}
intro.play();
})
.on(this.LOAD_EVENTS.PROGRESS, (progress: number) => {
percentText.setText(`${Math.floor(progress * 100)}%`);
// need to reset fill style due to `clear` restting it
progressBar
.clear()
.fillStyle(0xffffff, 0.8)
.fillRect(midWidth - 320, 360, 640 * progress, 64);
})
.on(this.LOAD_EVENTS.FILE_COMPLETE, (key: string) => {
assetText.setText(i18next.t("menu:loadingAsset", { assetName: key }));
switch (key) {
case "loading_bg":
bg.setTexture("loading_bg");
if (mobile) {
bg.setVisible(true);
}
break;
case "logo":
logo.setTexture("logo");
if (mobile) {
logo.setVisible(true);
}
break;
}
})
.on(this.LOAD_EVENTS.COMPLETE, () => {
for (const g of loadingGraphics) {
g.destroy();
}
intro.destroy();
});
}
async create() {
this.events.once(Phaser.Scenes.Events.DESTROY, () => this.handleDestroy());
this.scene.start("battle");
}
handleDestroy() {
console.debug(`Destroying ${LoadingScene.KEY} scene`);
this.load //
.off(this.LOAD_EVENTS.PROGRESS)
.off(this.LOAD_EVENTS.FILE_COMPLETE)
.off(this.LOAD_EVENTS.COMPLETE);
// this.textures.remove("loading_bg"); is removed in BattleScene.launchBattle()
this.children.removeAll(true);
console.debug(`Destroyed ${LoadingScene.KEY} scene`);
}
private loadBiomeImages(startingBiome: BiomeId = BiomeId.TOWN): this {
const biomesToLoad = new Set([BiomeId.TOWN, startingBiome]);
biomesToLoad.forEach(bt => {
const btKey = enumValueToKey(BiomeId, bt).toLowerCase();
const isBaseAnimated = btKey === "end";
const baseAKey = `${btKey}_a`;
const baseBKey = `${btKey}_b`;
this.loadImage(`${btKey}_bg`, "arenas");
if (isBaseAnimated) {
this.loadAtlas(baseAKey, "arenas").loadAtlas(baseBKey, "arenas");
} else {
this.loadImage(baseAKey, "arenas").loadImage(baseBKey, "arenas");
}
if (!getBiomeHasProps(bt)) {
return;
}
for (let p = 1; p <= 3; p++) {
const isPropAnimated = p === 3 && ["power_plant", "end"].includes(btKey);
const propKey = `${btKey}_b_${p}`;
if (isPropAnimated) {
this.loadAtlas(propKey, "arenas");
} else {
this.loadImage(propKey, "arenas");
}
}
});
return this;
}
private loadWindowVariants(): this {
for (const wv of getEnumValues(WindowVariant)) {
for (let w = 1; w <= 5; w++) {
this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, "ui/windows");
}
}
return this;
}
private loadEventImages(lang: string): this {
if (timedEventManager.activeEventHasBanner()) {
const availableLangs = timedEventManager.getEventBannerLangs();
// fallback to EN banner if translation not found
if (!availableLangs.includes(lang)) {
lang = "en";
}
this.loadImage(`${timedEventManager.getEventBannerFilename()}-${lang}`, "events");
}
if (timedEventManager.getLogoKey() !== "logo") {
this.loadImage(timedEventManager.getLogoKey(), "events");
}
return this;
}
private loadEggGachaImages(): this {
for (const gt of Object.keys(GachaType)) {
const key = gt.toLowerCase();
this.loadImage(`gacha_${key}`, "egg").loadAtlas(`gacha_underlay_${key}`, "egg");
}
return this;
}
private loadPokemonIcons(): this {
for (let i = 0; i < 10; i++) {
this.loadAtlas(`pokemon_icons_${i}`, "");
if (i) {
this.loadAtlas(`pokemon_icons_${i}v`, "");
}
}
return this;
}
}