Add WiP evolution phase

pull/1/head
Flashfyre 2023-04-10 07:59:00 -04:00
parent 15105231ba
commit 824106c2a3
10 changed files with 331 additions and 26 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

View File

@ -101,7 +101,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
} }
} }
updateInfo(pokemon: Pokemon): Promise<void> { updateInfo(pokemon: Pokemon, instant?: boolean): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
if (!this.scene) { if (!this.scene) {
resolve(); resolve();
@ -109,7 +109,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
} }
const updatePokemonHp = () => { const updatePokemonHp = () => {
const duration = Utils.clampInt(Math.abs((this.lastHp) - pokemon.hp) * 5, 250, 5000); const duration = !instant ? Utils.clampInt(Math.abs((this.lastHp) - pokemon.hp) * 5, 250, 5000) : 0;
this.scene.tweens.add({ this.scene.tweens.add({
targets: this.hpBar, targets: this.hpBar,
ease: 'Sine.easeOut', ease: 'Sine.easeOut',
@ -154,13 +154,13 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}); });
} }
updatePokemonExp(battler: Pokemon): Promise<void> { updatePokemonExp(battler: Pokemon, instant?: boolean): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
const levelUp = this.lastLevel < battler.level; const levelUp = this.lastLevel < battler.level;
const relLevelExp = getLevelRelExp(this.lastLevel + 1, battler.species.growthRate); const relLevelExp = getLevelRelExp(this.lastLevel + 1, battler.species.growthRate);
const levelExp = levelUp ? relLevelExp : battler.levelExp; const levelExp = levelUp ? relLevelExp : battler.levelExp;
let ratio = levelExp / relLevelExp; let ratio = levelExp / relLevelExp;
let duration = this.visible ? ((levelExp - this.lastLevelExp) / relLevelExp) * 1650 : 0; let duration = this.visible && !instant ? ((levelExp - this.lastLevelExp) / relLevelExp) * 1650 : 0;
if (duration) if (duration)
this.scene.sound.play('exp'); this.scene.sound.play('exp');
this.scene.tweens.add({ this.scene.tweens.add({
@ -191,7 +191,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.setLevel(this.lastLevel); this.setLevel(this.lastLevel);
this.scene.time.delayedCall(500, () => { this.scene.time.delayedCall(500, () => {
this.expBar.setScale(0, 1); this.expBar.setScale(0, 1);
this.updateInfo(battler).then(() => resolve()); this.updateInfo(battler, instant).then(() => resolve());
}); });
return; return;
} else { } else {

View File

@ -12,6 +12,8 @@ import { pokemonLevelMoves } from "./pokemon-level-moves";
import { MoveAnim, initAnim, loadMoveAnimAssets } from "./battle-anims"; import { MoveAnim, initAnim, loadMoveAnimAssets } from "./battle-anims";
import { StatusEffect } from "./status-effect"; import { StatusEffect } from "./status-effect";
import { SummaryUiMode } from "./ui/summary-ui-handler"; import { SummaryUiMode } from "./ui/summary-ui-handler";
import { Species } from "./species";
import { SpeciesEvolution } from "./pokemon-evolutions";
export class BattlePhase { export class BattlePhase {
protected scene: BattleScene; protected scene: BattleScene;
@ -1014,6 +1016,277 @@ export class AttemptCapturePhase extends BattlePhase {
} }
} }
export class EvolutionPhase extends BattlePhase {
private partyMemberIndex: integer;
private evolution: SpeciesEvolution;
private evolutionContainer: Phaser.GameObjects.Container;
private evolutionBaseBg: Phaser.GameObjects.Image;
private evolutionBg: Phaser.GameObjects.Video;
private evolutionBgOverlay: Phaser.GameObjects.Rectangle;
private pokemonSprite: Phaser.GameObjects.Sprite;
private pokemonTintSprite: Phaser.GameObjects.Sprite;
private pokemonEvoSprite: Phaser.GameObjects.Sprite;
private pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, partyMemberIndex: integer, evolution: SpeciesEvolution) {
super(scene);
this.partyMemberIndex = partyMemberIndex;
this.evolution = evolution;
}
start() {
super.start();
if (!this.evolution) {
this.end();
return;
}
this.scene.pauseBgm();
this.evolutionContainer = this.scene.add.container(0, 0);
this.scene.field.add(this.evolutionContainer);
this.evolutionBaseBg = this.scene.add.image(0, 0, 'plains_bg');
this.evolutionBaseBg.setOrigin(0, 0);
this.evolutionContainer.add(this.evolutionBaseBg);
this.evolutionBg = this.scene.add.video(0, 0, 'evo_bg').stop();
this.evolutionBg.setOrigin(0, 0);
this.evolutionBg.setScale(0.4359673025);
this.evolutionBg.setVisible(false);
this.evolutionContainer.add(this.evolutionBg);
this.evolutionBgOverlay = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x262626);
this.evolutionBgOverlay.setOrigin(0, 0);
this.evolutionBgOverlay.setAlpha(0);
this.evolutionContainer.add(this.evolutionBgOverlay);
const getPokemonSprite = () => {
return this.scene.add.sprite(this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`);
};
this.evolutionContainer.add((this.pokemonSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonTintSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonEvoSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonEvoTintSprite = getPokemonSprite()));
this.pokemonTintSprite.setAlpha(0);
this.pokemonTintSprite.setTintFill(0xFFFFFF);
this.pokemonEvoSprite.setVisible(false);
this.pokemonEvoTintSprite.setVisible(false);
this.pokemonEvoTintSprite.setTintFill(0xFFFFFF);
const pokemon = this.scene.getParty()[this.partyMemberIndex];
this.pokemonSprite.play(pokemon.getSpriteKey());
this.pokemonTintSprite.play(pokemon.getSpriteKey());
this.pokemonEvoSprite.play(pokemon.getSpriteKey());
this.pokemonEvoTintSprite.play(pokemon.getSpriteKey());
this.scene.ui.showText(`What?\n${pokemon.name} is evolving!`, null, () => {
pokemon.cry();
pokemon.evolve(this.evolution).then(() => {
this.pokemonEvoSprite.play(pokemon.getSpriteKey());
this.pokemonEvoTintSprite.play(pokemon.getSpriteKey());
});
this.scene.time.delayedCall(1000, () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 1,
delay: 500,
duration: 1500,
ease: 'Sine.easeOut',
onComplete: () => {
this.scene.time.delayedCall(1000, () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 0,
duration: 250,
onComplete: () => this.evolutionBgOverlay.setVisible(false)
});
this.evolutionBg.setVisible(true);
this.evolutionBg.play();
});
this.doSpiralUpward();
this.scene.tweens.addCounter({
from: 0,
to: 1,
duration: 2000,
onUpdate: t => {
this.pokemonTintSprite.setAlpha(t.getValue());
},
onComplete: () => {
this.pokemonSprite.setVisible(false);
this.scene.time.delayedCall(1000, () => {
this.doArcDownward();
this.scene.time.delayedCall(1500, () => {
this.pokemonEvoTintSprite.setScale(0.25);
this.pokemonEvoTintSprite.setVisible(true);
this.doCycle(1).then(() => {
this.scene.sound.play('shiny');
this.pokemonEvoSprite.setVisible(true);
});
});
});
}
})
}
});
//this.scene.sound.play('evolution');
});
}, 1000);
}
sin(index: integer, amplitude: integer) {
return amplitude * Math.sin(index * (Math.PI / 128));
}
cos(index: integer, amplitude: integer) {
return amplitude * Math.cos(index * (Math.PI / 128));
}
doSpiralUpward() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 64,
duration: 1,
useFrames: true,
onRepeat: () => {
if (f < 64) {
if (!(f & 7)) {
for (let i = 0; i < 4; i++)
this.doSpiralUpwardParticle((f & 120) * 2 + i * 64);
}
f++;
}
}
});
}
doArcDownward() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 96,
duration: 1,
useFrames: true,
onRepeat: () => {
if (f < 96) {
if (f < 6) {
for (let i = 0; i < 9; i++)
this.doArcDownParticle(i * 16);
}
f++;
}
}
});
}
doCycle(l: number): Promise<void> {
return new Promise(resolve => {
const isLastCycle = l === 15;
this.scene.tweens.add({
targets: this.pokemonTintSprite,
scale: 0.25,
ease: 'Cubic.easeInOut',
duration: 500 / l,
yoyo: !isLastCycle
});
this.scene.tweens.add({
targets: this.pokemonEvoTintSprite,
scale: 1,
ease: 'Cubic.easeInOut',
duration: 500 / l,
yoyo: !isLastCycle,
onComplete: () => {
if (l < 15)
this.doCycle(l + 0.5).then(() => resolve());
else {
this.pokemonTintSprite.setVisible(false);
resolve();
}
}
});
});
}
doSpiralUpwardParticle(trigIndex: integer) {
const initialX = (this.scene.game.canvas.width / 6) / 2;
const particle = this.scene.add.image(initialX, 0, 'evo_sparkle');
this.evolutionContainer.add(particle);
let f = 0;
let amp = 48;
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
duration: 1,
useFrames: true,
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (!f || particle.y > 8) {
particle.setPosition(initialX, 88 - (f * f) / 80);
particle.y += this.sin(trigIndex, amp) / 4;
particle.x += this.cos(trigIndex, amp);
particle.setScale(1 - (f / 80));
trigIndex += 4;
if (f & 1)
amp--;
f++;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
doArcDownParticle(trigIndex: integer) {
const initialX = (this.scene.game.canvas.width / 6) / 2;
const particle = this.scene.add.image(initialX, 0, 'evo_sparkle');
particle.setScale(0.5);
this.evolutionContainer.add(particle);
let f = 0;
let amp = 8;
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
duration: 1,
useFrames: true,
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (!f || particle.y < 88) {
particle.setPosition(initialX, 8 + (f * f) / 5);
particle.y += this.sin(trigIndex, amp) / 4;
particle.x += this.cos(trigIndex, amp);
amp = 8 + this.sin(f * 4, 40);
f++;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
}
export class SelectModifierPhase extends BattlePhase { export class SelectModifierPhase extends BattlePhase {
constructor(scene: BattleScene) { constructor(scene: BattleScene) {
super(scene); super(scene);

View File

@ -1,17 +1,16 @@
import Phaser from 'phaser'; import Phaser from 'phaser';
import { Biome, BiomeArena } from './biome'; import { Biome, BiomeArena } from './biome';
import UI from './ui/ui'; import UI from './ui/ui';
import { BattlePhase, EncounterPhase, SummonPhase, CommandPhase, NextEncounterPhase, SwitchBiomePhase, NewBiomeEncounterPhase } from './battle-phase'; import { BattlePhase, EncounterPhase, SummonPhase, CommandPhase, NextEncounterPhase, SwitchBiomePhase, NewBiomeEncounterPhase, EvolutionPhase } from './battle-phase';
import { PlayerPokemon, EnemyPokemon } from './pokemon'; import { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { allSpecies, getPokemonSpecies } from './pokemon-species'; import PokemonSpecies, { allSpecies, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils'; import * as Utils from './utils';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PartyShareModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonBaseStatBoosterModifierType, PokemonBaseStatModifier } from './modifier'; import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PartyShareModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier } from './modifier';
import { PokeballType } from './pokeball'; import { PokeballType } from './pokeball';
import { Species } from './species'; import { Species } from './species';
import { initAutoPlay } from './auto-play'; import { initAutoPlay } from './auto-play';
import { Battle } from './battle'; import { Battle } from './battle';
import { populateAnims } from './battle-anims'; import { populateAnims } from './battle-anims';
import { Stat } from './pokemon-stat';
const enableAuto = true; const enableAuto = true;
@ -164,6 +163,8 @@ export default class BattleScene extends Phaser.Scene {
this.loadImage(`pkmn__back__sub`, 'pokemon/back', 'sub.png'); this.loadImage(`pkmn__back__sub`, 'pokemon/back', 'sub.png');
this.loadImage(`pkmn__sub`, 'pokemon', 'sub.png'); this.loadImage(`pkmn__sub`, 'pokemon', 'sub.png');
this.loadAtlas('shiny', 'effects'); this.loadAtlas('shiny', 'effects');
this.loadImage('evo_sparkle', 'effects');
this.load.video('evo_bg', 'images/effects/evo_bg.mp4', null, false, true);
this.loadAtlas('pb', ''); this.loadAtlas('pb', '');
this.loadAtlas('items', ''); this.loadAtlas('items', '');
@ -197,6 +198,8 @@ export default class BattleScene extends Phaser.Scene {
this.loadSe('pb_lock'); this.loadSe('pb_lock');
this.loadBgm('level_up_fanfare'); this.loadBgm('level_up_fanfare');
this.loadBgm('evolution');
this.loadBgm('evolution_fanfare');
//this.load.glsl('sprite', 'shaders/sprite.frag'); //this.load.glsl('sprite', 'shaders/sprite.frag');
@ -254,7 +257,7 @@ export default class BattleScene extends Phaser.Scene {
for (let s = 0; s < 3; s++) { for (let s = 0; s < 3; s++) {
const playerSpecies = getPokemonSpecies(s === 0 ? Species.TORCHIC : s === 1 ? Species.TREECKO : Species.MUDKIP); //this.randomSpecies(); const playerSpecies = getPokemonSpecies(s === 0 ? Species.TORCHIC : s === 1 ? Species.TREECKO : Species.MUDKIP); //this.randomSpecies();
const playerPokemon = new PlayerPokemon(this, playerSpecies, 5); const playerPokemon = new PlayerPokemon(this, playerSpecies, 16);
playerPokemon.setVisible(false); playerPokemon.setVisible(false);
loadPokemonAssets.push(playerPokemon.loadAssets()); loadPokemonAssets.push(playerPokemon.loadAssets());
@ -302,10 +305,6 @@ export default class BattleScene extends Phaser.Scene {
this.plusKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.PLUS); this.plusKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.PLUS);
this.minusKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.MINUS); this.minusKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.MINUS);
for (let a = 0; a < 3; a++) {
this.addModifier(new PokemonBaseStatModifier(new PokemonBaseStatBoosterModifierType('HP-UP', Stat.HP), this.getParty()[0].id, Stat.HP));
}
Promise.all(loadPokemonAssets).then(() => { Promise.all(loadPokemonAssets).then(() => {
if (enableAuto) if (enableAuto)
initAutoPlay.apply(this); initAutoPlay.apply(this);
@ -346,6 +345,7 @@ export default class BattleScene extends Phaser.Scene {
this.unshiftPhase(new NewBiomeEncounterPhase(this)); this.unshiftPhase(new NewBiomeEncounterPhase(this));
} }
} else { } else {
this.pushPhase(new EvolutionPhase(this, 0, this.getPlayerPokemon().getEvolution()));
//this.pushPhase(new SelectStarterPhase(this)); //this.pushPhase(new SelectStarterPhase(this));
this.pushPhase(new EncounterPhase(this)); this.pushPhase(new EncounterPhase(this));
this.pushPhase(new SummonPhase(this)); this.pushPhase(new SummonPhase(this));
@ -356,7 +356,7 @@ export default class BattleScene extends Phaser.Scene {
} }
newBiome(): BiomeArena { newBiome(): BiomeArena {
const biome = this.currentBattle ? Utils.randInt(20) as Biome : Biome.PLAINS; const biome = this.currentBattle ? Utils.randInt(20) as Biome : Biome.LAKE;
this.arena = new BiomeArena(this, biome, Biome[biome].toLowerCase()); this.arena = new BiomeArena(this, biome, Biome[biome].toLowerCase());
return this.arena; return this.arena;
} }

View File

@ -36,7 +36,11 @@ export class SpeciesEvolutionCondition {
} }
} }
export const pokemonEvolutions = { interface PokemonEvolutions {
[key: string]: SpeciesEvolution[]
}
export const pokemonEvolutions: PokemonEvolutions = {
[Species.BULBASAUR]: [ [Species.BULBASAUR]: [
new SpeciesEvolution(Species.IVYSAUR, 16, null, null) new SpeciesEvolution(Species.IVYSAUR, 16, null, null)
], ],

View File

@ -4,7 +4,7 @@ import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './battle-info';
import { MessagePhase } from './battle-phase'; import { MessagePhase } from './battle-phase';
import { default as Move, allMoves, MoveCategory, Moves } from './move'; import { default as Move, allMoves, MoveCategory, Moves } from './move';
import { pokemonLevelMoves } from './pokemon-level-moves'; import { pokemonLevelMoves } from './pokemon-level-moves';
import { default as PokemonSpecies } from './pokemon-species'; import { default as PokemonSpecies, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils'; import * as Utils from './utils';
import { getTypeDamageMultiplier } from './type'; import { getTypeDamageMultiplier } from './type';
import { getLevelTotalExp } from './exp'; import { getLevelTotalExp } from './exp';
@ -15,6 +15,7 @@ import { Gender } from './gender';
import { initAnim, loadMoveAnimAssets } from './battle-anims'; import { initAnim, loadMoveAnimAssets } from './battle-anims';
import { StatusEffect } from './status-effect'; import { StatusEffect } from './status-effect';
import { tmSpecies } from './tms'; import { tmSpecies } from './tms';
import { pokemonEvolutions, SpeciesEvolution, SpeciesEvolutionCondition } from './pokemon-evolutions';
export default abstract class Pokemon extends Phaser.GameObjects.Container { export default abstract class Pokemon extends Phaser.GameObjects.Container {
public id: integer; public id: integer;
@ -241,13 +242,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.getAt(2) as Phaser.GameObjects.Sprite; return this.getAt(2) as Phaser.GameObjects.Sprite;
} }
playAnim() { playAnim(): void{
this.getSprite().play(this.getBattleSpriteKey()); this.getSprite().play(this.getBattleSpriteKey());
this.getTintSprite().play(this.getBattleSpriteKey()); this.getTintSprite().play(this.getBattleSpriteKey());
this.getZoomSprite().play(this.getBattleSpriteKey()); this.getZoomSprite().play(this.getBattleSpriteKey());
} }
calculateStats() { calculateStats(): void {
if (!this.stats) if (!this.stats)
this.stats = [ 0, 0, 0, 0, 0, 0 ]; this.stats = [ 0, 0, 0, 0, 0, 0 ];
const baseStats = this.species.baseStats.slice(0); const baseStats = this.species.baseStats.slice(0);
@ -273,15 +274,42 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
} }
getMaxHp() { getMaxHp(): integer {
return this.stats[Stat.HP]; return this.stats[Stat.HP];
} }
getHpRatio() { getHpRatio(): number {
return Math.floor((this.hp / this.getMaxHp()) * 100) / 100; return Math.floor((this.hp / this.getMaxHp()) * 100) / 100;
} }
generateAndPopulateMoveset() { getEvolution(): SpeciesEvolution {
if (!pokemonEvolutions.hasOwnProperty(this.species.speciesId))
return null;
const evolutions = pokemonEvolutions[this.species.speciesId];
for (let e of evolutions) {
if (this.level >= e.level) {
// TODO: Remove string conditions
if (e.condition === null || typeof e.condition === 'string' || (e.condition as SpeciesEvolutionCondition).predicate(this))
return e;
}
}
return null;
}
evolve(evolution: SpeciesEvolution): Promise<void> {
return new Promise(resolve => {
console.log(evolution?.speciesId)
this.species = getPokemonSpecies(evolution.speciesId);
this.loadAssets().then(() => {
this.calculateStats();
this.updateInfo().then(() => resolve());
});
});
}
generateAndPopulateMoveset(): void {
this.moveset = []; this.moveset = [];
const movePool = []; const movePool = [];
const allLevelMoves = pokemonLevelMoves[this.species.speciesId]; const allLevelMoves = pokemonLevelMoves[this.species.speciesId];
@ -352,8 +380,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
} }
updateInfo(): Promise<void> { updateInfo(instant?: boolean): Promise<void> {
return this.battleInfo.updateInfo(this); return this.battleInfo.updateInfo(this, instant);
} }
addExp(exp: integer) { addExp(exp: integer) {
@ -669,10 +697,9 @@ export class EnemyPokemon extends Pokemon {
const scoreB = moveScores[movePool.indexOf(b)]; const scoreB = moveScores[movePool.indexOf(b)];
return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0; return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0;
}); });
let randInt: integer;
let r = 0; let r = 0;
if (this.aiType === AiType.SMART_RANDOM) { if (this.aiType === AiType.SMART_RANDOM) {
while (r < sortedMovePool.length - 1 && (randInt = Utils.randInt(8)) >= 5) while (r < sortedMovePool.length - 1 && Utils.randInt(8) >= 5)
r++; r++;
} }
console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName())); console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName()));

View File

@ -10,6 +10,7 @@ import ModifierSelectUiHandler from './modifier-select-ui-handler';
import BallUiHandler from './ball-ui-handler'; import BallUiHandler from './ball-ui-handler';
import SummaryUiHandler from './summary-ui-handler'; import SummaryUiHandler from './summary-ui-handler';
import StarterSelectUiHandler from './starter-select-ui-handler'; import StarterSelectUiHandler from './starter-select-ui-handler';
import EvolutionUiHandler from './evolution-ui-handler';
export enum Mode { export enum Mode {
MESSAGE = 0, MESSAGE = 0,
@ -20,7 +21,7 @@ export enum Mode {
MODIFIER_SELECT, MODIFIER_SELECT,
PARTY, PARTY,
SUMMARY, SUMMARY,
STARTER_SELECT, STARTER_SELECT
}; };
const transitionModes = [ const transitionModes = [