diff --git a/public/images/ui/egg_summary_bg.png b/public/images/ui/egg_summary_bg.png new file mode 100644 index 00000000000..a1111b4f63b Binary files /dev/null and b/public/images/ui/egg_summary_bg.png differ diff --git a/public/images/ui/icon_egg_move.png b/public/images/ui/icon_egg_move.png new file mode 100644 index 00000000000..6af186e9b0c Binary files /dev/null and b/public/images/ui/icon_egg_move.png differ diff --git a/src/loading-scene.ts b/src/loading-scene.ts index ae5149d28f6..9a38480696b 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -80,6 +80,7 @@ export class LoadingScene extends SceneBase { this.loadAtlas("overlay_hp_boss", "ui"); this.loadImage("overlay_exp", "ui"); this.loadImage("icon_owned", "ui"); + this.loadImage("icon_egg_move", "ui"); this.loadImage("ability_bar_left", "ui"); this.loadImage("bgm_bar", "ui"); this.loadImage("party_exp_bar", "ui"); @@ -267,6 +268,7 @@ export class LoadingScene extends SceneBase { this.loadImage("gacha_knob", "egg"); this.loadImage("egg_list_bg", "ui"); + this.loadImage("egg_summary_bg", "ui"); this.loadImage("end_m", "cg"); this.loadImage("end_f", "cg"); diff --git a/src/overrides.ts b/src/overrides.ts index 8b3d628e05e..16af33d34dd 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -29,7 +29,10 @@ import { type ModifierOverride } from "./modifier/modifier-type"; * } * ``` */ -const overrides = {} satisfies Partial>; +const overrides = { + EGG_IMMEDIATE_HATCH_OVERRIDE: true, + EGG_FREE_GACHA_PULLS_OVERRIDE: true +} satisfies Partial>; /** * If you need to add Overrides values for local testing do that inside {@linkcode overrides} diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts index 6f3f0b37905..6e098cef3b5 100644 --- a/src/phases/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -1,5 +1,5 @@ import BattleScene, { AnySound } from "#app/battle-scene.js"; -import { Egg, EGG_SEED } from "#app/data/egg.js"; +import { Egg } from "#app/data/egg.js"; import { EggCountChangedEvent } from "#app/events/egg.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; import { getPokemonNameWithAffix } from "#app/messages.js"; @@ -12,12 +12,17 @@ import { Mode } from "#app/ui/ui.js"; import i18next from "i18next"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import * as Utils from "#app/utils.js"; +import { DexEntry, StarterDataEntry } from "#app/system/game-data.js"; +import { EggLapsePhase } from "./egg-lapse-phase"; + + /** * Class that represents egg hatching */ export class EggHatchPhase extends Phase { /** The egg that is hatching */ private egg: Egg; + private eggHatchData: EggHatchData; /** The number of eggs that are hatching */ private eggsToHatchCount: integer; @@ -58,10 +63,11 @@ export class EggHatchPhase extends Phase { private skipped: boolean; /** The sound effect being played when the egg is hatched */ private evolutionBgm: AnySound; + private hatchScene: EggLapsePhase; - constructor(scene: BattleScene, egg: Egg, eggsToHatchCount: integer) { + constructor(scene: BattleScene, hatchScene: EggLapsePhase, egg: Egg, eggsToHatchCount: integer) { super(scene); - + this.hatchScene = hatchScene; this.egg = egg; this.eggsToHatchCount = eggsToHatchCount; } @@ -307,6 +313,8 @@ export class EggHatchPhase extends Phase { * Function to do the logic and animation of completing a hatch and revealing the Pokemon */ doReveal(): void { + // set the previous dex data so info container can show new unlocks in egg summary + this.eggHatchData.setDex(); const isShiny = this.pokemon.isShiny(); if (this.pokemon.species.subLegendary) { this.scene.validateAchv(achvs.HATCH_SUB_LEGENDARY); @@ -345,7 +353,8 @@ export class EggHatchPhase extends Phase { this.scene.ui.showText(i18next.t("egg:hatchFromTheEgg", { pokemonName: getPokemonNameWithAffix(this.pokemon) }), null, () => { this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { - this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => { + this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then((value) => { + this.eggHatchData.setEggMoveUnlocked(value); this.scene.ui.showText("", 0); this.end(); }); @@ -438,14 +447,404 @@ export class EggHatchPhase extends Phase { * @returns the hatched PlayerPokemon */ generatePokemon(): PlayerPokemon { - let ret: PlayerPokemon; + // let ret: PlayerPokemon; - this.scene.executeWithSeedOffset(() => { - ret = this.egg.generatePlayerPokemon(this.scene); - this.eggMoveIndex = this.egg.eggMoveIndex; + // this.scene.executeWithSeedOffset(() => { + // ret = this.egg.generatePlayerPokemon(this.scene); + // }, this.egg.id, EGG_SEED.toString()); + // this.eggHatchContainer.add(new EggHatchData(this.scene, )) - }, this.egg.id, EGG_SEED.toString()); + // return ret; + this.eggHatchData = this.hatchScene.generatePokemon(this.egg); + return this.eggHatchData.pokemon; + } - return ret!; + // getNewProperties(pokemon: PlayerPokemon) { + // const speciesId = pokemon.species.speciesId; + // let newProperties = {newEggMove: false, newStarter: false}; + + // if (!this.starterData[speciesId].eggMoves) { + // this.starterData[speciesId].eggMoves = 0; + // } + + // const value = Math.pow(2, eggMoveIndex); + +// if (this.starterData[speciesId].eggMoves & value) { +// resolve(false); +// return; +// } +// } +} + +export class EggHatchData { + public pokemon: PlayerPokemon; + public eggMoveIndex: integer; + public eggMoveUnlocked: boolean; + public prevDexEntry: DexEntry; + public prevStarterEntry: StarterDataEntry; + private scene: BattleScene; + + constructor(scene: BattleScene, pokemon: PlayerPokemon, eggMoveIndex: integer) { + this.scene = scene; + this.pokemon = pokemon; + this.eggMoveIndex = eggMoveIndex; + } + + setEggMoveUnlocked(unlocked: boolean) { + this.eggMoveUnlocked = unlocked; + } + + setDex() { + const currDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId]; + const starterDataEntry = this.scene.gameData.starterData[this.pokemon.species.getRootSpeciesId()]; + // this.prevDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId]; + this.prevDexEntry = { + seenAttr: currDexEntry.seenAttr, + caughtAttr: currDexEntry.caughtAttr, + natureAttr: currDexEntry.natureAttr, + seenCount: currDexEntry.seenCount, + caughtCount: currDexEntry.caughtCount, + hatchedCount: currDexEntry.hatchedCount, + ivs: [...currDexEntry.ivs] + }; + this.prevStarterEntry = { + moveset: starterDataEntry.moveset, + eggMoves: starterDataEntry.eggMoves, + candyCount: starterDataEntry.candyCount, + friendship: starterDataEntry.friendship, + abilityAttr: starterDataEntry.abilityAttr, + passiveAttr: starterDataEntry.passiveAttr, + valueReduction: starterDataEntry.valueReduction, + classicWinCount: starterDataEntry.classicWinCount + }; + console.log("setting dex:"); + console.log(this.prevDexEntry); + // export interface DexEntry { + + // } + } + + getDex(): DexEntry { + console.log("getting dex:"); + console.log(this.prevDexEntry); + return this.prevDexEntry; + } + + // function that can be called when doing egg summary to set dex one at a time + updatePokemon(showMessage : boolean = false) { + console.log("setting dex (actual, local):"); + const currDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId]; + console.log(currDexEntry); + console.log(this.prevDexEntry); + this.setDex(); + // this.setDex(); + return new Promise(resolve => { + // this.scene.ui.showText(`${this.pokemonHatched[0].name}`, 0); + this.scene.gameData.setPokemonCaught(this.pokemon, true, true, showMessage).then(() => { + //TODO pass through egg move updates + // console.log("set IVs"); + this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); + // console.log("set egg moves"); + this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex, showMessage).then((value) => { + console.log(value); + this.eggMoveUnlocked = value; + console.log("updates complete, logging actual dex and local dexEntry"); + const currDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId]; + console.log(currDexEntry); + console.log(this.prevDexEntry); + + resolve(); + }); + }); + }); + } + + getEggMove() { + // TODO easy function to get egg move for display (or no egg move) + } +} + +export class EggSummaryPhase extends Phase { + private egg: Egg; + private eggHatchData: EggHatchData[]; + private showMessages: boolean; + + private eggHatchHandler: EggHatchSceneHandler; + private eggHatchContainer: Phaser.GameObjects.Container; + private eggHatchBg: Phaser.GameObjects.Image; + private pokemonBg: Phaser.GameObjects.Image; + private eggHatchOverlay: Phaser.GameObjects.Rectangle; + + private infoContainer: PokemonInfoContainer; + private spriteContainers: Phaser.GameObjects.Container[]; + private shinyIcons: Phaser.GameObjects.Image[]; + private hiddenAbilityIcons: Phaser.GameObjects.Image[]; + private pokeballIcons: Phaser.GameObjects.Image[]; + private eggMoveIcons: Phaser.GameObjects.Image[]; + private infoContainers: PokemonInfoContainer[]; + constructor(scene: BattleScene, eggHatchData: EggHatchData[]) { + super(scene); + this.eggHatchData = eggHatchData; + } + + start() { + super.start(); + + // 55 pokemon total now + // for (let i = 0; i < 44; i++) { + // this.pokemonHatched.push(this.scene.addPlayerPokemon(getPokemonSpecies(Species.PIKACHU), 1, undefined, undefined, undefined, false)); + // } + + // for (const eggInfo of this.eggHatchData) { + // eggInfo.updatePokemon(false); + // } + + const updateNextPokemon = (i: integer) => { + console.log(i); + if (i >= this.eggHatchData.length) { + console.log("displayed all pokemon"); + this.scene.ui.setModeForceTransition(Mode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => { + this.scene.fadeOutBgm(null, false); + + this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler; + + this.eggHatchContainer = this.eggHatchHandler.eggHatchContainer; + }); + + // this.scene.ui.showText(" ", null, () => { + // // this.scene.ui.showText(null, 0); + // // this.scene.tweens.add({ + // // duration: Utils.fixedInt(3000), + // // targets: this.eggHatchOverlay, + // // alpha: 0, + // // ease: "Cubic.easeOut" + // console.log("displayed all pokemon"); + // // TODO change end to be called by UI + // // this.end(); + // }, null, true); + + } else { + this.eggHatchData[i].updatePokemon().then(() => { + console.log("updating next pokemon"); + if (i < this.eggHatchData.length) { + updateNextPokemon(i + 1); + } + }); + } + }; + updateNextPokemon(0); + + + // this.scene.ui.setModeForceTransition(Mode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => { + + // this.scene.fadeOutBgm(null, false); + + // this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler; + + // this.eggHatchContainer = this.eggHatchHandler.eggHatchContainer; + + // }); + + //////////////// old method + + + // this.eggHatchBg = this.scene.add.image(0, 0, "egg_list_bg"); + // this.pokemonBg = this.scene.add.image(0, 0, "starter_container_bg"); + // this.eggHatchContainer.add(this.eggHatchBg); + // this.eggHatchContainer.add(this.pokemonBg); + // this.eggHatchBg.setOrigin(0, 0); + // this.pokemonBg.setOrigin(0.3,0); + // this.pokemonBg.setDepth(1); + // this.pokemonBg.setScale(1,1); + + // this.eggHatchOverlay = this.scene.add.rectangle(0, -this.scene.game.canvas.height / 6, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0xFFFFFF); + // this.eggHatchOverlay.setOrigin(0, 0); + // this.eggHatchOverlay.setAlpha(0); + // this.scene.fieldUI.add(this.eggHatchOverlay); + + // this.infoContainer = new PokemonInfoContainer(this.scene); + // this.infoContainer.setup(); + // this.eggHatchContainer.add(this.infoContainer); + + + // this.spriteContainers = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const container = this.scene.add.container(0, 0); + // if (i) { + // container.setVisible(false); + // } + // this.eggHatchContainer.add(container); + // return container; + // }); + + // //TODO format grid properly with pokemon sprites + // let i = 0; + // let cols = 11; + // let size = 22; + // if (this.pokemonHatched.length >= 50) { + // cols = 13; + // size = 14; + // } + // const scale_size = size * 2; + + // this.shinyIcons = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const x = (i % cols) * size; + // const y = Math.floor(i / cols) * size; + // const ret = this.scene.add.image(x + 0.1 * size, y + 0.2 * size, "shiny_star_small"); + // ret.setOrigin(0, 0); + // ret.setScale(size / scale_size); + // ret.setVisible(true); + // this.eggHatchContainer.add(ret); + // return ret; + // }); + + // this.hiddenAbilityIcons = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const x = (i % cols) * size; + // const y = Math.floor(i / cols) * size; + // const ret = this.scene.add.image(x + 0.5 * size, y + 0.9 * size, "ha_capsule"); + // ret.setOrigin(0, 0); + // ret.setScale(size / scale_size); + // ret.setVisible(true); + // this.eggHatchContainer.add(ret); + // return ret; + // }); + + // this.pokeballIcons = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const x = (i % cols) * size; + // const y = Math.floor(i / cols) * size; + // const ret = this.scene.add.image(x+ 0.1 * size, y + 0.9 * size, "icon_owned"); + // ret.setOrigin(0, 0); + // ret.setScale(size / scale_size); + // ret.setVisible(true); + // this.eggHatchContainer.add(ret); + // return ret; + // }); + + // this.eggMoveIcons = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const x = (i % cols) * size; + // const y = Math.floor(i / cols) * size; + // const ret = this.scene.add.image(x + 0.8 * size, y + 0.9 * size, "icon_owned"); + // ret.setOrigin(0, 0); + // ret.setScale(size / scale_size); + // ret.setVisible(true); + // ret.setTint(0.5); + // this.eggHatchContainer.add(ret); + // return ret; + // }); + + // this.infoContainers = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // const ret = new PokemonInfoContainer(this.scene); + // ret.setup(); + // ret.show(this.pokemonHatched[i]); + // this.eggHatchContainer.add(ret); + // return ret; + // }); + + // for (const displayPokemon of this.pokemonHatched) { + // console.log(displayPokemon); + // // const x = (index % 9) * 18; + // // const y = Math.floor(index / 9) * 18; + // const x = (i % cols) * size; + // const y = Math.floor(i / cols) * size; + // const icon = this.scene.add.sprite(x-2, y+2, displayPokemon.species.getIconAtlasKey(displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // icon.setScale(size / (scale_size)); + // icon.setOrigin(0, 0); + // icon.setFrame(displayPokemon.species.getIconId(displayPokemon.gender === Gender.FEMALE, displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // // this.checkIconId(icon, displayPokemon.species, displayPokemon.female, displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant); + // this.spriteContainers[i].add(icon); + // this.spriteContainers[i].setVisible(true); + + // // const cursorObj = this.scene.add.image(x, y, "select_cursor_pokerus"); + // // cursorObj.setVisible(true); + // // cursorObj.setOrigin(0, 0); + // // cursorObj.setScale(size / scale_size * 2); + // // this.spriteContainers[i].add(cursorObj); + + // // DONE shiny icon funcitonality for variants + // // TODO test shiny icons + // this.shinyIcons[i].setVisible(displayPokemon.shiny); + // this.shinyIcons[i].setTint(getVariantTint(displayPokemon.variant)); + // // this.shinyIcons[i].setTint(getVariantTint(speciesVariants[v] === DexAttr.DEFAULT_VARIANT ? 0 : speciesVariants[v] === DexAttr.VARIANT_2 ? 1 : 2)); + // // DONE new pokemon / catch icon functionality + // // TODO test for new pokemon + // const dexEntry = this.scene.gameData.dexData[this.pokemonHatched[i].species.speciesId]; + // const caughtAttr = dexEntry.caughtAttr; + // this.pokeballIcons[i].setVisible(!caughtAttr); + // // this.pokeballIcons[i].setVisible(this.scene.gameData.dexData[displayPokemon.species.speciesId].caughtAttr) + // // DONE? hidden ability icon functionality + // // TODO test hidden abilities / ask + // this.hiddenAbilityIcons[i].setVisible((displayPokemon.abilityIndex >= 2)); + + // // TODO new egg move icon functionality + // this.eggMoveIcons[i].setVisible(true); + // i++; + // } + + + + // // for(const ret of this.pokemonHatched) { + // console.log(this.pokemonHatched); + // console.log(this.newEggMoves); + + + // this.scene.ui.showText(`${this.pokemonHatched.length} eggs hatched. Skip messages?`, 0); + // this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { + // console.log("messages skipped"); + // this.showMessages = false; + // updateNextPokemon(0); + // }, () => { + // console.log("messages shown"); + // this.showMessages = true; + // updateNextPokemon(0); + // } + // ); + // this.scene.ui.showText(`${this.pokemonHatched.length} eggs hatched. Skip messages?`, null, () => { + // this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { + // this.scene.ui.setMode(Mode.MESSAGE); + // this.showMessages = false; + // updateNextPokemon(0); + // }, () => { + // this.scene.ui.setMode(Mode.MESSAGE); + // this.showMessages = true; + // updateNextPokemon(0); + // } + + + + // }); + } + + // updatePokemon(pokemon: PlayerPokemon, eggMoveIndex: integer, showMessage : boolean = false) { + // console.log(pokemon); + // return new Promise(resolve => { + // // this.scene.ui.showText(`${this.pokemonHatched[0].name}`, 0); + // this.scene.gameData.setPokemonCaught(pokemon, true, true, showMessage).then(() => { + // //TODO pass through egg move updates + // // console.log("set IVs"); + // this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs); + // // console.log("set egg moves"); + // this.scene.gameData.setEggMoveUnlocked(pokemon.species, eggMoveIndex, showMessage).then((value) => { + // if (value) { + // this.eggMoveUnlocks.push(true); + // console.log("new egg move?"); + // } else { + // this.eggMoveUnlocks.push(false); + // } + // resolve(); + // }); + // }); + // }); + // } + + end() { + console.log("ended egg hatch summary phase"); + this.scene.tweens.add({ + duration: Utils.fixedInt(250), + targets: this.eggHatchOverlay, + alpha: 0, + ease: "Cubic.easeOut" + }); + this.eggHatchHandler.clear(); + this.scene.time.delayedCall(250, () => this.scene.setModifiersVisible(true)); + super.end(); } } diff --git a/src/phases/egg-lapse-phase.ts b/src/phases/egg-lapse-phase.ts index 50d7106f229..303085be543 100644 --- a/src/phases/egg-lapse-phase.ts +++ b/src/phases/egg-lapse-phase.ts @@ -1,11 +1,16 @@ import BattleScene from "#app/battle-scene.js"; -import { Egg } from "#app/data/egg.js"; +import { Egg, EGG_SEED } from "#app/data/egg.js"; import { Phase } from "#app/phase.js"; import i18next from "i18next"; import Overrides from "#app/overrides"; -import { EggHatchPhase } from "./egg-hatch-phase"; +import { EggHatchData, EggHatchPhase, EggSummaryPhase } from "./egg-hatch-phase"; +import { Mode } from "#app/ui/ui.js"; +import { achvs } from "#app/system/achv.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; export class EggLapsePhase extends Phase { + + private eggHatchData: EggHatchData[] = []; constructor(scene: BattleScene) { super(scene); } @@ -17,19 +22,95 @@ export class EggLapsePhase extends Phase { return Overrides.EGG_IMMEDIATE_HATCH_OVERRIDE ? true : --egg.hatchWaves < 1; }); - let eggCount: integer = eggsToHatch.length; + let eggsToHatchCount: integer = eggsToHatch.length; + this.eggHatchData= []; + if (eggsToHatchCount > 0) { - if (eggCount) { - this.scene.queueMessage(i18next.t("battle:eggHatching")); - - for (const egg of eggsToHatch) { - this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg, eggCount)); - if (eggCount > 0) { - eggCount--; + if (eggsToHatchCount >= 1) { + this.scene.ui.showText(i18next.t("battle:eggHatching"), 0, () => { + // show prompt for skip + this.scene.ui.showText("Lots of eggs ?", 0); + this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { + for (const egg of eggsToHatch) { + this.hatchEggSilently(egg); + } + this.scene.unshiftPhase(new EggSummaryPhase(this.scene, this.eggHatchData)); + this.end(); + }, () => { + for (const egg of eggsToHatch) { + this.scene.unshiftPhase(new EggHatchPhase(this.scene, this, egg, eggsToHatchCount)); + eggsToHatchCount--; + } + this.scene.unshiftPhase(new EggSummaryPhase(this.scene, this.eggHatchData)); + this.end(); + } + ); + }, 100, true); + } else { + this.scene.queueMessage(i18next.t("battle:eggHatching")); + for (const egg of eggsToHatch) { + this.scene.unshiftPhase(new EggHatchPhase(this.scene, this, egg, eggsToHatchCount)); + eggsToHatchCount--; } + this.scene.unshiftPhase(new EggSummaryPhase(this.scene, this.eggHatchData)); + this.end(); } + + console.log(this.eggHatchData); + } else { + this.end(); } - this.end(); } + + hatchEggSilently(egg: Egg) { + const eggIndex = this.scene.gameData.eggs.findIndex(e => e.id === egg.id); + if (eggIndex === -1) { + return this.end(); + } + this.scene.gameData.eggs.splice(eggIndex, 1); + + const data = this.generatePokemon(egg); + const pokemon = data.pokemon; + if (pokemon.fusionSpecies) { + pokemon.clearFusionSpecies(); + } + console.log(pokemon); + + pokemon.loadAssets().then(() => { + + if (pokemon.species.subLegendary) { + this.scene.validateAchv(achvs.HATCH_SUB_LEGENDARY); + } + if (pokemon.species.legendary) { + this.scene.validateAchv(achvs.HATCH_LEGENDARY); + } + if (pokemon.species.mythical) { + this.scene.validateAchv(achvs.HATCH_MYTHICAL); + } + if (pokemon.isShiny()) { + this.scene.validateAchv(achvs.HATCH_SHINY); + } + + }); + + } + + // TODO fix duplicated code neatly + /** + * Generates a Pokemon and hatch data to be hatched by the egg + * @returns the hatched PlayerPokemon + */ + generatePokemon(egg: Egg): EggHatchData { + let ret: PlayerPokemon; + let newHatchData: EggHatchData; + this.scene.executeWithSeedOffset(() => { + ret = egg.generatePlayerPokemon(this.scene); + newHatchData = new EggHatchData(this.scene, ret, egg.eggMoveIndex); + this.eggHatchData.push(newHatchData); + + }, egg.id, EGG_SEED.toString()); + return newHatchData; + } + } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 74558b255e1..ea92456d329 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1554,11 +1554,11 @@ export class GameData { } } - setPokemonCaught(pokemon: Pokemon, incrementCount: boolean = true, fromEgg: boolean = false): Promise { - return this.setPokemonSpeciesCaught(pokemon, pokemon.species, incrementCount, fromEgg); + setPokemonCaught(pokemon: Pokemon, incrementCount: boolean = true, fromEgg: boolean = false, showMessage: boolean = true): Promise { + return this.setPokemonSpeciesCaught(pokemon, pokemon.species, incrementCount, fromEgg, showMessage); } - setPokemonSpeciesCaught(pokemon: Pokemon, species: PokemonSpecies, incrementCount: boolean = true, fromEgg: boolean = false): Promise { + setPokemonSpeciesCaught(pokemon: Pokemon, species: PokemonSpecies, incrementCount: boolean = true, fromEgg: boolean = false, showMessage: boolean = true): Promise { return new Promise(resolve => { const dexEntry = this.dexData[species.speciesId]; const caughtAttr = dexEntry.caughtAttr; @@ -1615,17 +1615,25 @@ export class GameData { } const checkPrevolution = () => { + console.log("checking prevolution"); if (hasPrevolution) { const prevolutionSpecies = pokemonPrevolutions[species.speciesId]; - return this.setPokemonSpeciesCaught(pokemon, getPokemonSpecies(prevolutionSpecies), incrementCount, fromEgg).then(() => resolve()); + this.setPokemonSpeciesCaught(pokemon, getPokemonSpecies(prevolutionSpecies), incrementCount, fromEgg, showMessage).then(() => resolve()); } else { + console.log("resolving"); resolve(); } }; if (newCatch && speciesStarters.hasOwnProperty(species.speciesId)) { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.showText(i18next.t("battle:addedAsAStarter", { pokemonName: species.name }), null, () => checkPrevolution(), null, true); + if (showMessage) { + this.scene.playSound("level_up_fanfare"); + console.log(`${species.name} has been\nadded as a starter!`); + this.scene.ui.showText(i18next.t("battle:addedAsAStarter", { pokemonName: species.name }), null, () => checkPrevolution(), null, true); + console.log("show text passed"); + } else { + resolve(); + } } else { checkPrevolution(); } @@ -1669,7 +1677,7 @@ export class GameData { this.starterData[species.speciesId].candyCount += count; } - setEggMoveUnlocked(species: PokemonSpecies, eggMoveIndex: integer): Promise { + setEggMoveUnlocked(species: PokemonSpecies, eggMoveIndex: integer, showMessage: boolean = true): Promise { return new Promise(resolve => { const speciesId = species.speciesId; if (!speciesEggMoves.hasOwnProperty(speciesId) || !speciesEggMoves[speciesId][eggMoveIndex]) { @@ -1690,10 +1698,15 @@ export class GameData { this.starterData[speciesId].eggMoves |= value; - this.scene.playSound("level_up_fanfare"); - - const moveName = allMoves[speciesEggMoves[speciesId][eggMoveIndex]].name; - this.scene.ui.showText(eggMoveIndex === 3 ? i18next.t("egg:rareEggMoveUnlock", { moveName: moveName }) : i18next.t("egg:eggMoveUnlock", { moveName: moveName }), null, () => resolve(true), null, true); + if (showMessage) { + this.scene.playSound("level_up_fanfare"); + const moveName = allMoves[speciesEggMoves[speciesId][eggMoveIndex]].name; + this.scene.ui.showText(eggMoveIndex === 3 ? i18next.t("egg:rareEggMoveUnlock", { moveName: moveName }) : i18next.t("egg:eggMoveUnlock", { moveName: moveName }), null, (() => { + resolve(true); + }), null, true); + } else { + resolve(true); + } }); } diff --git a/src/ui/egg-summary-ui-handler.ts b/src/ui/egg-summary-ui-handler.ts new file mode 100644 index 00000000000..2baf079a5ad --- /dev/null +++ b/src/ui/egg-summary-ui-handler.ts @@ -0,0 +1,404 @@ +import BattleScene from "../battle-scene"; +import { Mode } from "./ui"; +import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; +import MessageUiHandler from "./message-ui-handler"; +import { getEggTierForSpecies } from "../data/egg"; +import {Button} from "#enums/buttons"; +import { Gender } from "#app/data/gender.js"; +import { getVariantTint } from "#app/data/variant.js"; +import { EggTier } from "#app/enums/egg-type.js"; +import PokemonHatchInfoContainer from "./pokemon-hatch-info-container"; +import { EggHatchData, EggSummaryPhase } from "#app/phases/egg-hatch-phase.js"; + +export default class EggSummaryUiHandler extends MessageUiHandler { + private pokemonListContainer: Phaser.GameObjects.Container; + private pokemonIconSpritesContainer: Phaser.GameObjects.Container; + private pokemonIconsContainer: Phaser.GameObjects.Container; + private eggListMessageBoxContainer: Phaser.GameObjects.Container; + private eggHatchContainer: Phaser.GameObjects.Container; + private eggHatchBg: Phaser.GameObjects.Image; + + + private infoContainer: PokemonHatchInfoContainer; + + + private cursorObj: Phaser.GameObjects.Image; + + private iconAnimHandler: PokemonIconAnimHandler; + private eggHatchData: EggHatchData[]; + + /** + * Allows subscribers to listen for events + * + * Current Events: + * - {@linkcode EggEventType.EGG_COUNT_CHANGED} {@linkcode EggCountChangedEvent} + */ + public readonly eventTarget: EventTarget = new EventTarget(); + + constructor(scene: BattleScene) { + super(scene, Mode.EGG_HATCH_SUMMARY); + } + + + setup() { + const ui = this.getUi(); + + this.pokemonListContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.pokemonListContainer.setVisible(false); + ui.add(this.pokemonListContainer); + + this.eggHatchContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.eggHatchContainer.setVisible(false); + ui.add(this.eggHatchContainer); + // this.scene.fieldUI.add(this.eggHatchContainer); + + // const bgColor = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x006860); + // bgColor.setOrigin(0, 0); + // this.eggListContainer.add(bgColor); + this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler.setup(this.scene); + + this.eggHatchBg = this.scene.add.image(0, 0, "egg_summary_bg"); + this.eggHatchBg.setOrigin(0, 0); + this.eggHatchContainer.add(this.eggHatchBg); + + this.pokemonIconsContainer = this.scene.add.container(115, 9); + this.pokemonIconSpritesContainer = this.scene.add.container(115, 9); + this.pokemonListContainer.add(this.pokemonIconsContainer); + this.pokemonListContainer.add(this.pokemonIconSpritesContainer); + + this.cursorObj = this.scene.add.image(0, 0, "select_cursor"); + this.cursorObj.setOrigin(0, 0); + this.pokemonListContainer.add(this.cursorObj); + + // this.eggSprite = this.scene.add.sprite(54, 37, "egg"); + // this.eggListContainer.add(this.eggSprite); + + + // TODO remove? + this.eggListMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); + this.eggListMessageBoxContainer.setVisible(false); + this.pokemonListContainer.add(this.eggListMessageBoxContainer); + + // TODO clean up info container showing + this.infoContainer = new PokemonHatchInfoContainer(this.scene, this.pokemonListContainer); + this.infoContainer.setup(); + this.infoContainer.changeToEggSummaryLayout(); + this.infoContainer.setVisible(true); + this.pokemonListContainer.add(this.infoContainer); + + this.cursor = -1; + } + + clear() { + super.clear(); + this.cursor = -1; + this.pokemonListContainer.setVisible(false); + this.pokemonIconSpritesContainer.removeAll(true); + this.pokemonIconsContainer.removeAll(true); + this.eggHatchBg.setVisible(false); + // this.currentPokemonSprite.setVisible(false); + // this.pokemonEggMovesContainer.setVisible(false); + this.getUi().hideTooltip(); + console.log("Egg Summary Handler cleared"); + + } + + show(args: any[]): boolean { + /* args[] information + * args[0] : the list of EggHatchData for each egg/pokemon hatched + */ + super.show(args); + + + + if (args.length >= 1) { + // this.pokemonHatched = args[0]; + this.eggHatchData = args[0].sort(function sortHatchData(a: EggHatchData, b: EggHatchData) { + const speciesA = a.pokemon.species; + const speciesB = b.pokemon.species; + if (getEggTierForSpecies(speciesA) < getEggTierForSpecies(speciesB)) { + return -1; + } else if (getEggTierForSpecies(speciesA) > getEggTierForSpecies(speciesB)) { + return 1; + } else { + if (speciesA.speciesId < speciesB.speciesId) { + return -1; + } else if (speciesA.speciesId > speciesB.speciesId) { + return 1; + } else { + return 0; + } + } + } + + ); + } + // this.pokemonHatched = []; + + this.getUi().bringToTop(this.pokemonListContainer); + + this.pokemonListContainer.setVisible(true); + this.eggHatchContainer.setVisible(true); + this.pokemonIconsContainer.setVisible(true); + this.eggHatchBg.setVisible(true); + + this.eggHatchData.forEach( (value: EggHatchData, i: number) => { + const x = (i % 11) * 18; + const y = Math.floor(i / 11) * 18; + + const displayPokemon = value.pokemon; + + const bg = this.scene.add.image(x+2, y+5, "passive_bg"); + bg.setOrigin(0, 0); + bg.setScale(0.75); + bg.setVisible(true); + this.pokemonIconsContainer.add(bg); + + // set tint for passive bg + switch (getEggTierForSpecies(displayPokemon.species)) { + case EggTier.COMMON: + bg.setTint(0xabddab); + break; + case EggTier.GREAT: + bg.setTint(0xabafff); + break; + case EggTier.ULTRA: + bg.setTint(0xffffaa); + break; + case EggTier.MASTER: + bg.setTint(0xdfffaf); + break; + } + + const icon = this.scene.add.sprite(x-2, y+2, displayPokemon.species.getIconAtlasKey(displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // const icon = this.scene.add.sprite(x - 2, y + 2, "egg_icons"); + icon.setScale(0.5); + icon.setOrigin(0, 0); + icon.setFrame(displayPokemon.species.getIconId(displayPokemon.gender === Gender.FEMALE, displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // icon.setFrame(egg.getKey()); + this.pokemonIconSpritesContainer.add(icon); + this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); + + // add shiny + const shiny = this.scene.add.image(x + 12, y + 2, "shiny_star_small"); + shiny.setScale(0.5); + shiny.setVisible(displayPokemon.shiny); + shiny.setTint(getVariantTint(displayPokemon.variant)); + this.pokemonIconsContainer.add(shiny); + + const ha = this.scene.add.image(x + 12, y + 7, "ha_capsule"); + ha.setScale(0.5); + ha.setVisible((displayPokemon.hasAbility(displayPokemon.species.abilityHidden))); + this.pokemonIconsContainer.add(ha); + + const pb = this.scene.add.image(x + 12, y + 14, "icon_owned"); + pb.setOrigin(0, 0); + pb.setScale(0.5); + const dexEntry = value.prevDexEntry; + const caughtAttr = dexEntry.caughtAttr; + pb.setVisible(!caughtAttr); + if (!caughtAttr) { + this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE); + } + this.pokemonIconsContainer.add(pb); + + const em = this.scene.add.image(x, y + 2, "icon_egg_move"); + em.setOrigin(0, 0); + em.setScale(0.5); + em.setVisible(value.eggMoveUnlocked); + this.pokemonIconsContainer.add(em); + }); + // console.log("generating icons..."); + // this.shinyIcons = new Array(this.eggHatchData.length).fill(null).map((_, i) => { + // const x = (i % 11) * 18; + // const y = Math.floor(i / 11) * 18; + // const ret = this.scene.add.image(x + 12, y + 2, "shiny_star_small"); + // ret.setOrigin(0, 0); + // ret.setScale(0.5); + // ret.setVisible(false); + // this.pokemonIconsContainer.add(ret); + // return ret; + // }); + + // this.hiddenAbilityIcons = new Array(this.eggHatchData.length).fill(null).map((_, i) => { + // const x = (i % 11) * 18; + // const y = Math.floor(i / 11) * 18; + // const ret = this.scene.add.image(x + 12, y + 7, "ha_capsule"); + // ret.setOrigin(0, 0); + // ret.setScale(0.5); + // ret.setVisible(false); + // this.pokemonIconsContainer.add(ret); + // return ret; + // }); + + // this.pokeballIcons = new Array(this.eggHatchData.length).fill(null).map((_, i) => { + // const x = (i % 11) * 18; + // const y = Math.floor(i / 11) * 18; + // const ret = this.scene.add.image(x + 12, y + 14, "icon_owned"); + // ret.setOrigin(0, 0); + // ret.setScale(0.5); + // ret.setVisible(false); + // this.pokemonIconsContainer.add(ret); + // return ret; + // }); + + // this.eggMoveIcons = new Array(this.eggHatchData.length).fill(null).map((_, i) => { + // const x = (i % 11) * 18; + // const y = Math.floor(i / 11) * 18; + // const ret = this.scene.add.image(x, y + 2, "icon_egg_move"); + // ret.setOrigin(0, 0); + // ret.setScale(0.5); + // ret.setVisible(false); + // this.pokemonIconsContainer.add(ret); + // return ret; + // }); + // console.log("icons done"); + + // console.log("generating info containers..."); + + // // setup single info container + + // // this.infoContainers = new Array(this.pokemonHatched.length).fill(null).map((_, i) => { + // // const ret = new PokemonInfoContainer(this.scene, 45, 100); + // // ret.setup(); + // // ret.show(this.pokemonHatched[i]); + // // ret.setVisible(false); + // // ret.setScale(0.8); + // // this.eggListPokemonContainer.add(ret); + // // return ret; + // // }); + + + + // // TODO sort by number / egg type + // // TODO add egg hatch count in bottom right + // let i = 0; + // for (const hatchData of this.eggHatchData) { + // console.log(hatchData); + // const displayPokemon = hatchData.pokemon; + + // // const x = (index % 9) * 18; + // // const y = Math.floor(index / 9) * 18; + // const x = (i % 11) * 18; + // const y = Math.floor(i / 11) * 18; + // const icon = this.scene.add.sprite(x-2, y+2, displayPokemon.species.getIconAtlasKey(displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // // const icon = this.scene.add.sprite(x - 2, y + 2, "egg_icons"); + // icon.setScale(0.5); + // icon.setOrigin(0, 0); + // icon.setOrigin(0, 0); + // icon.setFrame(displayPokemon.species.getIconId(displayPokemon.gender === Gender.FEMALE, displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant)); + // // icon.setFrame(egg.getKey()); + // this.pokemonIconSpritesContainer.add(icon); + // this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); + + // // this.checkIconId(icon, displayPokemon.species, displayPokemon.female, displayPokemon.formIndex, displayPokemon.shiny, displayPokemon.variant); + + // // DONE shiny icon funcitonality for variants + // // TODO test shiny icons + // this.shinyIcons[i].setVisible(displayPokemon.shiny); + // this.shinyIcons[i].setTint(getVariantTint(displayPokemon.variant)); + // // this.shinyIcons[i].setTint(getVariantTint(speciesVariants[v] === DexAttr.DEFAULT_VARIANT ? 0 : speciesVariants[v] === DexAttr.VARIANT_2 ? 1 : 2)); + // // DONE new pokemon / catch icon functionality + // // TODO test for new pokemon + // const dexEntry = hatchData.prevDexEntry; + // const caughtAttr = dexEntry.caughtAttr; + // this.pokeballIcons[i].setVisible(!caughtAttr); + // // this.pokeballIcons[i].setVisible(this.scene.gameData.dexData[displayPokemon.species.speciesId].caughtAttr) + + + // this.hiddenAbilityIcons[i].setVisible((displayPokemon.hasAbility(displayPokemon.species.abilityHidden))); + + // this.eggMoveIcons[i].setVisible(hatchData.eggMoveUnlocked); + + // console.log(displayPokemon); + // console.log(displayPokemon.shiny); + // console.log(caughtAttr); + // console.log(hatchData.eggMoveUnlocked); + // // this.pokeballIcons[i].setVisible(true); + // // this.shinyIcons[i].setVisible(true); + // // this.hiddenAbilityIcons[i].setVisible(true); + + // i++; + // } + + this.setCursor(0); + + return true; + } + + + + processInput(button: Button): boolean { + const ui = this.getUi(); + + let success = false; + const error = false; + console.log("egg handler button " + button); + if (button === Button.CANCEL) { + const phase = this.scene.getCurrentPhase(); + if (phase instanceof EggSummaryPhase) { + phase.end(); + } + ui.revertMode(); + success = true; + } else { + const count = this.eggHatchData.length; + const rows = Math.ceil(count / 11); + const row = Math.floor(this.cursor / 11); + switch (button) { + case Button.UP: + if (row) { + success = this.setCursor(this.cursor - 11); + } + break; + case Button.DOWN: + if (row < rows - 2 || (row < rows - 1 && this.cursor % 11 <= (count - 1) % 11)) { + success = this.setCursor(this.cursor + 11); + } + break; + case Button.LEFT: + if (this.cursor % 11) { + success = this.setCursor(this.cursor - 1); + } + break; + case Button.RIGHT: + if (this.cursor % 11 < (row < rows - 1 ? 10 : (count - 1) % 11)) { + success = this.setCursor(this.cursor + 1); + } + break; + } + } + + if (success) { + ui.playSelect(); + } else if (error) { + ui.playError(); + } + + return success || error; + } + + setCursor(cursor: integer): boolean { + let changed = false; + + const lastCursor = this.cursor; + + changed = super.setCursor(cursor); + + if (changed) { + this.cursorObj.setPosition(114 + 18 * (cursor % 11), 10 + 18 * Math.floor(cursor / 11)); + + if (lastCursor > -1) { + this.iconAnimHandler.addOrUpdate(this.pokemonIconSpritesContainer.getAt(lastCursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.NONE); + } + this.iconAnimHandler.addOrUpdate(this.pokemonIconSpritesContainer.getAt(cursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.ACTIVE); + + this.infoContainer.showHatchInfo(this.eggHatchData[cursor]); + + } + + return changed; + } + +} diff --git a/src/ui/pokemon-hatch-info-container.ts b/src/ui/pokemon-hatch-info-container.ts new file mode 100644 index 00000000000..491ef23df17 --- /dev/null +++ b/src/ui/pokemon-hatch-info-container.ts @@ -0,0 +1,149 @@ + +import PokemonInfoContainer from "./pokemon-info-container"; +import BattleScene from "../battle-scene"; +import { Gender } from "../data/gender"; +import { Type } from "../data/type"; +import i18next from "i18next"; +import * as Utils from "../utils"; +import { TextStyle, addTextObject } from "./text"; +import { speciesEggMoves } from "#app/data/egg-moves.js"; +import { allMoves } from "#app/data/move.js"; +import { Species } from "#app/enums/species.js"; +import { getEggTierForSpecies } from "#app/data/egg.js"; +import { EggHatchData } from "#app/phases/egg-hatch-phase.js"; + +export default class PokemonHatchInfoContainer extends PokemonInfoContainer { + private currentPokemonSprite: Phaser.GameObjects.Sprite; + private pokemonNumberText: Phaser.GameObjects.Text; + private pokemonNameText: Phaser.GameObjects.Text; + private pokemonEggMovesContainer: Phaser.GameObjects.Container; + private pokemonEggMoveContainers: Phaser.GameObjects.Container[]; + private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[]; + private pokemonEggMoveLabels: Phaser.GameObjects.Text[]; + private pokemonHatchedIcon : Phaser.GameObjects.Sprite; + private pokemonListContainer: Phaser.GameObjects.Container; + + constructor(scene: BattleScene, listContainer : Phaser.GameObjects.Container, x: number = 115, y: number = 9,) { + super(scene, x, y); + this.pokemonListContainer = listContainer; + + } + setup(): void { + super.setup(); + super.changeToEggSummaryLayout(); + + this.currentPokemonSprite = this.scene.add.sprite(54, 80, "pkmn__sub"); + this.currentPokemonSprite.setScale(0.8); + this.currentPokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true }); + this.pokemonListContainer.add(this.currentPokemonSprite); + + this.pokemonNumberText = addTextObject(this.scene, 80, 107.5, "0000", TextStyle.SUMMARY, {fontSize: 74}); + this.pokemonNumberText.setOrigin(0, 0); + this.pokemonListContainer.add(this.pokemonNumberText); + + this.pokemonNameText = addTextObject(this.scene, 7, 107.5, "", TextStyle.SUMMARY, {fontSize: 74}); + this.pokemonNameText.setOrigin(0, 0); + this.pokemonListContainer.add(this.pokemonNameText); + + this.pokemonHatchedIcon = this.scene.add.sprite(-2, 90, "egg_icons"); + this.pokemonHatchedIcon.setOrigin(0, 0.2); + this.pokemonHatchedIcon.setScale(0.8); + this.pokemonListContainer.add(this.pokemonHatchedIcon); + + this.pokemonEggMoveContainers = []; + this.pokemonEggMoveBgs = []; + this.pokemonEggMoveLabels = []; + this.pokemonEggMovesContainer = this.scene.add.container(0, 200); + this.pokemonEggMovesContainer.setVisible(false); + this.pokemonEggMovesContainer.setScale(0.5); + + const eggMovesLabel = addTextObject(this.scene, 70, 0, i18next.t("starterSelectUiHandler:eggMoves"), TextStyle.WINDOW_ALT); + eggMovesLabel.setOrigin(0.5, 0); + + this.pokemonEggMovesContainer.add(eggMovesLabel); + + for (let m = 0; m < 4; m++) { + const eggMoveContainer = this.scene.add.container(0, 7 + 5.25 * m); + + const eggMoveBg = this.scene.add.nineslice(70, 0, "type_bgs", "unknown", 92, 14, 2, 2, 2, 2); + eggMoveBg.setOrigin(1, 0); + eggMoveBg.setZ(3); + + const eggMoveLabel = addTextObject(this.scene, 70 -eggMoveBg.width / 2, 0, "???", TextStyle.PARTY); + eggMoveLabel.setOrigin(0.5, 0); + eggMoveLabel.setZ(3); + + this.pokemonEggMoveBgs.push(eggMoveBg); + this.pokemonEggMoveLabels.push(eggMoveLabel); + + eggMoveContainer.add(eggMoveBg); + eggMoveContainer.add(eggMoveLabel); + eggMoveContainer.setScale(0.375); + + this.pokemonEggMoveContainers.push(eggMoveContainer); + + this.pokemonEggMovesContainer.add(eggMoveContainer); + } + + super.add(this.pokemonEggMoveContainers); + + } + + showHatchInfo(hatchInfo: EggHatchData) { + this.pokemonEggMovesContainer.setVisible(true); + + const displayPokemon = hatchInfo.pokemon; + const species = displayPokemon.species; + const female = displayPokemon.gender === Gender.FEMALE; + const formIndex = displayPokemon.formIndex; + const shiny = displayPokemon.shiny; + const variant = displayPokemon.variant; + super.show(displayPokemon, false, 1, hatchInfo.getDex(), hatchInfo.prevStarterEntry, true); + + species.loadAssets(this.scene, female, formIndex, shiny, variant, true).then(() => { + // if (assetLoadCancelled.value) { + // return; + // } + // this.assetLoadCancelled = null; + // this.speciesLoaded.set(species.speciesId, true); + // redundant setVisible(true) but makes sure sprite is only visible after being rendered (no substitute visible) + this.currentPokemonSprite.setVisible(true); + this.currentPokemonSprite.play(species.getSpriteKey(female, formIndex, shiny, variant)); + this.currentPokemonSprite.setPipelineData("shiny", shiny); + this.currentPokemonSprite.setPipelineData("variant", variant); + this.currentPokemonSprite.setPipelineData("spriteKey", species.getSpriteKey(female, formIndex, shiny, variant)); + // this.pokemonSprite.setVisible(!this.statsMode); + }); + // TODO pokemon name and number + + this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4)); + this.pokemonNameText.setText(species.name); + + const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId); + + for (let em = 0; em < 4; em++) { + // TODO add some new egg move indicator + const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null; + const eggMoveUnlocked = eggMove && this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em); + this.pokemonEggMoveBgs[em].setFrame(Type[eggMove ? eggMove.type : Type.UNKNOWN].toString().toLowerCase()); + + this.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : "???"); + if (!(eggMove && hatchInfo.prevStarterEntry.eggMoves & Math.pow(2, em)) && eggMoveUnlocked) { + this.pokemonEggMoveLabels[em].setText("(+) " + eggMove.name); + } + } + + // will always have at least one egg move + this.pokemonEggMovesContainer.setVisible(true); + + // TODO show egg tier / icon + if (species.speciesId === Species.MANAPHY || species.speciesId === Species.PHIONE) { + this.pokemonHatchedIcon.setFrame("manaphy"); + } else { + this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species)); + } + + } + + +} diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index edb85ecff7a..9b29a204cee 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -6,7 +6,7 @@ import { getNatureName } from "../data/nature"; import { Type } from "../data/type"; import Pokemon from "../field/pokemon"; import i18next from "i18next"; -import { DexAttr } from "../system/game-data"; +import { DexAttr, DexEntry, StarterDataEntry } from "../system/game-data"; import * as Utils from "../utils"; import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; @@ -63,6 +63,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { private pokemonMovesContainers: Phaser.GameObjects.Container[]; private pokemonMoveBgs: Phaser.GameObjects.NineSlice[]; private pokemonMoveLabels: Phaser.GameObjects.Text[]; + private infoBg; private numCharsBeforeCutoff = 16; @@ -83,9 +84,9 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { const currentLanguage = i18next.resolvedLanguage!; // TODO: is this bang correct? const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage?.includes(lang))!; // TODO: is this bang correct? const textSettings = languageSettings[langSettingKey]; - const infoBg = addWindow(this.scene, 0, 0, this.infoWindowWidth, 132); - infoBg.setOrigin(0.5, 0.5); - infoBg.setName("window-info-bg"); + this.infoBg = addWindow(this.scene, 0, 0, this.infoWindowWidth, 132); + this.infoBg.setOrigin(0.5, 0.5); + this.infoBg.setName("window-info-bg"); this.pokemonMovesContainer = this.scene.add.container(6, 14); this.pokemonMovesContainer.setName("pkmn-moves"); @@ -133,7 +134,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.statsContainer = new StatsContainer(this.scene, -48, -64, true); - this.add(infoBg); + this.add(this.infoBg); this.add(this.statsContainer); // The position should be set per language @@ -207,9 +208,17 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.setVisible(false); } - show(pokemon: Pokemon, showMoves: boolean = false, speedMultiplier: number = 1): Promise { + // TODO neaten up boolean calls + show(pokemon: Pokemon, showMoves: boolean = false, speedMultiplier: number = 1, dexEntry?: DexEntry, starterEntry?: StarterDataEntry, eggInfo = false): Promise { return new Promise(resolve => { - const caughtAttr = BigInt(pokemon.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr); + if (!dexEntry) { + dexEntry = pokemon.scene.gameData.dexData[pokemon.species.speciesId]; + } + if (!starterEntry) { + starterEntry = pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()]; + } + + const caughtAttr = BigInt(dexEntry.caughtAttr); if (pokemon.gender > Gender.GENDERLESS) { this.pokemonGenderText.setText(getGenderSymbol(pokemon.gender)); this.pokemonGenderText.setColor(getGenderColor(pokemon.gender)); @@ -268,7 +277,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { const opponentPokemonAbilityIndex = (opponentPokemonOneNormalAbility && pokemon.abilityIndex === 1) ? 2 : pokemon.abilityIndex; const opponentPokemonAbilityAttr = 1 << opponentPokemonAbilityIndex; - const rootFormHasHiddenAbility = pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr & opponentPokemonAbilityAttr; + const rootFormHasHiddenAbility = starterEntry.abilityAttr & opponentPokemonAbilityAttr; if (!rootFormHasHiddenAbility) { this.pokemonAbilityLabelText.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); @@ -280,7 +289,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonNatureText.setText(getNatureName(pokemon.getNature(), true, false, false, this.scene.uiTheme)); - const dexNatures = pokemon.scene.gameData.dexData[pokemon.species.speciesId].natureAttr; + const dexNatures = dexEntry.natureAttr; const newNature = 1 << (pokemon.nature + 1); if (!(dexNatures & newNature)) { @@ -324,31 +333,31 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { } const starterSpeciesId = pokemon.species.getRootSpeciesId(); - const originalIvs: integer[] | null = this.scene.gameData.dexData[starterSpeciesId].caughtAttr - ? this.scene.gameData.dexData[starterSpeciesId].ivs - : null; + const originalIvs: integer[] | null = eggInfo ? (dexEntry.caughtAttr ? dexEntry.ivs : null) : (this.scene.gameData.dexData[starterSpeciesId].caughtAttr + ? this.scene.gameData.dexData[starterSpeciesId].ivs : null); this.statsContainer.updateIvs(pokemon.ivs, originalIvs!); // TODO: is this bang correct? - - this.scene.tweens.add({ - targets: this, - duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), - ease: "Cubic.easeInOut", - x: this.initialX - this.infoWindowWidth, - onComplete: () => { - resolve(); - } - }); - - if (showMoves) { + if (!eggInfo) { this.scene.tweens.add({ - delay: Utils.fixedInt(Math.floor(325 / speedMultiplier)), - targets: this.pokemonMovesContainer, - duration: Utils.fixedInt(Math.floor(325 / speedMultiplier)), + targets: this, + duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), ease: "Cubic.easeInOut", - x: this.movesContainerInitialX - 57, - onComplete: () => resolve() + x: this.initialX - this.infoWindowWidth, + onComplete: () => { + resolve(); + } }); + + if (showMoves) { + this.scene.tweens.add({ + delay: Utils.fixedInt(Math.floor(325 / speedMultiplier)), + targets: this.pokemonMovesContainer, + duration: Utils.fixedInt(Math.floor(325 / speedMultiplier)), + ease: "Cubic.easeInOut", + x: this.movesContainerInitialX - 57, + onComplete: () => resolve() + }); + } } for (let m = 0; m < 4; m++) { @@ -364,6 +373,39 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { }); } + changeToEggSummaryLayout() { + // The position should be set per language + // const currentLanguage = i18next.resolvedLanguage; + // const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang)); + // const textSettings = languageSettings[langSettingKey]; + const infoContainerLabelXPos = 25; + const infoContainerTextXPos = 29; + this.x = this.initialX - this.infoWindowWidth; + + // The font size should be set by language + // const infoContainerTextSize = textSettings?.infoContainerTextSize || "64px"; + + + this.pokemonGenderText.setPosition(87, -2); + this.pokemonGenderNewText.setPosition(77, -2); + this.pokemonShinyIcon.setPosition(82, 87); + this.pokemonShinyNewIcon.setPosition(72, 87); + + + this.pokemonFormLabelText.setPosition(infoContainerLabelXPos, 152); + this.pokemonFormText.setPosition(infoContainerTextXPos, 152); + this.pokemonAbilityLabelText.setPosition(infoContainerLabelXPos, 110); // originally 29 + this.pokemonAbilityText.setPosition(infoContainerTextXPos, 110); // originally 29 + this.pokemonNatureLabelText.setPosition(infoContainerLabelXPos, 125); // originally 39 + this.pokemonNatureText.setPosition(infoContainerTextXPos, 125); // originally 39 + + + this.statsContainer.setScale(0.7); + this.statsContainer.setPosition(30, -3); + this.infoBg.setVisible(false); + this.pokemonMovesContainer.setVisible(false); + } + makeRoomForConfirmUi(speedMultiplier: number = 1, fromCatch: boolean = false): Promise { const xPosition = fromCatch ? this.initialX - this.infoWindowWidth - 65 : this.initialX - this.infoWindowWidth - ConfirmUiHandler.windowWidth; return new Promise(resolve => { diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 1f4a0b3a51e..c3fc6de44fe 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -49,6 +49,7 @@ import BgmBar from "#app/ui/bgm-bar"; import RenameFormUiHandler from "./rename-form-ui-handler"; import RunHistoryUiHandler from "./run-history-ui-handler"; import RunInfoUiHandler from "./run-info-ui-handler"; +import EggSummaryUiHandler from "./egg-summary-ui-handler"; export enum Mode { MESSAGE, @@ -64,6 +65,7 @@ export enum Mode { STARTER_SELECT, EVOLUTION_SCENE, EGG_HATCH_SCENE, + EGG_HATCH_SUMMARY, CONFIRM, OPTION_SELECT, MENU, @@ -162,6 +164,7 @@ export default class UI extends Phaser.GameObjects.Container { new SaveSlotSelectUiHandler(scene), new PartyUiHandler(scene), new SummaryUiHandler(scene), + new EggSummaryUiHandler(scene), new StarterSelectUiHandler(scene), new EvolutionSceneHandler(scene), new EggHatchSceneHandler(scene),