Add starter select

This commit is contained in:
Flashfyre 2023-04-12 19:09:15 -04:00
parent 950b3a14b4
commit 6397a10998
20 changed files with 501 additions and 92 deletions

View File

@ -4,7 +4,6 @@
- Title screen
- Starter select screen
- UI
- Get starters from save data caught Pokemon
- Moves
- Move logic

BIN
public/audio/bgm/menu.mp3 Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

View File

@ -429,9 +429,12 @@ function loadAnimAssets(scene: BattleScene, anims: Anim[], startLoad?: boolean):
scene.loadImage(bg, 'battle_anims');
for (let s of sounds)
scene.loadSe(s, 'battle_anims', s);
scene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
if (startLoad && !scene.load.isLoading())
scene.load.start();
if (startLoad) {
scene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
if (!scene.load.isLoading())
scene.load.start();
} else
resolve();
});
}

View File

@ -16,7 +16,9 @@ import { EvolutionPhase } from "./evolution-phase";
import { BattlePhase } from "./battle-phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./battle-stat";
import { Biome, biomeLinks } from "./biome";
import { ModifierType, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, getModifierTypeOptionsForWave, regenerateModifierPoolThresholds } from "./modifier-type";
import { ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, getModifierTypeOptionsForWave, regenerateModifierPoolThresholds } from "./modifier-type";
import PokemonSpecies from "./pokemon-species";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
export class SelectStarterPhase extends BattlePhase {
constructor(scene: BattleScene) {
@ -26,7 +28,26 @@ export class SelectStarterPhase extends BattlePhase {
start() {
super.start();
this.scene.ui.setMode(Mode.STARTER_SELECT);
this.scene.sound.play('menu');
this.scene.ui.setMode(Mode.STARTER_SELECT, (starterSpecies: PokemonSpecies[]) => {
const party = this.scene.getParty();
const loadPokemonAssets: Promise<void>[] = [];
for (let species of starterSpecies) {
const starter = new PlayerPokemon(this.scene, species, 5);
starter.setVisible(false);
party.push(starter);
loadPokemonAssets.push(starter.loadAssets());
}
Promise.all(loadPokemonAssets).then(() => {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => {
SoundFade.fadeOut(this.scene.sound.get('menu'), 500, true);
this.scene.time.delayedCall(500, () => this.scene.arena.playBgm());
this.end();
});
});
});
}
}

View File

@ -1,7 +1,7 @@
import Phaser from 'phaser';
import { Biome, BiomeArena } from './biome';
import UI from './ui/ui';
import { EncounterPhase, SummonPhase, CommandPhase, NextEncounterPhase, SwitchBiomePhase, NewBiomeEncounterPhase, SelectBiomePhase } from './battle-phases';
import { EncounterPhase, SummonPhase, CommandPhase, NextEncounterPhase, SwitchBiomePhase, NewBiomeEncounterPhase, SelectBiomePhase, SelectStarterPhase } from './battle-phases';
import { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { allSpecies, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils';
@ -23,6 +23,7 @@ export enum Button {
RIGHT,
ACTION,
CANCEL,
QUICK_START,
RANDOM,
AUTO,
SPEED_UP,
@ -32,6 +33,7 @@ export enum Button {
export default class BattleScene extends Phaser.Scene {
public auto: boolean;
public gameSpeed: integer = 1;
public quickStart: boolean;
private phaseQueue: BattlePhase[];
private phaseQueuePrepend: BattlePhase[];
@ -157,6 +159,13 @@ export default class BattleScene extends Phaser.Scene {
this.loadImage('biome_select_window_2', 'ui');
this.loadImage('biome_select_window_3', 'ui');
this.loadImage('starter_select_bg', 'ui');
this.loadImage('starter_select_message', 'ui');
this.loadImage('starter_select_cursor', 'ui');
this.loadImage('starter_select_cursor_highlight', 'ui');
this.loadImage('starter_select_gen_cursor', 'ui');
this.loadImage('starter_select_gen_cursor_highlight', 'ui');
// Load arena images
Utils.getEnumValues(Biome).map(at => {
const atKey = Biome[at].toLowerCase();
@ -215,6 +224,7 @@ export default class BattleScene extends Phaser.Scene {
this.loadSe('pb_catch');
this.loadSe('pb_lock');
this.loadBgm('menu');
this.loadBgm('level_up_fanfare');
this.loadBgm('evolution');
this.loadBgm('evolution_fanfare');
@ -269,6 +279,7 @@ export default class BattleScene extends Phaser.Scene {
let loadPokemonAssets = [];
const isRandom = this.isButtonPressed(Button.RANDOM); // For testing purposes
this.quickStart = isRandom || this.isButtonPressed(Button.QUICK_START);
if (isRandom) {
const biomes = Utils.getEnumValues(Biome);
@ -291,18 +302,17 @@ export default class BattleScene extends Phaser.Scene {
a.setOrigin(0, 0);
field.add(a);
});
this.arena.playBgm();
for (let s = 0; s < 3; s++) {
const playerSpecies = !isRandom ? getPokemonSpecies(s === 0 ? Species.TORCHIC : s === 1 ? Species.TREECKO : Species.MUDKIP) : this.randomSpecies(5);
const playerPokemon = new PlayerPokemon(this, playerSpecies, 5);
playerPokemon.setVisible(false);
loadPokemonAssets.push(playerPokemon.loadAssets());
if (this.quickStart) {
for (let s = 0; s < 3; s++) {
const playerSpecies = !isRandom ? getPokemonSpecies(s === 0 ? Species.TORCHIC : s === 1 ? Species.TREECKO : Species.MUDKIP) : this.randomSpecies(5);
const playerPokemon = new PlayerPokemon(this, playerSpecies, 5);
playerPokemon.setVisible(false);
loadPokemonAssets.push(playerPokemon.loadAssets());
this.party.push(playerPokemon);
this.party.push(playerPokemon);
}
}
console.log(this.getPlayerPokemon().species.name, this.getPlayerPokemon().species.speciesId, this.getPlayerPokemon().stats);
const trainerPbFrameNames = this.anims.generateFrameNames('trainer_m_pb', { zeroPad: 2, start: 1, end: 12 });
this.anims.create({
@ -354,6 +364,7 @@ export default class BattleScene extends Phaser.Scene {
[Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
[Button.ACTION]: [keyCodes.ENTER, keyCodes.SPACE, keyCodes.Z],
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.ESC, keyCodes.X],
[Button.QUICK_START]: [keyCodes.Q],
[Button.RANDOM]: [keyCodes.R],
[Button.AUTO]: [keyCodes.F2],
[Button.SPEED_UP]: [keyCodes.PLUS],
@ -384,8 +395,6 @@ export default class BattleScene extends Phaser.Scene {
newBattle(): Battle {
if (this.currentBattle) {
console.log(this.getPlayerPokemon(), this.getParty().map(p => p.name), this.getPlayerPokemon().id)
this.getEnemyPokemon().destroy();
if (this.currentBattle.waveIndex % 10)
this.unshiftPhase(new NextEncounterPhase(this));
@ -394,7 +403,11 @@ export default class BattleScene extends Phaser.Scene {
this.unshiftPhase(new NewBiomeEncounterPhase(this));
}
} else {
//this.pushPhase(new SelectStarterPhase(this));
if (!this.quickStart) {
this.arena.preloadBgm();
this.pushPhase(new SelectStarterPhase(this));
} else
this.arena.playBgm();
this.pushPhase(new EncounterPhase(this));
this.pushPhase(new SummonPhase(this));
}

View File

@ -187,12 +187,18 @@ export class BiomeArena {
return Biome[this.biomeType].toLowerCase();
}
playBgm() {
preloadBgm(): void {
this.scene.loadBgm(this.bgm);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => this.scene.playBgm(this.bgm));
}
fadeOutBgm(duration: integer, destroy?: boolean) {
playBgm(): void {
this.scene.loadBgm(this.bgm);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => this.scene.playBgm(this.bgm));
if (!this.scene.load.isLoading())
this.scene.load.start();
}
fadeOutBgm(duration: integer, destroy?: boolean): void {
if (destroy === undefined)
destroy = true;
const bgm = this.scene.sound.get(this.bgm);

View File

@ -770,6 +770,12 @@ export const pokemonEvolutions: PokemonEvolutions = {
[Species.EXEGGCUTE]: [
new SpeciesEvolution(Species.EXEGGUTOR, 1, "Leaf Stone", null, SpeciesWildEvolutionDelay.LONG)
],
[Species.TANGELA]: [
new SpeciesEvolution(Species.TANGROWTH, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Ancient power learned*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.LICKITUNG]: [
new SpeciesEvolution(Species.LICKILICKY, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Rollout learned*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.STARYU]: [
new SpeciesEvolution(Species.STARMIE, 1, "Water Stone", null, SpeciesWildEvolutionDelay.MEDIUM)
],
@ -785,27 +791,54 @@ export const pokemonEvolutions: PokemonEvolutions = {
[Species.TOGETIC]: [
new SpeciesEvolution(Species.TOGEKISS, 1, "Shiny Stone", null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.AIPOM]: [
new SpeciesEvolution(Species.AMBIPOM, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Double hit learned*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.SUNKERN]: [
new SpeciesEvolution(Species.SUNFLORA, 1, "Sun Stone", null, SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.YANMA]: [
new SpeciesEvolution(Species.YANMEGA, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Rollout learned*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.MURKROW]: [
new SpeciesEvolution(Species.HONCHKROW, 1, "Dusk Stone", null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.MISDREAVUS]: [
new SpeciesEvolution(Species.MISMAGIUS, 1, "Dusk Stone", null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.GLIGAR]: [
new SpeciesEvolution(Species.GLISCOR, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Razor fang at night*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.SNEASEL]: [
new SpeciesEvolution(Species.WEAVILE, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Razor claw at night*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.PILOSWINE]: [
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Ancient power learned*/), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.LOMBRE]: [
new SpeciesEvolution(Species.LUDICOLO, 1, "Water Stone", null, SpeciesWildEvolutionDelay.LONG)
],
[Species.NUZLEAF]: [
new SpeciesEvolution(Species.SHIFTRY, 1, "Leaf Stone", null, SpeciesWildEvolutionDelay.LONG)
],
[Species.NOSEPASS]: [
new SpeciesEvolution(Species.PROBOPASS, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Magnetic field??*/), SpeciesWildEvolutionDelay.LONG)
],
[Species.SKITTY]: [
new SpeciesEvolution(Species.DELCATTY, 1, "Moon Stone", null, SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.ROSELIA]: [
new SpeciesEvolution(Species.ROSERADE, 1, "Shiny Stone", null, SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.BONSLY]: [
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Mimic learned */), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.MIME_JR]: [
new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Mimic learned */), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.MANTYKE]: [
new SpeciesEvolution(Species.MANTINE, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => true /* Remoraid in party */), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.PANSAGE]: [
new SpeciesEvolution(Species.SIMISAGE, 1, "Leaf Stone", null, SpeciesWildEvolutionDelay.MEDIUM)
],
@ -904,10 +937,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.CHANSEY]: [
new SpeciesEvolution(Species.BLISSEY, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.BLISSEY, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.MUNCHLAX]: [
new SpeciesEvolution(Species.SNORLAX, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.LONG)
new SpeciesEvolution(Species.SNORLAX, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.TOGEPI]: [
new SpeciesEvolution(Species.TOGETIC, 1, null, new SpeciesEvolutionCondition((p: Pokemon) => p.winCount >= 10), SpeciesWildEvolutionDelay.SHORT)

View File

@ -1,7 +1,11 @@
import { Moves } from "./move";
import { Species } from "./species";
export const pokemonLevelMoves = {
interface PokemonLevelMoves {
[key: string]: Array<Array<integer | Moves>>
}
export const pokemonLevelMoves: PokemonLevelMoves = {
[Species.BULBASAUR]: [
[ 1, Moves.TACKLE ],
[ 3, Moves.GROWL ],

View File

@ -131,7 +131,7 @@ export default class PokemonSpecies {
if (pokemonEvolutions.hasOwnProperty(this.speciesId)) {
for (let e of pokemonEvolutions[this.speciesId]) {
const condition = e.condition;
if (!condition || !condition.applyToWild || condition.predicate(this)) {
if (!condition || typeof(condition) === 'string' || !condition.applyToWild || condition.predicate(this)) {
const speciesId = e.speciesId;
const level = e.level;
evolutionLevels.push([ speciesId, level ]);
@ -146,7 +146,7 @@ export default class PokemonSpecies {
return evolutionLevels;
}
getPrevolutionLevels() {
getPrevolutionLevels(ignoreConditions?: boolean) {
const prevolutionLevels = [];
const allEvolvingPokemon = Object.keys(pokemonEvolutions);
@ -154,7 +154,7 @@ export default class PokemonSpecies {
for (let e of pokemonEvolutions[p]) {
if (e.speciesId === this.speciesId) {
const condition = e.condition;
if (!condition || !condition.applyToWild || condition.predicate(this)) {
if (ignoreConditions || !condition || typeof(condition) === 'string' || !condition.applyToWild || condition.predicate(this)) {
const speciesId = parseInt(p) as Species;
let level = e.level;
prevolutionLevels.push([ speciesId, level ]);
@ -169,6 +169,18 @@ export default class PokemonSpecies {
return prevolutionLevels;
}
getSpriteAtlasPath(female: boolean, shiny?: boolean): string {
return this.getSpriteId(female, shiny).replace(/\_{2}/g, '/');
}
getSpriteId(female: boolean, shiny?: boolean): string {
return `${shiny ? 'shiny__' : ''}${this.genderDiffs && female ? 'female__' : ''}${this.speciesId}`;
}
getSpriteKey(female: boolean, shiny?: boolean): string {
return `pkmn__${this.getSpriteId(female, shiny)}`;
}
getIconAtlasKey(): string {
return `pokemon_icons_${this.generation}`;
}
@ -225,6 +237,32 @@ export default class PokemonSpecies {
return `pkmn_icon__${this.getIconId()}`;
}
loadAssets(scene: BattleScene, female: boolean, shiny?: boolean, startLoad?: boolean): Promise<void> {
return new Promise(resolve => {
scene.load.audio(this.speciesId.toString(), `audio/cry/${this.speciesId}.mp3`);
scene.loadAtlas(this.getSpriteKey(female, shiny), 'pokemon', this.getSpriteAtlasPath(female, shiny));
scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
const originalWarn = console.warn;
// Ignore warnings for missing frames, because there will be a lot
console.warn = () => {};
const frameNames = scene.anims.generateFrameNames(this.getSpriteKey(female, shiny), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
console.warn = originalWarn;
scene.anims.create({
key: this.getSpriteKey(female, shiny),
frames: frameNames,
frameRate: 12,
repeat: -1
});
resolve();
});
if (startLoad) {
if (!scene.load.isLoading())
scene.load.start();
} else
resolve();
});
}
generateIconAnim(scene: BattleScene): void {
const frameNames = scene.anims.generateFrameNames(this.getIconAtlasKey(), { prefix: `${this.getIconId()}_`, zeroPad: 2, suffix: '.png', start: 1, end: 34 });
scene.anims.create({
@ -234,6 +272,11 @@ export default class PokemonSpecies {
repeat: -1
});
}
cry(scene: BattleScene, soundConfig?: Phaser.Types.Sound.SoundConfig): integer {
scene.sound.play(this.speciesId.toString(), soundConfig);
return scene.sound.get(this.speciesId.toString()).totalDuration * 1000;
}
}
class PokemonForm extends PokemonSpecies {
@ -750,14 +793,14 @@ export const allSpecies = [
[ Species.PROBOPASS, "Probopass", 4, 0, 0, 0, "Compass Pokémon", Type.ROCK, Type.STEEL, 1.4, 340, "Sturdy", "Magnet Pull", "Sand Force", 525, 60, 55, 145, 75, 150, 40, 60, 70, 184, GrowthRate.MEDIUM_FAST, "Mineral", null, 50, 20, 0 ],
[ Species.DUSKNOIR, "Dusknoir", 4, 0, 0, 0, "Gripper Pokémon", Type.GHOST, -1, 2.2, 106.6, "Pressure", null, "Frisk", 525, 45, 100, 135, 65, 135, 45, 45, 35, 236, GrowthRate.FAST, "Amorphous", null, 50, 25, 0 ],
[ Species.FROSLASS, "Froslass", 4, 0, 0, 0, "Snow Land Pokémon", Type.ICE, Type.GHOST, 1.3, 26.6, "Snow Cloak", null, "Cursed Body", 480, 70, 80, 70, 80, 70, 110, 75, 70, 168, GrowthRate.MEDIUM_FAST, "Fairy", "Mineral", 0, 20, 0 ],
[ Species.ROTOM, "Rotom", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GHOST, 0.3, 0.3, "Levitate", null, null, 440, 50, 50, 77, 95, 77, 91, 45, 70, 154, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1,
[ Species.ROTOM, "Rotom", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GHOST, 0.3, 0.3, "Levitate", null, null, 440, 50, 50, 77, 95, 77, 91, 45, 70, 154, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0,
[
[ "Normal", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GHOST, 0.3, 0.3, "Levitate", null, null, 440, 50, 50, 77, 95, 77, 91, 45, 70, 154, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ],
[ "Heat", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.FIRE, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ],
[ "Wash", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.WATER, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ],
[ "Frost", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.ICE, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ],
[ "Fan", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.FLYING, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ],
[ "Mow", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GRASS, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 1 ]
[ "Normal", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GHOST, 0.3, 0.3, "Levitate", null, null, 440, 50, 50, 77, 95, 77, 91, 45, 70, 154, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ],
[ "Heat", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.FIRE, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ],
[ "Wash", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.WATER, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ],
[ "Frost", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.ICE, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ],
[ "Fan", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.FLYING, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ],
[ "Mow", 4, 0, 0, 0, "Plasma Pokémon", Type.ELECTRIC, Type.GRASS, 0.3, 0.3, "Levitate", null, null, 520, 50, 65, 107, 105, 107, 86, 45, 70, 182, GrowthRate.MEDIUM_FAST, "Amorphous", null, null, 20, 0 ]
]
],
[ Species.UXIE, "Uxie", 4, 1, 0, 0, "Knowledge Pokémon", Type.PSYCHIC, -1, 0.3, 0.3, "Levitate", null, null, 580, 75, 75, 130, 75, 130, 95, 3, 140, 261, GrowthRate.SLOW, "Undiscovered", null, null, 80, 0 ],

View File

@ -163,32 +163,24 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
Promise.allSettled(moveIds.map(m => initMoveAnim(m)))
.then(() => {
loadMoveAnimAssets(this.scene as BattleScene, moveIds);
(this.scene as BattleScene).loadAtlas(this.getSpriteKey(), 'pokemon', this.getSpriteAtlasPath());
this.species.loadAssets(this.scene as BattleScene, this.gender === Gender.FEMALE);
if (this.isPlayer())
(this.scene as BattleScene).loadAtlas(this.getBattleSpriteKey(), 'pokemon', this.getBattleSpriteAtlasPath());
this.scene.load.audio(this.species.speciesId.toString(), `audio/cry/${this.species.speciesId}.mp3`);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
const originalWarn = console.warn;
// Ignore warnings for missing frames, because there will be a lot
console.warn = () => {};
const frameNames = this.scene.anims.generateFrameNames(this.getSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
const battleFrameNames = this.isPlayer()
? this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 })
: null;
console.warn = originalWarn;
this.scene.anims.create({
key: this.getSpriteKey(),
frames: frameNames,
frameRate: 12,
repeat: -1
});
if (this.isPlayer()) {
this.scene.anims.create({
key: this.getBattleSpriteKey(),
frames: battleFrameNames,
frameRate: 12,
repeat: -1
});
const originalWarn = console.warn;
// Ignore warnings for missing frames, because there will be a lot
console.warn = () => {};
const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
console.warn = originalWarn;
if (this.isPlayer()) {
this.scene.anims.create({
key: this.getBattleSpriteKey(),
frames: battleFrameNames,
frameRate: 12,
repeat: -1
});
}
}
this.playAnim();
resolve();
@ -208,7 +200,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getSpriteId(): string {
return `${this.shiny ? 'shiny__' : ''}${this.species.genderDiffs && !this.gender ? 'female__' : ''}${this.species.speciesId}`;
return this.species.getSpriteId(this.gender === Gender.FEMALE, this.shiny);
}
getBattleSpriteId(): string {
@ -216,7 +208,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getSpriteKey(): string {
return `pkmn__${this.getSpriteId()}`;
return this.species.getSpriteKey(this.gender === Gender.FEMALE, this.shiny);
}
getBattleSpriteKey(): string {
@ -507,8 +499,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
cry(soundConfig?: Phaser.Types.Sound.SoundConfig): integer {
this.scene.sound.play(this.species.speciesId.toString(), soundConfig);
return this.scene.sound.get(this.species.speciesId.toString()).totalDuration * 1000;
return this.species.cry(this.scene as BattleScene, soundConfig);
}
faintCry(callback: Function) {

View File

@ -1,10 +1,37 @@
import BattleScene, { Button } from "../battle-scene";
import { allSpecies } from "../pokemon-species";
import PokemonSpecies, { allSpecies } from "../pokemon-species";
import { Species } from "../species";
import { TextStyle, addTextObject } from "../text";
import { Mode } from "./ui";
import UiHandler from "./uiHandler";
import * as Utils from "../utils";
import MessageUiHandler from "./message-ui-handler";
export default class StarterSelectUiHandler extends UiHandler {
export type StarterSelectCallback = (starterSpecies: PokemonSpecies[]) => void;
export default class StarterSelectUiHandler extends MessageUiHandler {
private starterSelectContainer: Phaser.GameObjects.Container;
private starterSelectGenIconContainers: Phaser.GameObjects.Container[];
private pokemonNumberText: Phaser.GameObjects.Text;
private pokemonSprite: Phaser.GameObjects.Sprite;
private pokemonNameText: Phaser.GameObjects.Text;
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
private genMode: boolean;
private genCursor: integer = 0;
private genSpecies: PokemonSpecies[][] = [];
private lastSpecies: PokemonSpecies;
private speciesLoaded: Map<Species, boolean> = new Map<Species, boolean>();
private starterGens: integer[] = [];
private starterCursors: integer[] = [];
private assetLoadCancelled: Utils.BooleanHolder;
private cursorObj: Phaser.GameObjects.Image;
private starterCursorObjs: Phaser.GameObjects.Image[];
private starterIcons: Phaser.GameObjects.Sprite[];
private genCursorObj: Phaser.GameObjects.Image;
private genCursorHighlightObj: Phaser.GameObjects.Image;
private starterSelectCallback: StarterSelectCallback;
constructor(scene: BattleScene) {
super(scene, Mode.STARTER_SELECT);
@ -17,38 +44,217 @@ export default class StarterSelectUiHandler extends UiHandler {
this.starterSelectContainer.setVisible(false);
ui.add(this.starterSelectContainer);
let s = 0;
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.starterSelectContainer.add(bgColor);
for (let species of allSpecies) {
if (species.getSpeciesForLevel(1) !== species.speciesId || species.generation >= 6)
continue;
species.generateIconAnim(this.scene);
const x = (s % 24) * 13;
const y = Math.floor(s / 24) * 13;
const icon = this.scene.add.sprite(x, y, species.getIconAtlasKey());
const starterSelectBg = this.scene.add.image(1, 1, 'starter_select_bg');
starterSelectBg.setOrigin(0, 0);
this.starterSelectContainer.add(starterSelectBg);
this.pokemonNumberText = addTextObject(this.scene, 17, 1, '000', TextStyle.SUMMARY);
this.pokemonNumberText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNumberText);
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
this.starterSelectContainer.add(this.pokemonSprite);
this.pokemonNameText = addTextObject(this.scene, 6, 112, '', TextStyle.SUMMARY);
this.pokemonNameText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNameText);
const genText = addTextObject(this.scene, 115, 6, 'I\nII\nIII\nIV\nV', TextStyle.WINDOW);
genText.setLineSpacing(16);
this.starterSelectContainer.add(genText);
this.starterSelectGenIconContainers = new Array(5).fill(null).map((_, i) => {
const container = this.scene.add.container(149, 9);
if (i)
container.setVisible(false);
this.starterSelectContainer.add(container);
return container;
});
this.starterCursorObjs = new Array(3).fill(null).map(() => {
const cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor_highlight');
cursorObj.setVisible(false);
cursorObj.setOrigin(0, 0);
this.starterSelectContainer.add(cursorObj);
return cursorObj;
});
this.cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor');
this.cursorObj.setOrigin(0, 0);
this.starterSelectContainer.add(this.cursorObj);
this.genCursorHighlightObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor_highlight');
this.genCursorHighlightObj.setOrigin(0, 0);
this.starterSelectContainer.add(this.genCursorHighlightObj);
this.genCursorObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor');
this.genCursorObj.setVisible(false);
this.genCursorObj.setOrigin(0, 0);
this.starterSelectContainer.add(this.genCursorObj);
for (let g = 0; g < this.starterSelectGenIconContainers.length; g++) {
let s = 0;
this.genSpecies.push([]);
for (let species of allSpecies) {
if (species.getPrevolutionLevels(true).length || species.generation !== g + 1)
continue;
this.speciesLoaded.set(species.speciesId, false);
this.genSpecies[g].push(species);
species.generateIconAnim(this.scene);
const x = (s % 9) * 18;
const y = Math.floor(s / 9) * 18;
const icon = this.scene.add.sprite(x, y, species.getIconAtlasKey());
icon.setScale(0.5);
icon.setOrigin(0, 0);
icon.play(species.getIconKey()).stop();
this.starterSelectGenIconContainers[g].add(icon);
s++;
}
}
this.scene.anims.create({
key: 'pkmn_icon__000',
frames: this.scene.anims.generateFrameNames('pokemon_icons_0', { prefix: `000_`, zeroPad: 2, suffix: '.png', start: 1, end: 34 }),
frameRate: 128,
repeat: -1
});
this.starterIcons = new Array(3).fill(null).map((_, i) => {
const icon = this.scene.add.sprite(115, 95 + 16 * i, 'pokemon_icons_0');
icon.setScale(0.5);
icon.setOrigin(0, 0);
icon.play(species.getIconKey()).stop();
icon.play('pkmn_icon__000');
this.starterSelectContainer.add(icon);
s++;
return icon;
});
this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6);
this.starterSelectMessageBoxContainer.setVisible(false);
this.starterSelectContainer.add(this.starterSelectMessageBoxContainer);
const starterSelectMessageBox = this.scene.add.image(0, 0, 'starter_select_message');
starterSelectMessageBox.setOrigin(0, 1);
this.starterSelectMessageBoxContainer.add(starterSelectMessageBox);
this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 });
this.message.setOrigin(0, 1);
this.starterSelectMessageBoxContainer.add(this.message);
}
show(args: any[]): void {
if (args.length >= 1 && args[0] instanceof Function) {
super.show(args);
this.starterSelectCallback = args[0] as StarterSelectCallback;
this.starterSelectContainer.setVisible(true);
this.setGenMode(false);
this.setCursor(0);
this.setGenMode(true);
this.setCursor(0);
}
}
show(args: any[]) {
super.show(args);
this.starterSelectContainer.setVisible(true);
this.setCursor(0);
showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) {
super.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
this.starterSelectMessageBoxContainer.setVisible(true);
}
processInput(button: Button) {
processInput(button: Button): void {
const ui = this.getUi();
let success = false;
if (button === Button.ACTION) {
} else if (button === Button.CANCEL) {
if (this.genMode) {
switch (button) {
case Button.UP:
if (this.genCursor)
success = this.setCursor(this.genCursor - 1);
break;
case Button.DOWN:
if (this.genCursor < 4)
success = this.setCursor(this.genCursor + 1);
break;
case Button.RIGHT:
success = this.setGenMode(false);
break;
}
} else {
if (button === Button.ACTION) {
if (this.starterCursors.length < 3) {
let isDupe = false;
for (let s = 0; s < this.starterCursors.length; s++) {
if (this.starterGens[s] === this.genCursor && this.starterCursors[s] === this.cursor) {
isDupe = true;
break;
}
}
if (!isDupe) {
const cursorObj = this.starterCursorObjs[this.starterCursors.length];
cursorObj.setVisible(true);
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
const species = this.genSpecies[this.genCursor][this.cursor];
this.starterIcons[this.starterCursors.length].play(species.getIconKey());
this.starterGens.push(this.genCursor);
this.starterCursors.push(this.cursor);
if (this.speciesLoaded.get(species.speciesId))
species.cry(this.scene);
if (this.starterCursors.length === 3) {
ui.showText('Begin with these POKéMON?', null, () => {
ui.setModeWithoutClear(Mode.CONFIRM, () => {
ui.setMode(Mode.STARTER_SELECT);
const originalStarterSelectCallback = this.starterSelectCallback;
this.starterSelectCallback = null;
originalStarterSelectCallback(new Array(3).fill(0).map((_, i) => this.genSpecies[this.starterGens[i]][this.starterCursors[i]]));
}, () => {
ui.setMode(Mode.STARTER_SELECT);
this.popStarter();
this.clearText();
});
});
}
success = true;
} else
ui.playError();
}
} else if (button === Button.CANCEL) {
if (this.starterCursors.length) {
this.popStarter();
success = true;
} else
ui.playError();
} else {
const genStarters = this.starterSelectGenIconContainers[this.genCursor].getAll().length;
const rows = Math.ceil(genStarters / 9);
const row = Math.floor(this.cursor / 9);
switch (button) {
case Button.UP:
if (row)
success = this.setCursor(this.cursor - 9);
break;
case Button.DOWN:
if (row < rows - 2 || (row < rows - 1 && this.cursor % 9 <= (genStarters - 1) % 9))
success = this.setCursor(this.cursor + 9);
break;
case Button.LEFT:
if (this.cursor % 9)
success = this.setCursor(this.cursor - 1);
else
success = this.setGenMode(true);
break;
case Button.RIGHT:
if (this.cursor % 9 < (row < rows - 1 ? 8 : (genStarters - 1) % 9))
success = this.setCursor(this.cursor + 1);
break;
}
}
}
if (success)
@ -56,17 +262,99 @@ export default class StarterSelectUiHandler extends UiHandler {
}
setCursor(cursor: integer): boolean {
let changed: boolean = this.cursor !== cursor;
let changed = false;
if (changed) {
const forward = this.cursor < cursor;
this.cursor = cursor;
if (this.genMode) {
changed = this.genCursor !== cursor;
if (this.genCursor !== undefined)
this.starterSelectGenIconContainers[this.genCursor].setVisible(false);
this.cursor = 0;
this.genCursor = cursor;
this.genCursorObj.setY(5 + 17 * this.genCursor);
this.genCursorHighlightObj.setY(this.genCursorObj.y);
this.starterSelectGenIconContainers[this.genCursor].setVisible(true);
for (let s = 0; s < this.starterCursorObjs.length; s++)
this.starterCursorObjs[s].setVisible(this.starterGens[s] === cursor);
} else {
changed = super.setCursor(cursor);
this.cursorObj.setPosition(148 + 18 * (cursor % 9), 10 + 18 * Math.floor(cursor / 9));
this.setSpecies(this.genSpecies[this.genCursor][cursor]);
}
return changed;
}
setGenMode(genMode: boolean): boolean {
if (genMode !== this.genMode) {
this.genMode = genMode;
this.genCursorObj.setVisible(genMode);
this.cursorObj.setVisible(!genMode);
this.setCursor(genMode ? this.genCursor : this.cursor);
if (genMode)
this.setSpecies(null);
return true;
}
return false;
}
setSpecies(species: PokemonSpecies) {
this.pokemonSprite.setVisible(false);
if (this.assetLoadCancelled) {
this.assetLoadCancelled.value = true;
this.assetLoadCancelled = null;
}
if (this.lastSpecies)
(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies)) as Phaser.GameObjects.Sprite).stop();
if (species) {
this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 3));
this.pokemonNameText.setText(species.name.toUpperCase());
const assetLoadCancelled = new Utils.BooleanHolder(false);
this.assetLoadCancelled = assetLoadCancelled;
const female = Utils.randInt(2) === 1;
species.loadAssets(this.scene, female, false, true).then(() => {
if (assetLoadCancelled.value)
return;
this.assetLoadCancelled = null;
this.speciesLoaded.set(species.speciesId, true);
this.pokemonSprite.play(species.getSpriteKey(female, false));
this.pokemonSprite.setVisible(true);
});
(this.starterSelectGenIconContainers[this.genCursor].getAt(this.cursor) as Phaser.GameObjects.Sprite).play(species.getIconKey());
} else {
this.pokemonNumberText.setText(Utils.padInt(0, 3));
this.pokemonNameText.setText('');
}
this.lastSpecies = species;
}
popStarter(): void {
this.starterGens.pop();
this.starterCursors.pop();
this.starterCursorObjs[this.starterCursors.length].setVisible(false);
this.starterIcons[this.starterCursors.length].play('pkmn_icon__000');
}
clearText() {
this.starterSelectMessageBoxContainer.setVisible(false);
super.clearText();
}
clear() {
clear(): void {
super.clear();
this.cursor = -1;
this.starterSelectContainer.setVisible(false);

View File

@ -20,11 +20,11 @@ export enum Mode {
BALL,
MODIFIER_SELECT,
PARTY,
CONFIRM,
SUMMARY,
BIOME_SELECT,
STARTER_SELECT,
EVOLUTION_SCENE
EVOLUTION_SCENE,
CONFIRM
};
const transitionModes = [
@ -56,11 +56,11 @@ export default class UI extends Phaser.GameObjects.Container {
new BallUiHandler(scene),
new ModifierSelectUiHandler(scene),
new PartyUiHandler(scene),
new ConfirmUiHandler(scene),
new SummaryUiHandler(scene),
new BiomeSelectUiHandler(scene),
new StarterSelectUiHandler(scene),
new EvolutionSceneHandler(scene)
new EvolutionSceneHandler(scene),
new ConfirmUiHandler(scene)
];
}

View File

@ -18,7 +18,7 @@ export default abstract class UiHandler {
this.active = true;
}
abstract processInput(button: Button);
abstract processInput(button: Button): void;
getUi() {
return this.scene.ui;

View File

@ -62,6 +62,14 @@ export function getEnumValues(enumType): integer[] {
return Object.values(enumType).filter(v => !isNaN(parseInt(v.toString()))).map(v => parseInt(v.toString()));
}
export class BooleanHolder {
public value: boolean;
constructor(value: boolean) {
this.value = value;
}
}
export class NumberHolder {
public value: number;