Add biome flow

pull/1/head
Flashfyre 2023-04-12 00:37:56 -04:00
parent 1bf0456511
commit 4c892c2c40
9 changed files with 245 additions and 41 deletions

View File

@ -8,7 +8,6 @@
- Get starters from save data caught Pokemon
- Moves
- Move logic
- Can't use when PP consumed
- Abilities
- Ability logic
- Ability activation indicator (?)
@ -26,7 +25,6 @@
- Status effect indicator
- Modifiers
- PP Up
- Ether/elixir
- Type enhancers
- Evolution items
- Various mainline game items for various enhancements
@ -38,6 +36,5 @@
- Custom art
- Battle bases and backgrounds
- Game sequence
- Biome sequence (random?)
- Endgame?
- Endless mode?

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

View File

@ -15,6 +15,7 @@ import EvolutionSceneHandler from "./ui/evolution-scene-handler";
import { EvolutionPhase } from "./evolution-phase";
import { BattlePhase } from "./battle-phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./battle-stat";
import { Biome, biomeLinks } from "./biome";
export class SelectStarterPhase extends BattlePhase {
constructor(scene: BattleScene) {
@ -132,7 +133,7 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
}
}
export class SwitchBiomePhase extends BattlePhase {
export class SelectBiomePhase extends BattlePhase {
constructor(scene: BattleScene) {
super(scene);
}
@ -142,6 +143,35 @@ export class SwitchBiomePhase extends BattlePhase {
this.scene.arena.fadeOutBgm(2000);
const currentBiome = this.scene.arena.biomeType;
const setNextBiome = (nextBiome: Biome) => {
this.scene.unshiftPhase(new SwitchBiomePhase(this.scene, nextBiome));
this.end();
};
if (Array.isArray(biomeLinks[currentBiome]))
this.scene.ui.setMode(Mode.BIOME_SELECT, currentBiome, (biomeIndex: integer) => {
this.scene.ui.setMode(Mode.MESSAGE);
setNextBiome((biomeLinks[currentBiome] as Biome[])[biomeIndex]);
});
else
setNextBiome(biomeLinks[currentBiome] as Biome)
}
}
export class SwitchBiomePhase extends BattlePhase {
private nextBiome: Biome;
constructor(scene: BattleScene, nextBiome: Biome) {
super(scene);
this.nextBiome = nextBiome;
}
start() {
super.start();
this.scene.tweens.add({
targets: this.scene.arenaEnemy,
x: '+=300',
@ -149,7 +179,7 @@ export class SwitchBiomePhase extends BattlePhase {
onComplete: () => {
this.scene.arenaEnemy.setX(this.scene.arenaEnemy.x - 600);
this.scene.newBiome();
this.scene.newBiome(this.nextBiome);
const biomeKey = this.scene.arena.getBiomeKey();
const bgTexture = `${biomeKey}_bg`;
@ -380,6 +410,7 @@ export class CommandPhase extends BattlePhase {
success = true;
break;
}
if (success) {
const enemyMove = enemyPokemon.getNextMove();
const enemyPhase = new EnemyMovePhase(this.scene, enemyPokemon, enemyMove);

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 } from './battle-phases';
import { EncounterPhase, SummonPhase, CommandPhase, NextEncounterPhase, SwitchBiomePhase, NewBiomeEncounterPhase, SelectBiomePhase } from './battle-phases';
import { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { allSpecies, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils';
@ -153,6 +153,9 @@ export default class BattleScene extends Phaser.Scene {
this.loadImage('summary_moves_overlay_pp', 'ui');
this.loadAtlas('summary_moves_cursor', 'ui');
this.loadImage('biome_select_window_2', 'ui');
this.loadImage('biome_select_window_3', 'ui');
// Load arena images
Utils.getEnumValues(Biome).map(at => {
const atKey = Biome[at].toLowerCase();
@ -238,25 +241,6 @@ export default class BattleScene extends Phaser.Scene {
this.field = field;
this.newBiome();
const biomeKey = this.arena.getBiomeKey();
this.arenaBg = this.add.sprite(0, 0, `${biomeKey}_bg`);
this.arenaBgTransition = this.add.sprite(0, 0, `${biomeKey}_bg`);
this.arenaPlayer = this.add.sprite(340, 20, `${biomeKey}_a`);
this.arenaPlayerTransition = this.add.sprite(40, 20, `${biomeKey}_a`);
this.arenaEnemy = this.add.sprite(-240, 13, `${biomeKey}_b`);
this.arenaNextEnemy = this.add.sprite(-240, 13, `${biomeKey}_b`);
this.arenaBgTransition.setVisible(false);
this.arenaPlayerTransition.setVisible(false);
[this.arenaBg, this.arenaBgTransition, this.arenaPlayer, this.arenaPlayerTransition, this.arenaEnemy, this.arenaNextEnemy].forEach(a => {
a.setOrigin(0, 0);
field.add(a);
});
this.arena.playBgm();
const fieldUI = this.add.container(0, this.game.canvas.height);
fieldUI.setDepth(1);
fieldUI.setScale(6);
@ -281,6 +265,29 @@ export default class BattleScene extends Phaser.Scene {
const isRandom = this.isButtonPressed(Button.RANDOM); // For testing purposes
if (isRandom) {
const biomes = Utils.getEnumValues(Biome);
this.newBiome(biomes[Utils.randInt(biomes.length)]);
} else
this.newBiome(Biome.PLAINS);
const biomeKey = this.arena.getBiomeKey();
this.arenaBg = this.add.sprite(0, 0, `${biomeKey}_bg`);
this.arenaBgTransition = this.add.sprite(0, 0, `${biomeKey}_bg`);
this.arenaPlayer = this.add.sprite(340, 20, `${biomeKey}_a`);
this.arenaPlayerTransition = this.add.sprite(40, 20, `${biomeKey}_a`);
this.arenaEnemy = this.add.sprite(-240, 13, `${biomeKey}_b`);
this.arenaNextEnemy = this.add.sprite(-240, 13, `${biomeKey}_b`);
this.arenaBgTransition.setVisible(false);
this.arenaPlayerTransition.setVisible(false);
[this.arenaBg, this.arenaBgTransition, this.arenaPlayer, this.arenaPlayerTransition, this.arenaEnemy, this.arenaNextEnemy].forEach(a => {
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);
@ -378,7 +385,7 @@ export default class BattleScene extends Phaser.Scene {
if (this.currentBattle.waveIndex % 10)
this.unshiftPhase(new NextEncounterPhase(this));
else {
this.unshiftPhase(new SwitchBiomePhase(this));
this.unshiftPhase(new SelectBiomePhase(this));
this.unshiftPhase(new NewBiomeEncounterPhase(this));
}
} else {
@ -391,8 +398,7 @@ export default class BattleScene extends Phaser.Scene {
return this.currentBattle;
}
newBiome(): BiomeArena {
const biome = this.currentBattle ? Utils.randInt(20) as Biome : Biome.PLAINS;
newBiome(biome: Biome): BiomeArena {
this.arena = new BiomeArena(this, biome, Biome[biome].toLowerCase());
return this.arena;
}

View File

@ -1,7 +1,7 @@
import BattleScene from "./battle-scene";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade.js";
import { pokemonEvolutions, SpeciesEvolution } from "./pokemon-evolutions";
import { default as PokemonSpecies, allSpecies, getPokemonSpecies } from "./pokemon-species";
import { default as PokemonSpecies, getPokemonSpecies } from "./pokemon-species";
import { Species } from "./species";
import { Type } from './type';
import * as Utils from './utils';
@ -35,6 +35,54 @@ export enum Biome {
SPACE
};
export function getBiomeName(biome: Biome) {
switch (biome) {
case Biome.PLAINS:
return 'STARTER PLAINS';
case Biome.GRASS:
return 'GRASSY FIELD';
case Biome.RUINS:
return 'ANCIENT RUINS';
case Biome.ABYSS:
return 'THE ABYSS';
case Biome.SPACE:
return 'STRATOSPHERE';
default:
return Biome[biome].replace(/\_/g, ' ');
}
}
interface BiomeLinks {
[key: integer]: Biome | Biome[]
}
export const biomeLinks: BiomeLinks = {
[Biome.PLAINS]: Biome.GRASS,
[Biome.GRASS]: [ Biome.TALL_GRASS, Biome.CITY, Biome.LAKE ],
[Biome.TALL_GRASS]: [ Biome.FOREST, Biome.CAVE ],
[Biome.CITY]: [ Biome.DOJO, Biome.POWER_PLANT ],
[Biome.FOREST]: Biome.MEADOW,
[Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ],
[Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ],
[Biome.BEACH]: Biome.SEA,
[Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP ],
[Biome.SEABED]: Biome.CAVE,
[Biome.MOUNTAIN]: [ Biome.WASTELAND, Biome.VOLCANO ],
[Biome.LAND]: [ Biome.DESERT, Biome.MOUNTAIN ],
[Biome.CAVE]: [ Biome.LAND, Biome.BEACH ],
[Biome.DESERT]: Biome.RUINS,
[Biome.ICE_CAVE]: Biome.LAKE,
[Biome.MEADOW]: Biome.GRASS,
[Biome.POWER_PLANT]: Biome.GRASS,
[Biome.VOLCANO]: Biome.ICE_CAVE,
[Biome.GRAVEYARD]: Biome.ABYSS,
[Biome.DOJO]: Biome.GRASS,
[Biome.RUINS]: Biome.FOREST,
[Biome.WASTELAND]: Biome.LAND,
[Biome.ABYSS]: Biome.SPACE,
[Biome.SPACE]: Biome.RUINS
};
enum PoolTier {
COMMON,
UNCOMMON,
@ -47,12 +95,24 @@ enum PoolTier {
BOSS_ULTRA_RARE
};
interface SpeciesTree {
[key: integer]: Species[]
}
interface BiomeTierPools {
[key: integer]: Array<Species | SpeciesTree>
}
interface BiomePools {
[key: integer]: BiomeTierPools
}
export class BiomeArena {
private scene: BattleScene;
public biomeType: integer;
private bgm: string;
private pokemonPool: PokemonSpecies[][];
private pokemonPool: BiomeTierPools;
constructor(scene: BattleScene, biome: integer, bgm: string) {
this.scene = scene;
@ -140,7 +200,7 @@ export class BiomeArena {
}
}
const biomePools = {
const biomePools: BiomePools = {
[Biome.PLAINS]: {
[PoolTier.COMMON]: [
{ 1: [ Species.CATERPIE ], 7: [ Species.METAPOD ] },
@ -3805,8 +3865,10 @@ const biomePools = {
let treeIndex = -1;
let arrayIndex = 0;
// Not sure why this works but let's just leave it alone until we need it again
for (let t = 0; t < biomeTierPool.length; t++) {
const existingSpeciesIds = biomeTierPool[t] as Species[];
const existingSpeciesIds = biomeTierPool[t] as SpeciesTree;
for (let es = 0; es < existingSpeciesIds.length; es++) {
const existingSpeciesId = existingSpeciesIds[es];
if (pokemonEvolutions.hasOwnProperty(existingSpeciesId) && (pokemonEvolutions[existingSpeciesId] as SpeciesEvolution[]).find(ese => ese.speciesId === speciesId)) {

View File

@ -766,7 +766,7 @@ const modifierPool = {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed)).length;
return thresholdPartyMemberCount;
}),
new WeightedModifierType(new PokemonPpRestoreModifierType('MAX ETHER', 100), (party: PlayerPokemon[]) => {
new WeightedModifierType(new PokemonPpRestoreModifierType('MAX ETHER', -1), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed > 10)).length;
return Math.ceil(thresholdPartyMemberCount / 3);
})
@ -793,7 +793,7 @@ const modifierPool = {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed)).length;
return thresholdPartyMemberCount;
}),
new WeightedModifierType(new PokemonAllMovePpRestoreModifierType('MAX ELIXIR', 100), (party: PlayerPokemon[]) => {
new WeightedModifierType(new PokemonAllMovePpRestoreModifierType('MAX ELIXIR', -1), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed > 10)).length;
return Math.ceil(thresholdPartyMemberCount / 3);
}),
@ -863,16 +863,13 @@ export function regenerateModifierPoolThresholds(party: PlayerPokemon[]) {
console.log(modifierPoolThresholds)
}
export function getModifierTypesForWave(waveIndex: integer, count: integer, party: PlayerPokemon[]): Array<ModifierType> {
export function getModifierTypesForWave(waveIndex: integer, count: integer, party: PlayerPokemon[]): ModifierType[] {
if (waveIndex % 10 === 0)
return modifierPool[ModifierTier.LUXURY];
const ret = [];
for (let m = 0; m < count; m++)
ret.push(getNewModifierType(party));
return ret;
return new Array(count).fill(0).map(() => getNewModifierType(party));
}
function getNewModifierType(party: PlayerPokemon[]) {
function getNewModifierType(party: PlayerPokemon[]): ModifierType {
const tierValue = Utils.randInt(256);
const tier = tierValue >= 52 ? ModifierTier.COMMON : tierValue >= 8 ? ModifierTier.GREAT : tierValue >= 1 ? ModifierTier.ULTRA : ModifierTier.MASTER;
const thresholds = Object.keys(modifierPoolThresholds[tier]);
@ -892,5 +889,5 @@ function getNewModifierType(party: PlayerPokemon[]) {
modifierType = (modifierType as WeightedModifierType).modifierType;
if (modifierType instanceof ModifierTypeGenerator)
modifierType = (modifierType as ModifierTypeGenerator).generateType(party);
return modifierType;
return modifierType as ModifierType;
}

View File

@ -0,0 +1,108 @@
import BattleScene, { Button } from "../battle-scene";
import { Biome, biomeLinks, getBiomeName } from "../biome";
import { addTextObject, TextStyle } from "../text";
import { Mode } from "./ui";
import UiHandler from "./uiHandler";
export default class BiomeSelectUiHandler extends UiHandler {
private biomeSelectContainer: Phaser.GameObjects.Container;
private biomeSelectBg: Phaser.GameObjects.Image;
private biomesText: Phaser.GameObjects.Text;
private biomeChoices: Biome[];
private cursorObj: Phaser.GameObjects.Image;
private biomeSelectHandler: Function;
constructor(scene: BattleScene) {
super(scene, Mode.BIOME_SELECT);
}
setup() {
const ui = this.getUi();
this.biomeSelectContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 97, -49);
this.biomeSelectContainer.setVisible(false);
ui.add(this.biomeSelectContainer);
this.biomeSelectBg = this.scene.add.image(0, 0, 'biome_select_window_2');
this.biomeSelectBg.setOrigin(0, 1);
this.biomeSelectContainer.add(this.biomeSelectBg);
this.biomesText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 3 });
this.biomesText.setLineSpacing(12);
this.biomeSelectContainer.add(this.biomesText);
}
show(args: any[]) {
if (args.length >= 2 && typeof(args[0]) === 'number' && args[1] instanceof Function) {
super.show(args);
if (!Array.isArray(biomeLinks[args[0]]))
return;
this.biomeChoices = biomeLinks[args[0]] as Biome[];
this.biomeSelectBg.setTexture(`biome_select_window_${this.biomeChoices.length}`)
this.biomesText.setText(this.biomeChoices.map(b => getBiomeName(b)).join('\n'));
this.biomesText.setPositionRelative(this.biomeSelectBg, 16, 9);
this.biomeSelectHandler = args[1] as Function;
this.biomeSelectContainer.setVisible(true);
this.setCursor(0);
}
}
processInput(button: Button) {
const ui = this.getUi();
let success = false;
if (button === Button.ACTION || button === Button.CANCEL) {
success = true;
const originalBiomeSelectHandler = this.biomeSelectHandler;
this.biomeSelectHandler = null;
originalBiomeSelectHandler(this.cursor);
this.clear();
} else {
switch (button) {
case Button.UP:
if (this.cursor)
success = this.setCursor(this.cursor - 1);
break;
case Button.DOWN:
if (this.cursor < this.biomeChoices.length - 1)
success = this.setCursor(this.cursor + 1);
break;
}
}
if (success)
ui.playSelect();
}
setCursor(cursor: integer): boolean {
const ret = super.setCursor(cursor);
if (!this.cursorObj) {
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
this.biomeSelectContainer.add(this.cursorObj);
}
this.cursorObj.setPositionRelative(this.biomeSelectBg, 12, 17 + 16 * this.cursor);
return ret;
}
clear() {
super.clear();
this.biomeSelectContainer.setVisible(false);
this.biomeSelectHandler = null;
this.eraseCursor();
}
eraseCursor() {
if (this.cursorObj)
this.cursorObj.destroy();
this.cursorObj = null;
}
}

View File

@ -11,6 +11,7 @@ import BallUiHandler from './ball-ui-handler';
import SummaryUiHandler from './summary-ui-handler';
import StarterSelectUiHandler from './starter-select-ui-handler';
import EvolutionSceneHandler from './evolution-scene-handler';
import BiomeSelectUiHandler from './biome-select-ui-handler';
export enum Mode {
MESSAGE = 0,
@ -21,6 +22,7 @@ export enum Mode {
PARTY,
CONFIRM,
SUMMARY,
BIOME_SELECT,
STARTER_SELECT,
EVOLUTION_SCENE
};
@ -56,6 +58,7 @@ export default class UI extends Phaser.GameObjects.Container {
new PartyUiHandler(scene),
new ConfirmUiHandler(scene),
new SummaryUiHandler(scene),
new BiomeSelectUiHandler(scene),
new StarterSelectUiHandler(scene),
new EvolutionSceneHandler(scene)
];