Add WiP features related to forms and save data

This commit is contained in:
Flashfyre committed 2023-04-17 22:44:41 -04:00
1 parent bcafa47673
commit 00ad27247c
274 files changed
+1507 -440761

No files matched your search

+6
View File
@@ -91,6 +91,12 @@ export class Arena {
return Biome[this.biomeType].toLowerCase();
}
getFormIndex(species: PokemonSpecies) {
if (!species.canChangeForm && species.forms?.length)
return Utils.randInt(species.forms.length); // TODO: Base on biome
return 0;
}
trySetWeather(weather: WeatherType, viaMove: boolean): boolean {
if (this.weather?.weatherType === (weather || null))
return false;
+22 -77
View File
@@ -1,6 +1,7 @@
import BattleScene from "./battle-scene";
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult } from "./pokemon";
import { applyMoveAttrs, BypassSleepAttr, ChargeAttr, ConditionalMoveAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveHitEffectAttr, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr } from "./move";
import * as Utils from './utils';
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, ConditionalMoveAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr } from "./move";
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./pokemon-stat";
@@ -20,9 +21,8 @@ import PokemonSpecies from "./pokemon-species";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { BattleTagLapseType, BattleTagType, HideSpriteTag as HiddenTag } from "./battle-tag";
import { getPokemonMessage } from "./messages";
import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, getWeatherLapseMessage as getWeatherEffectMessage } from "./weather";
import { Moves, allMoves } from "./move";
import * as Utils from './utils';
import { Starter } from "./ui/starter-select-ui-handler";
import { Gender } from "./gender";
export class SelectStarterPhase extends BattlePhase {
constructor(scene: BattleScene) {
@@ -34,14 +34,17 @@ export class SelectStarterPhase extends BattlePhase {
this.scene.sound.play('menu', { loop: true });
this.scene.ui.setMode(Mode.STARTER_SELECT, (starterSpecies: PokemonSpecies[]) => {
this.scene.ui.setMode(Mode.STARTER_SELECT, (starters: Starter[]) => {
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());
for (let starter of starters) {
const starterGender = starter.species.malePercent !== null
? !starter.female ? Gender.MALE : Gender.FEMALE
: Gender.GENDERLESS;
const starterPokemon = new PlayerPokemon(this.scene, starter.species, 5, starter.formIndex, starterGender, starter.shiny);
starterPokemon.setVisible(false);
party.push(starterPokemon);
loadPokemonAssets.push(starterPokemon.loadAssets());
}
Promise.all(loadPokemonAssets).then(() => {
this.scene.ui.clearText();
@@ -205,8 +208,7 @@ export class SwitchBiomePhase extends BattlePhase {
onComplete: () => {
this.scene.arenaEnemy.setX(this.scene.arenaEnemy.x - 600);
this.scene.newArena(this.nextBiome)
.trySetWeather(getRandomWeatherType(this.nextBiome), false);
this.scene.newArena(this.nextBiome);
const biomeKey = this.scene.arena.getBiomeKey();
const bgTexture = `${biomeKey}_bg`;
@@ -396,13 +398,9 @@ export class CheckSwitchPhase extends BattlePhase {
this.scene.ui.showText('Will you switch\nPOKéMON?', null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.unshiftPhase(new SwitchPhase(this.scene, false, true));
this.end();
}, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.end();
});
}, () => this.end());
});
}
}
@@ -450,12 +448,10 @@ export class CommandPhase extends BattlePhase {
let isDelayed = (command: Command, playerMove: PokemonMove, enemyMove: PokemonMove) => {
switch (command) {
case Command.FIGHT:
if (playerMove && enemyMove) {
const playerMovePriority = playerMove.getMove().priority;
const enemyMovePriority = enemyMove.getMove().priority;
if (playerMovePriority !== enemyMovePriority)
return playerMovePriority < enemyMovePriority;
}
const playerMovePriority = playerMove.getMove().priority;
const enemyMovePriority = enemyMove.getMove().priority;
if (playerMovePriority !== enemyMovePriority)
return playerMovePriority < enemyMovePriority;
break;
case Command.BALL:
case Command.POKEMON:
@@ -495,9 +491,6 @@ export class CommandPhase extends BattlePhase {
}
if (success) {
if (this.scene.arena.weather)
this.scene.unshiftPhase(new WeatherEffectPhase(this.scene, this.scene.arena.weather, isDelayed(command, null, null)));
const enemyMove = enemyPokemon.getNextMove();
const enemyPhase = new EnemyMovePhase(this.scene, enemyPokemon, enemyMove);
if (isDelayed(command, playerMove, enemyMove))
@@ -546,9 +539,6 @@ export class TurnEndPhase extends BattlePhase {
playerPokemon.battleSummonData.turnCount++;
enemyPokemon.battleSummonData.turnCount++;
if (this.scene.arena.weather && !this.scene.arena.weather.lapse())
this.scene.arena.trySetWeather(WeatherType.NONE, false);
this.end();
}
}
@@ -643,8 +633,6 @@ export abstract class MovePhase extends BattlePhase {
const failed = new Utils.BooleanHolder(false);
applyMoveAttrs(ConditionalMoveAttr, this.pokemon, target, this.move.getMove(), failed);
if (!failed.value && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
failed.value = true;
if (failed.value)
this.scene.unshiftPhase(new MessagePhase(this.scene, 'But it failed!'));
else
@@ -806,12 +794,6 @@ abstract class MoveEffectPhase extends PokemonPhase {
if (!this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length)
return false;
}
const moveAccuracy = new Utils.NumberHolder(this.move.getMove().accuracy);
applyMoveAttrs(VariableAccuracyAttr, this.getUserPokemon(), this.getTargetPokemon(), this.move.getMove(), moveAccuracy);
if (moveAccuracy.value === -1)
return true;
if (this.move.getMove().category !== MoveCategory.STATUS) {
const userAccuracyLevel = this.getUserPokemon().summonData.battleStats[BattleStat.ACC];
@@ -823,9 +805,8 @@ abstract class MoveEffectPhase extends PokemonPhase {
? (3 + Math.min(userAccuracyLevel - targetEvasionLevel, 6)) / 3
: 3 / (3 + Math.min(targetEvasionLevel - userAccuracyLevel, 6));
}
return rand <= moveAccuracy.value * accuracyMultiplier;
return rand <= this.move.getMove().accuracy * accuracyMultiplier;
}
return true;
}
@@ -1067,41 +1048,8 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
}
}
export class WeatherEffectPhase extends CommonAnimPhase {
private weather: Weather;
private playerDelayed: boolean;
export class WeatherPhase extends BattlePhase {
constructor(scene: BattleScene, weather: Weather, playerDelayed: boolean) {
super(scene, true, CommonAnim.SUNNY + (weather.weatherType - 1));
this.weather = weather;
this.playerDelayed = playerDelayed;
}
start() {
if (this.weather.isDamaging()) {
const inflictDamage = (pokemon: Pokemon) => {
this.scene.unshiftPhase(new MessagePhase(this.scene, getWeatherDamageMessage(this.weather.weatherType, pokemon)));
pokemon.damage(Math.ceil(pokemon.getMaxHp() / 16));
this.scene.unshiftPhase(new DamagePhase(this.scene, pokemon.isPlayer()));
};
const playerPokemon = this.scene.getPlayerPokemon();
const enemyPokemon = this.scene.getEnemyPokemon();
const playerImmune = !!playerPokemon.getTypes().filter(t => this.weather.isTypeDamageImmune(t)).length;
const enemyImmune = !!playerPokemon.getTypes().filter(t => this.weather.isTypeDamageImmune(t)).length;
if (!this.playerDelayed && !playerImmune)
inflictDamage(playerPokemon);
if (!enemyImmune)
inflictDamage(enemyPokemon);
if (this.playerDelayed && !playerImmune)
inflictDamage(playerPokemon);
}
this.scene.ui.showText(getWeatherEffectMessage(this.weather.weatherType), null, () => super.start());
}
}
export class MessagePhase extends BattlePhase {
@@ -1120,10 +1068,7 @@ export class MessagePhase extends BattlePhase {
start() {
super.start();
if (this.text)
this.scene.ui.showText(this.text, null, () => this.end(), this.callbackDelay || (this.prompt ? 0 : 1500), this.prompt);
else
this.end();
this.scene.ui.showText(this.text, null, () => this.end(), this.callbackDelay || (this.prompt ? 0 : 1500), this.prompt);
}
}
+23 -6
View File
@@ -14,6 +14,8 @@ import { initCommonAnims, loadCommonAnimAssets, populateAnims } from './battle-a
import { BattlePhase } from './battle-phase';
import { initGameSpeed } from './game-speed';
import { Arena } from './arena';
import { SaveData } from './data';
import StarterSelectUiHandler from './ui/starter-select-ui-handler';
const enableAuto = true;
@@ -24,6 +26,9 @@ export enum Button {
RIGHT,
ACTION,
CANCEL,
CYCLE_SHINY,
CYCLE_FORM,
CYCLE_GENDER,
QUICK_START,
RANDOM,
AUTO,
@@ -36,6 +41,8 @@ export default class BattleScene extends Phaser.Scene {
public gameSpeed: integer = 1;
public quickStart: boolean;
public saveData: SaveData;
private phaseQueue: BattlePhase[];
private phaseQueuePrepend: BattlePhase[];
private currentPhase: BattlePhase;
@@ -66,12 +73,11 @@ export default class BattleScene extends Phaser.Scene {
private blockInput: boolean;
public trainerId: integer = Utils.randInt(65536);
public secretId: integer = Utils.randInt(65536);
constructor() {
super('battle');
this.saveData = new SaveData(this);
this.phaseQueue = [];
this.phaseQueuePrepend = [];
}
@@ -307,7 +313,7 @@ export default class BattleScene extends Phaser.Scene {
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);
const playerPokemon = new PlayerPokemon(this, playerSpecies, 5, 0);
playerPokemon.setVisible(false);
loadPokemonAssets.push(playerPokemon.loadAssets());
@@ -365,6 +371,9 @@ 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.CYCLE_SHINY]: [keyCodes.R],
[Button.CYCLE_FORM]: [keyCodes.F],
[Button.CYCLE_GENDER]: [keyCodes.G],
[Button.QUICK_START]: [keyCodes.Q],
[Button.RANDOM]: [keyCodes.R],
[Button.AUTO]: [keyCodes.F2],
@@ -443,6 +452,16 @@ export default class BattleScene extends Phaser.Scene {
this.ui.processInput(Button.ACTION);
else if (this.isButtonPressed(Button.CANCEL))
this.ui.processInput(Button.CANCEL);
else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
if (this.isButtonPressed(Button.CYCLE_SHINY))
this.ui.processInput(Button.CYCLE_SHINY);
else if (this.isButtonPressed(Button.CYCLE_FORM))
this.ui.processInput(Button.CYCLE_FORM);
else if (this.isButtonPressed(Button.CYCLE_GENDER))
this.ui.processInput(Button.CYCLE_GENDER);
else
return;
}
else if (this.isButtonPressed(Button.SPEED_UP)) {
if (!this.auto) {
if (this.gameSpeed < 2)
@@ -581,8 +600,6 @@ export default class BattleScene extends Phaser.Scene {
});
}
updateModifiers(): Promise<void> {
return new Promise(resolve => {
for (let modifier of this.modifiers) {
+26 -25
View File
@@ -1,4 +1,5 @@
import { pokemonEvolutions, SpeciesEvolution } from "./pokemon-evolutions";
import { allSpecies } from "./pokemon-species";
import { Species } from "./species";
import { Type } from './type';
import * as Utils from './utils';
@@ -233,13 +234,13 @@ export const biomePools: BiomePools = {
{ 1: [ Species.STUNKY ], 34: [ Species.SKUNTANK ] },
{ 1: [ Species.PATRAT ], 20: [ Species.WATCHOG ] },
{ 1: [ Species.LILLIPUP ], 16: [ Species.HERDIER ], 32: [ Species.STOUTLAND ] },
Species.TRUBBISH
{ 1: [ Species.TRUBBISH ], 36: [ Species.GARBODOR ] }
],
[BiomePoolTier.UNCOMMON]: [ Species.GARBODOR ],
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BURMY ], 20: [ Species.WORMADAM ] } ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [ Species.EEVEE, Species.SMEARGLE ],
[BiomePoolTier.ULTRA_RARE]: [ Species.DITTO, Species.CASTFORM ],
[BiomePoolTier.BOSS]: [ Species.MUK, Species.WEEZING, Species.SKUNTANK, Species.WATCHOG, Species.STOUTLAND, Species.GARBODOR ],
[BiomePoolTier.BOSS]: [ Species.MUK, Species.WEEZING, Species.WORMADAM, Species.SKUNTANK, Species.WATCHOG, Species.STOUTLAND, Species.GARBODOR ],
[BiomePoolTier.BOSS_RARE]: [ Species.CASTFORM ],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
@@ -386,11 +387,11 @@ export const biomePools: BiomePools = {
{ 1: [ Species.DWEBBLE ], 34: [ Species.CRUSTLE ] },
{ 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] }
],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BURMY ], 20: [ Species.WORMADAM ] } ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [ Species.KELDEO ],
[BiomePoolTier.BOSS]: [ Species.CLOYSTER, Species.KINGLER, Species.STARMIE, Species.CRAWDAUNT, Species.CRUSTLE, Species.CARRACOSTA ],
[BiomePoolTier.BOSS]: [ Species.CLOYSTER, Species.KINGLER, Species.STARMIE, Species.CRAWDAUNT, Species.WORMADAM, Species.CRUSTLE, Species.CARRACOSTA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.KELDEO ],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
@@ -416,7 +417,7 @@ export const biomePools: BiomePools = {
[Biome.SEABED]: {
[BiomePoolTier.COMMON]: [ { 1: [ Species.CHINCHOU ], 27: [ Species.LANTURN ] }, Species.REMORAID, Species.CLAMPERL, Species.BASCULIN, { 1: [ Species.FRILLISH ], 40: [ Species.JELLICENT ] } ],
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.TENTACOOL ], 30: [ Species.TENTACRUEL ] }, Species.SHELLDER, Species.LUVDISC, { 1: [ Species.SHELLOS ], 30: [ Species.GASTRODON ] } ],
[BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, Species.MANTINE, Species.MANTYKE, Species.PHIONE, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] } ],
[BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.PHIONE, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] } ],
[BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.OMANYTE ], 40: [ Species.OMASTAR ] }, { 1: [ Species.KABUTO ], 40: [ Species.KABUTOPS ] }, Species.RELICANTH ],
[BiomePoolTier.ULTRA_RARE]: [ Species.FEEBAS, Species.MANAPHY ],
[BiomePoolTier.BOSS]: [ Species.LANTURN, Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, Species.MANTINE, Species.HUNTAIL, Species.GOREBYSS, Species.LUVDISC, Species.JELLICENT, Species.ALOMOMOLA ],
@@ -438,19 +439,13 @@ export const biomePools: BiomePools = {
{ 1: [ Species.GEODUDE ], 25: [ Species.GRAVELER ] },
{ 1: [ Species.RHYHORN ], 42: [ Species.RHYDON ] },
{ 1: [ Species.NATU ], 25: [ Species.XATU ] },
{ 1: [ Species.SLUGMA ], 38: [ Species.MAGCARGO ] },
{ 1: [ Species.ARON ], 32: [ Species.LAIRON ], 42: [ Species.AGGRON ] },
{ 1: [ Species.ROGGENROLA ], 25: [ Species.BOLDORE ] },
{ 1: [ Species.RUFFLET ], 54: [ Species.BRAVIARY ] },
Species.MANDIBUZZ
],
[BiomePoolTier.RARE]: [
Species.MURKROW,
{ 1: [ Species.SLUGMA ], 38: [ Species.MAGCARGO ] },
Species.SKARMORY,
{ 1: [ Species.TORCHIC ], 16: [ Species.COMBUSKEN ], 36: [ Species.BLAZIKEN ] },
{ 1: [ Species.SPOINK ], 32: [ Species.GRUMPIG ] },
Species.VULLABY
],
[BiomePoolTier.RARE]: [ Species.MURKROW, Species.SKARMORY, { 1: [ Species.TORCHIC ], 16: [ Species.COMBUSKEN ], 36: [ Species.BLAZIKEN ] }, { 1: [ Species.SPOINK ], 32: [ Species.GRUMPIG ] }, Species.VULLABY ],
[BiomePoolTier.SUPER_RARE]: [
{ 1: [ Species.LARVITAR ], 30: [ Species.PUPITAR ] },
{ 1: [ Species.CRANIDOS ], 30: [ Species.RAMPARDOS ] },
@@ -458,10 +453,10 @@ export const biomePools: BiomePools = {
{ 1: [ Species.GIBLE ], 24: [ Species.GABITE ], 48: [ Species.GARCHOMP ] },
{ 1: [ Species.AXEW ], 38: [ Species.FRAXURE ] }
],
[BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL, Species.TORNADUS ],
[BiomePoolTier.ULTRA_RARE]: [ Species.TORNADUS ],
[BiomePoolTier.BOSS]: [ Species.PIDGEOT, Species.FEAROW, Species.SKARMORY, Species.SWELLOW, Species.AGGRON, Species.STARAPTOR, Species.UNFEZANT, Species.BRAVIARY, Species.MANDIBUZZ ],
[BiomePoolTier.BOSS_RARE]: [ Species.BLAZIKEN, Species.RAMPARDOS, Species.BASTIODON ],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.TORNADUS ],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.TORNADUS ],
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.HO_OH, Species.RAYQUAZA ]
},
[Biome.LAND]: {
@@ -495,10 +490,10 @@ export const biomePools: BiomePools = {
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.GEODUDE ], 25: [ Species.GRAVELER ] }, { 1: [ Species.MAKUHITA ], 24: [ Species.HARIYAMA ] }, Species.NOSEPASS ],
[BiomePoolTier.RARE]: [ Species.ONIX ],
[BiomePoolTier.SUPER_RARE]: [ Species.SHUCKLE ],
[BiomePoolTier.ULTRA_RARE]: [ Species.UXIE, Species.COBALION ],
[BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL, Species.UXIE, Species.COBALION ],
[BiomePoolTier.BOSS]: [ Species.PARASECT, Species.ONIX, Species.CROBAT, Species.URSARING, Species.EXPLOUD, Species.MAWILE, Species.PROBOPASS, Species.GIGALITH, Species.SWOOBAT ],
[BiomePoolTier.BOSS_RARE]: [ Species.SHUCKLE ],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.UXIE ],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.UXIE ],
[BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.MEWTWO, Species.COBALION ]
},
[Biome.DESERT]: {
@@ -2633,12 +2628,18 @@ export const biomePools: BiomePools = {
]
],
[ Species.BURMY, Type.BUG, -1, [
[ Biome.FOREST, BiomePoolTier.UNCOMMON ]
[ Biome.CITY, BiomePoolTier.UNCOMMON ],
[ Biome.FOREST, BiomePoolTier.UNCOMMON ],
[ Biome.BEACH, BiomePoolTier.UNCOMMON ]
]
],
[ Species.WORMADAM, Type.BUG, Type.GRASS, [
[ Biome.CITY, BiomePoolTier.UNCOMMON ],
[ Biome.CITY, BiomePoolTier.BOSS ],
[ Biome.FOREST, BiomePoolTier.UNCOMMON ],
[ Biome.FOREST, BiomePoolTier.BOSS ]
[ Biome.FOREST, BiomePoolTier.BOSS ],
[ Biome.BEACH, BiomePoolTier.UNCOMMON ],
[ Biome.BEACH, BiomePoolTier.BOSS ]
]
],
[ Species.MOTHIM, Type.BUG, Type.FLYING, [
@@ -3364,7 +3365,7 @@ export const biomePools: BiomePools = {
]
],
[ Species.GARBODOR, Type.POISON, -1, [
[ Biome.CITY, BiomePoolTier.UNCOMMON ],
[ Biome.CITY, BiomePoolTier.COMMON ],
[ Biome.CITY, BiomePoolTier.BOSS ]
]
],
@@ -3850,7 +3851,7 @@ export const biomePools: BiomePools = {
}
}
console.log(beautify(output, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, '$1Species.$2').replace(/"(\d+)": /g, '$1: ').replace(/( )"(.*?)"/g, '$1[PoolTier.$2]').replace(/( )"(.*?)"/g, '$1[Biome.$2]'));
console.log(beautify(output, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, '$1Species.$2').replace(/"(\d+)": /g, '$1: ').replace(/( )"(.*?)"/g, '$1[BiomePoolTier.$2]').replace(/( )"(.*?)"/g, '$1[Biome.$2]'));
}
outputPools();
@@ -3868,15 +3869,15 @@ export const biomePools: BiomePools = {
for (let t of Object.keys(biomePools[b])) {
for (let p = 0; p < biomePools[b][t].length; p++) {
if (biomePools[b][t][p] === pokemon.speciesId) {
poolTier = parseInt(t) as PoolTier;
poolTier = parseInt(t) as BiomePoolTier;
break;
}
}
}
if (poolTier > -1)
pokemonBiomes[pokemon.speciesId - 1][3].push([ Biome[b], PoolTier[poolTier] ]);
pokemonBiomes[pokemon.speciesId - 1][3].push([ Biome[b], BiomePoolTier[BiomePoolTier] ]);
} else if (biomePoolPredicates[b](pokemon)) {
pokemonBiomes[pokemon.speciesId - 1][3].push([ Biome[b], PoolTier[PoolTier.COMMON] ]);
pokemonBiomes[pokemon.speciesId - 1][3].push([ Biome[b], BiomePoolTier[BiomePoolTier.COMMON] ]);
}
}
}
+239
View File
@@ -0,0 +1,239 @@
import BattleScene from "./battle-scene";
import { Gender } from "./gender";
import PokemonSpecies, { allSpecies } from "./pokemon-species";
import { Species } from "./species";
import * as Utils from "./utils";
export interface DexData {
[key: integer]: DexData | DexEntry
}
export interface DexEntry {
seen: boolean;
caught: boolean;
}
export interface StarterDexEntry {
shiny: boolean;
formIndex: integer;
female: boolean;
entry: DexEntry;
}
export interface StarterDexUnlockTree {
shiny: boolean | Map<boolean, StarterDexUnlockTree>
formIndex: integer | Map<integer, StarterDexUnlockTree>
female: boolean | Map<boolean, StarterDexUnlockTree>
key: string,
entry: DexEntry
}
export class SaveData {
private scene: BattleScene;
public trainerId: integer;
public secretId: integer;
public dexData: DexData;
constructor(scene: BattleScene) {
this.scene = scene;
this.trainerId = Utils.randInt(65536);
this.secretId = Utils.randInt(65536)
this.initDexData();
}
save() {
}
load() {
}
initDexData() {
const data: DexData = {};
const initDexSubData = (dexData: DexData, count: integer): DexData[] => {
const ret: DexData[] = [];
for (let i = 0; i < count; i++) {
const newData: DexData = {};
dexData[i] = newData;
ret.push(newData);
}
return ret;
};
const initDexEntries = (dexData: DexData, count: integer): DexEntry[] => {
const ret: DexEntry[] = [];
for (let i = 0; i < count; i++) {
const entry: DexEntry = { seen: true, caught: true };
dexData[i] = entry;
ret.push(entry);
}
return ret;
};
for (let species of allSpecies) {
data[species.speciesId] = {};
if (species.forms?.length)
initDexSubData(data[species.speciesId] as DexData, 2).map(sd => species.malePercent !== null ? initDexSubData(sd, species.forms.length).map(fd => initDexEntries(fd, 2)) : initDexEntries(sd, species.forms.length));
else if (species.malePercent !== null)
initDexSubData(data[species.speciesId] as DexData, 2).map(sd => initDexEntries(sd, 2));
else
initDexEntries(data[species.speciesId] as DexData, 2)
}
const defaultStarters: Species[] = [
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE,
Species.TREECKO, Species.TORCHIC, Species.MUDKIP,
Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP,
Species.SNIVY, Species.TEPIG, Species.OSHAWOTT
];
for (let ds of defaultStarters) {
let entry = data[ds][0][Gender.MALE] as DexEntry;
entry.seen = true;
entry.caught = true;
entry = data[ds][0][Gender.FEMALE] as DexEntry;
entry.seen = true;
entry.caught = true;
entry = data[ds][1][Gender.FEMALE] as DexEntry;
entry.seen = true;
entry.caught = true;
}
this.dexData = data;
}
getDexEntry(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean) : DexEntry {
const shinyIndex = !shiny ? 0 : 1;
const genderIndex = !female ? 0 : 1;
const data = this.dexData[species.speciesId];
if (species.forms?.length) {
if (species.malePercent !== null)
return data[shinyIndex][formIndex][genderIndex];
return data[shinyIndex][formIndex];
} else if (species.malePercent !== null)
return data[shinyIndex][genderIndex];
return data[shinyIndex] as DexEntry;
}
getDefaultStarterDexEntry(species: PokemonSpecies, forceShiny?: boolean, forceFormIndex?: integer, forceFemale?: boolean): StarterDexEntry {
const hasForms = !!species.forms?.length;
let shiny = false;
let formIndex = 0;
let female = false;
let entry = null;
const traverseData = (data: DexData, level: integer) => {
const keys = Object.keys(data);
keys.forEach((key: string, k: integer) => {
if (entry)
return;
switch (level) {
case 0:
shiny = !!k;
if (forceShiny !== undefined && shiny !== forceShiny)
return;
break;
case 1:
formIndex = k;
if (forceFormIndex !== undefined && formIndex !== forceFormIndex)
return;
break;
case 2:
female = !!k;
if (forceFemale !== undefined && female !== forceFemale)
return
break;
}
if ('caught' in data[key]) {
if (data[key].caught)
entry = data[key] as DexEntry;
} else
traverseData(data[key] as DexData, level + (hasForms ? 1 : 2));
});
};
traverseData(this.dexData[species.speciesId] as DexData, 0);
if (entry) {
return {
shiny: shiny,
formIndex: formIndex,
female: female,
entry: entry
};
}
return null;
}
getStarterDexUnlockTree(species: PokemonSpecies): StarterDexUnlockTree {
const hasForms = !!species.forms?.length;
const hasGender = species.malePercent !== null;
const getTreeOrValueMap = (key: string, parent?: StarterDexUnlockTree): (Map<any, any>) => {
switch (key) {
case 'shiny':
const shinyMap = new Map<boolean, StarterDexUnlockTree>();
for (let s = 0; s < 2; s++) {
const props = { shiny: !!s, formIndex: null };
shinyMap.set(!!s, {
shiny: !!s,
formIndex: hasForms ? getTreeOrValueMap('formIndex', props as StarterDexUnlockTree) : null,
female: !hasForms && hasGender ? getTreeOrValueMap('female', props as StarterDexUnlockTree) : null,
key: hasForms ? 'formIndex' : hasGender ? 'female' : 'entry',
entry: hasForms || hasGender ? null : this.dexData[species.speciesId][!s ? 0 : 1]
});
}
return shinyMap;
case 'formIndex':
const formMap = new Map<integer, StarterDexUnlockTree>();
for (let f = 0; f < species.forms.length; f++) {
const props = { shiny: parent.shiny, formIndex: f };
formMap.set(f, {
shiny: parent.shiny,
formIndex: f,
female: hasGender ? getTreeOrValueMap('female', props as StarterDexUnlockTree) : null,
key: hasGender ? 'female' : 'entry',
entry: hasGender ? null : this.dexData[species.speciesId][!parent.shiny ? 0 : 1][f]
});
}
return formMap;
case 'female':
const genderMap = new Map<boolean, StarterDexUnlockTree>();
for (let g = 0; g < 2; g++) {
genderMap.set(!!g, {
shiny: parent.shiny,
formIndex: parent.formIndex,
female: !!g,
key: 'entry',
entry: hasForms
? this.dexData[species.speciesId][!parent.shiny ? 0 : 1][parent.formIndex as integer][g]
: this.dexData[species.speciesId][!parent.shiny ? 0 : 1][g]
});
}
return genderMap;
}
};
const root = {
shiny: getTreeOrValueMap('shiny'),
formIndex: null,
female: null,
key: 'shiny',
entry: null
};
return root;
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
export enum Gender {
GENDERLESS = -1,
FEMALE,
MALE
MALE,
FEMALE
}
export function getGenderSymbol(gender: Gender) {
+1 -1
View File
@@ -199,7 +199,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier {
const pokemon = this.getPokemon(scene);
const pokemonIcon = scene.add.sprite(0, 8, pokemon.species.getIconAtlasKey());
pokemonIcon.play(pokemon.species.getIconKey()).stop();
pokemonIcon.play(pokemon.getIconKey()).stop();
pokemonIcon.setOrigin(0, 0.5);
container.add(pokemonIcon);
+935 -888
View File
File diff suppressed because it is too large. Load diff
+66 -52
View File
@@ -3,7 +3,7 @@ import BattleScene from './battle-scene';
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './battle-info';
import Move, { StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, Moves, allMoves, MoveCategory } from "./move";
import { pokemonLevelMoves } from './pokemon-level-moves';
import { default as PokemonSpecies, getPokemonSpecies } from './pokemon-species';
import { default as PokemonSpecies, PokemonSpeciesForm, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils';
import { Type, getTypeDamageMultiplier } from './type';
import { getLevelTotalExp } from './exp';
@@ -25,6 +25,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public id: integer;
public name: string;
public species: PokemonSpecies;
public formIndex: integer;
public shiny: boolean;
public pokeball: PokeballType;
protected battleInfo: BattleInfo;
@@ -48,7 +49,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
private shinySparkle: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, dataSource?: Pokemon) {
constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, dataSource?: Pokemon) {
super(scene, x, y);
this.name = Utils.toPokemonUpperCase(species.name);
this.species = species;
@@ -56,13 +57,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
? new PlayerBattleInfo(scene)
: new EnemyBattleInfo(scene);
this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL;
this.level = level;//Utils.randInt(player ? 100 : 30, player ? 41 : 1);
this.level = level;
this.formIndex = formIndex || 0;
if (gender !== undefined)
this.gender = gender;
if (shiny !== undefined)
this.shiny = shiny;
this.exp = dataSource?.exp || getLevelTotalExp(this.level, species.growthRate);
this.levelExp = dataSource?.levelExp || 0;
if (dataSource) {
this.id = dataSource.id;
this.shiny = dataSource.shiny;
this.gender = dataSource.gender;
this.hp = dataSource.hp;
this.stats = dataSource.stats;
this.ivs = dataSource.ivs;
@@ -81,36 +85,40 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
Utils.binToDec(Utils.decToBin(this.id).substring(20, 25)),
Utils.binToDec(Utils.decToBin(this.id).substring(25, 30))
];
//} else
//this.id = parseInt(Utils.decToBin(this.ivs[Stat.HP]) + Utils.decToBin(this.ivs[Stat.ATK]) + Utils.decToBin(this.ivs[Stat.DEF]) + Utils.decToBin(this.ivs[Stat.SPATK]) + Utils.decToBin(this.ivs[Stat.SPDEF]) + Utils.decToBin(this.ivs[Stat.SPD]) + this.id.toString(2).slice(30));
//} else
//this.id = parseInt(Utils.decToBin(this.ivs[Stat.HP]) + Utils.decToBin(this.ivs[Stat.ATK]) + Utils.decToBin(this.ivs[Stat.DEF]) + Utils.decToBin(this.ivs[Stat.SPATK]) + Utils.decToBin(this.ivs[Stat.SPDEF]) + Utils.decToBin(this.ivs[Stat.SPD]) + this.id.toString(2).slice(30));
if (this.species.malePercent === null)
this.gender = Gender.GENDERLESS;
else {
const genderChance = (this.id % 256) * 0.390625;
if (genderChance < this.species.malePercent)
this.gender = Gender.MALE;
else
this.gender = Gender.FEMALE;
if (this.gender === undefined) {
if (this.getSpeciesForm().malePercent === null)
this.gender = Gender.GENDERLESS;
else {
const genderChance = (this.id % 256) * 0.390625;
if (genderChance < this.getSpeciesForm().malePercent)
this.gender = Gender.MALE;
else
this.gender = Gender.FEMALE;
}
}
const rand1 = Utils.binToDec(Utils.decToBin(this.id).substring(0, 16));
const rand2 = Utils.binToDec(Utils.decToBin(this.id).substring(16, 32));
const E = this.scene.trainerId ^ this.scene.secretId;
const E = this.scene.saveData.trainerId ^ this.scene.saveData.secretId;
const F = rand1 ^ rand2;
let shinyThreshold = new Utils.IntegerHolder(32);
this.scene.applyModifiers(ShinyRateBoosterModifier, shinyThreshold);
console.log(shinyThreshold.value);
if (this.shiny === undefined) {
let shinyThreshold = new Utils.IntegerHolder(32);
this.scene.applyModifiers(ShinyRateBoosterModifier, shinyThreshold);
console.log(shinyThreshold.value);
this.shiny = (E ^ F) < shinyThreshold.value;
if ((E ^ F) < 32)
console.log('REAL SHINY!!');
if (this.shiny)
console.log((E ^ F), shinyThreshold.value);
/*else
this.shiny = Utils.randInt(16) === 0;*/
this.shiny = (E ^ F) < shinyThreshold.value;
if ((E ^ F) < 32)
console.log('REAL SHINY!!');
if (this.shiny)
console.log((E ^ F), shinyThreshold.value);
/*else
this.shiny = Utils.randInt(16) === 0;*/
}
this.winCount = 0;
}
@@ -166,7 +174,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
Promise.allSettled(moveIds.map(m => initMoveAnim(m)))
.then(() => {
loadMoveAnimAssets(this.scene, moveIds);
this.species.loadAssets(this.scene, this.gender === Gender.FEMALE, this.shiny);
this.getSpeciesForm().loadAssets(this.scene, this.gender === Gender.FEMALE, this.formIndex, this.shiny);
if (this.isPlayer())
this.scene.loadAtlas(this.getBattleSpriteKey(), 'pokemon', this.getBattleSpriteAtlasPath());
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
@@ -203,7 +211,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getSpriteId(): string {
return this.species.getSpriteId(this.gender === Gender.FEMALE, this.shiny);
return this.getSpeciesForm().getSpriteId(this.gender === Gender.FEMALE, this.formIndex, this.shiny);
}
getBattleSpriteId(): string {
@@ -211,7 +219,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getSpriteKey(): string {
return this.species.getSpriteKey(this.gender === Gender.FEMALE, this.shiny);
return this.getSpeciesForm().getSpriteKey(this.gender === Gender.FEMALE, this.formIndex, this.shiny);
}
getBattleSpriteKey(): string {
@@ -219,14 +227,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getIconId(): string {
// TODO: Add form special cases
return this.species.getIconId();
return this.getSpeciesForm().getIconId(this.gender === Gender.FEMALE, this.formIndex);
}
getIconKey(): string {
return `pkmn_icon__${this.getIconId()}`;
}
getSpeciesForm(): PokemonSpeciesForm {
if (!this.species.forms?.length)
return this.species;
return this.species.forms[this.formIndex];
}
getSprite(): Phaser.GameObjects.Sprite {
return this.getAt(0) as Phaser.GameObjects.Sprite;
}
@@ -262,8 +275,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
calculateStats(): void {
if (!this.stats)
this.stats = [ 0, 0, 0, 0, 0, 0 ];
const baseStats = this.species.baseStats.slice(0);
console.log(this.id);
const baseStats = this.getSpeciesForm().baseStats.slice(0);
this.scene.applyModifiers(PokemonBaseStatBoosterModifier, this, baseStats);
const stats = Utils.getEnumValues(Stat);
for (let s of stats) {
@@ -298,9 +310,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
getTypes(): Type[] {
const speciesTypes = [ this.species.type1 ];
if (this.species.type2 > -1)
speciesTypes.push(this.species.type1);
const speciesForm = this.getSpeciesForm();
const speciesTypes = [ speciesForm.type1 ];
if (speciesForm.type2 !== null)
speciesTypes.push(speciesForm.type1);
if (this.getTag(BattleTagType.IGNORE_FLYING)) {
const flyingIndex = speciesTypes.indexOf(Type.FLYING);
@@ -425,9 +438,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
addExp(exp: integer) {
this.exp += exp;
while (this.exp >= getLevelTotalExp(this.level + 1, this.species.growthRate))
while (this.exp >= getLevelTotalExp(this.level + 1, this.getSpeciesForm().growthRate))
this.level++;
this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate);
this.levelExp = this.exp - getLevelTotalExp(this.level, this.getSpeciesForm().growthRate);
}
apply(source: Pokemon, battlerMove: PokemonMove): MoveResult {
@@ -440,7 +453,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
case MoveCategory.SPECIAL:
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
const power = new Utils.NumberHolder(move.power);
const typeMultiplier = getTypeDamageMultiplier(move.type, this.species.type1) * (this.species.type2 > -1 ? getTypeDamageMultiplier(move.type, this.species.type2) : 1);
const typeMultiplier = getTypeDamageMultiplier(move.type, this.getSpeciesForm().type1) * (this.getSpeciesForm().type2 !== null ? getTypeDamageMultiplier(move.type, this.getSpeciesForm().type2) : 1);
const weatherTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(move.type);
applyMoveAttrs(VariablePowerAttr, source, this, move, power);
this.scene.applyModifiers(AttackTypeBoosterModifier, source, power);
@@ -449,7 +462,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const isCritical = Utils.randInt(critChance.value) === 0;
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK);
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF);
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 > -1 && source.species.type2 === move.type) ? 1.5 : 1;
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 !== null && source.species.type2 === move.type) ? 1.5 : 1;
const criticalMultiplier = isCritical ? 2 : 1;
damage = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier * typeMultiplier * weatherTypeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
@@ -573,7 +586,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
cry(soundConfig?: Phaser.Types.Sound.SoundConfig): integer {
return this.species.cry(this.scene, soundConfig);
return this.getSpeciesForm().cry(this.scene, soundConfig);
}
faintCry(callback: Function) {
@@ -639,18 +652,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
trySetStatus(effect: StatusEffect): boolean {
if (this.status)
return false;
const speciesForm = this.getSpeciesForm();
switch (effect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
if (this.species.isOfType(Type.POISON) || this.species.isOfType(Type.STEEL))
if (speciesForm.isOfType(Type.POISON) || speciesForm.isOfType(Type.STEEL))
return false;
break;
case StatusEffect.FREEZE:
if (this.species.isOfType(Type.ICE))
if (speciesForm.isOfType(Type.ICE))
return false;
break;
case StatusEffect.BURN:
if (this.species.isOfType(Type.FIRE))
if (speciesForm.isOfType(Type.FIRE))
return false;
break;
}
@@ -682,7 +696,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
getExpValue(): integer {
// Logic to factor in victor level has been removed for balancing purposes, so the player doesn't have to focus on EXP maxxing
return (this.species.baseExp * this.level) / 5 + 1;
return (this.getSpeciesForm().baseExp * this.level) / 5 + 1;
}
tint(color: number, alpha?: number, duration?: integer, ease?: string) {
@@ -763,10 +777,10 @@ export default interface Pokemon {
export class PlayerPokemon extends Pokemon {
public compatibleTms: Moves[];
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, dataSource?: Pokemon) {
super(scene, 106, 148, species, level, dataSource);
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, formIndex: integer, gender: Gender, shiny: boolean, dataSource?: Pokemon) {
super(scene, 106, 148, species, level, formIndex, gender, shiny, dataSource);
this.species.generateIconAnim(scene);
this.getSpeciesForm().generateIconAnim(scene, this.gender === Gender.FEMALE, formIndex);
this.generateCompatibleTms();
}
@@ -799,7 +813,7 @@ export class PlayerPokemon extends Pokemon {
this.handleSpecialEvolutions(evolution);
this.species = getPokemonSpecies(evolution.speciesId);
this.name = this.species.name.toUpperCase();
this.species.generateIconAnim(this.scene);
this.getSpeciesForm().generateIconAnim(this.scene, this.gender === Gender.FEMALE, this.formIndex);
this.compatibleTms.splice(0, this.compatibleTms.length);
this.generateCompatibleTms();
this.loadAssets().then(() => {
@@ -813,7 +827,7 @@ export class PlayerPokemon extends Pokemon {
if (this.species.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) {
const newEvolution = pokemonEvolutions[this.species.speciesId][1];
if (newEvolution.condition.predicate(this)) {
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level);
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.formIndex, this.gender, this.shiny);
this.scene.getParty().push(newPokemon);
newPokemon.evolve(newEvolution);
}
@@ -825,7 +839,7 @@ export class EnemyPokemon extends Pokemon {
public aiType: AiType;
constructor(scene: BattleScene, species: PokemonSpecies, level: integer) {
super(scene, -66, 84, species, level);
super(scene, -66, 84, species, level, scene.arena.getFormIndex(species));
this.aiType = AiType.SMART_RANDOM;
}
@@ -921,7 +935,7 @@ export class EnemyPokemon extends Pokemon {
let ret: PlayerPokemon = null;
if (party.length < 6) {
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this);
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.formIndex, this.gender, this.shiny);
party.push(newPokemon);
ret = newPokemon;
}
+1 -2
View File
@@ -510,8 +510,7 @@ class PartySlot extends Phaser.GameObjects.Container {
this.add(slotPb);
const pokemonIcon = this.scene.add.sprite(slotPb.x, slotPb.y, this.pokemon.species.getIconAtlasKey());
console.log(pokemonIcon)
pokemonIcon.play(this.pokemon.species.getIconKey());
pokemonIcon.play(this.pokemon.getIconKey());
this.slotPokemonIcon = pokemonIcon;
this.add(pokemonIcon);
+186 -36
View File
@@ -5,8 +5,16 @@ import { TextStyle, addTextObject } from "../text";
import { Mode } from "./ui";
import * as Utils from "../utils";
import MessageUiHandler from "./message-ui-handler";
import { StarterDexEntry, StarterDexUnlockTree } from "../data";
export type StarterSelectCallback = (starterSpecies: PokemonSpecies[]) => void;
export type StarterSelectCallback = (starters: Starter[]) => void;
export interface Starter {
species: PokemonSpecies;
shiny: boolean;
formIndex: integer;
female: boolean;
}
export default class StarterSelectUiHandler extends MessageUiHandler {
private starterSelectContainer: Phaser.GameObjects.Container;
@@ -14,15 +22,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private pokemonNumberText: Phaser.GameObjects.Text;
private pokemonSprite: Phaser.GameObjects.Sprite;
private pokemonNameText: Phaser.GameObjects.Text;
private instructionsText: Phaser.GameObjects.Text;
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
private genMode: boolean;
private shinyCursor: integer = 0;
private formCursor: integer = 0;
private genderCursor: integer = 0;
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 starterDetails: [boolean, integer, boolean][] = [];
private speciesStarterDexEntry: StarterDexEntry;
private speciesStarterDexTree: StarterDexUnlockTree;
private canCycleShiny: boolean;
private canCycleForm: boolean;
private canCycleGender: boolean;
private assetLoadCancelled: Utils.BooleanHolder;
private cursorObj: Phaser.GameObjects.Image;
@@ -102,13 +121,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
continue;
this.speciesLoaded.set(species.speciesId, false);
this.genSpecies[g].push(species);
species.generateIconAnim(this.scene);
const dexEntry = this.scene.saveData.getDefaultStarterDexEntry(species);
species.generateIconAnim(this.scene, dexEntry?.female, dexEntry?.formIndex);
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();
icon.play(species.getIconKey(dexEntry?.female, dexEntry?.formIndex)).stop();
if (!dexEntry)
icon.setTintFill(0);
this.starterSelectGenIconContainers[g].add(icon);
s++;
}
@@ -133,6 +155,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
this.starterSelectContainer.add(this.pokemonSprite);
this.instructionsText = addTextObject(this.scene, 1, 132, '', TextStyle.PARTY);
this.starterSelectContainer.add(this.instructionsText);
this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6);
this.starterSelectMessageBoxContainer.setVisible(false);
this.starterSelectContainer.add(this.starterSelectMessageBoxContainer);
@@ -144,6 +169,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 });
this.message.setOrigin(0, 1);
this.starterSelectMessageBoxContainer.add(this.message);
this.updateInstructions();
}
show(args: any[]): void {
@@ -188,7 +215,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
} else {
if (button === Button.ACTION) {
if (this.starterCursors.length < 3) {
if (!this.speciesStarterDexEntry)
ui.playError();
else 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) {
@@ -201,18 +230,27 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
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.starterIcons[this.starterCursors.length].play(species.getIconKey(this.speciesStarterDexEntry?.female));
this.starterGens.push(this.genCursor);
this.starterCursors.push(this.cursor);
this.starterDetails.push([ !!this.shinyCursor, this.formCursor, !!this.genderCursor ]);
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 thisObj = this;
const originalStarterSelectCallback = this.starterSelectCallback;
this.starterSelectCallback = null;
originalStarterSelectCallback(new Array(3).fill(0).map((_, i) => this.genSpecies[this.starterGens[i]][this.starterCursors[i]]));
originalStarterSelectCallback(new Array(3).fill(0).map(function (_, i) {
return {
species: thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]],
shiny: thisObj.starterDetails[i][0],
formIndex: thisObj.starterDetails[i][1],
female: thisObj.starterDetails[i][2]
};
}));
}, () => {
ui.setMode(Mode.STARTER_SELECT);
this.popStarter();
@@ -235,6 +273,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const rows = Math.ceil(genStarters / 9);
const row = Math.floor(this.cursor / 9);
switch (button) {
case Button.CYCLE_SHINY:
if (this.canCycleShiny) {
this.setSpeciesDetails(this.lastSpecies, !this.shinyCursor, this.formCursor, !!this.genderCursor);
}
break;
case Button.CYCLE_FORM:
if (this.canCycleForm)
this.setSpeciesDetails(this.lastSpecies, !!this.shinyCursor, (this.formCursor + 1) % this.lastSpecies.forms.length, !!this.genderCursor);
break;
case Button.CYCLE_GENDER:
if (this.canCycleGender)
this.setSpeciesDetails(this.lastSpecies, !!this.shinyCursor, this.formCursor, !this.genderCursor);
break;
case Button.UP:
if (row)
success = this.setCursor(this.cursor - 9);
@@ -260,6 +311,29 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (success)
ui.playSelect();
}
updateInstructions(): void {
let instructionLines = [
'Arrow Keys/WASD: Move'
];
if (!this.genMode)
instructionLines.push('A/Space/Enter: Select');
if (this.starterCursors.length)
instructionLines.push('X/Backspace/Esc: Undo');
if (this.speciesStarterDexTree) {
if (this.canCycleShiny)
instructionLines.push('R: Cycle Shiny');
if (this.canCycleForm)
instructionLines.push('F: Cycle Form');
if (this.canCycleGender)
instructionLines.push('G: Cycle Gender');
}
if (instructionLines.length >= 4)
instructionLines[2] += ` ${instructionLines.splice(3, 1)[0]}`;
this.instructionsText.setText(instructionLines.join('\n'));
}
setCursor(cursor: integer): boolean {
let changed = false;
@@ -283,6 +357,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.cursorObj.setPosition(148 + 18 * (cursor % 9), 10 + 18 * Math.floor(cursor / 9));
this.setSpecies(this.genSpecies[this.genCursor][cursor]);
this.updateInstructions();
}
return changed;
@@ -306,45 +382,119 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
setSpecies(species: PokemonSpecies) {
this.pokemonSprite.setVisible(false);
this.speciesStarterDexEntry = species ? this.scene.saveData.getDefaultStarterDexEntry(species) : null;
this.speciesStarterDexTree = this.speciesStarterDexEntry ? this.scene.saveData.getStarterDexUnlockTree(species) : null;
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('');
if (this.lastSpecies) {
const defaultStarterDexEntry = this.scene.saveData.getDefaultStarterDexEntry(this.lastSpecies);
const lastSpeciesIcon = (this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies)) as Phaser.GameObjects.Sprite);
lastSpeciesIcon.play(this.lastSpecies.getIconKey(!!defaultStarterDexEntry?.female, defaultStarterDexEntry?.formIndex)).stop();
}
this.lastSpecies = species;
if (species && this.speciesStarterDexEntry) {
this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 3));
this.pokemonNameText.setText(species.name.toUpperCase());
this.setSpeciesDetails(species, !!this.speciesStarterDexEntry?.shiny, this.speciesStarterDexEntry?.formIndex || 0, !!this.speciesStarterDexEntry?.female);
} else {
this.pokemonNumberText.setText(Utils.padInt(0, 3));
this.pokemonNameText.setText(species ? '???' : '');
this.setSpeciesDetails(species, false, 0, false);
}
}
setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean): void {
if (shiny !== undefined)
this.shinyCursor = !shiny ? 0 : 1;
if (formIndex !== undefined)
this.formCursor = formIndex;
if (female !== undefined)
this.genderCursor = !female ? 0 : 1;
this.pokemonSprite.setVisible(false);
if (species) {
const defaultDexEntry = this.scene.saveData.getDefaultStarterDexEntry(species, shiny, formIndex, female);
const dexEntry = this.scene.saveData.getDexEntry(species, !!this.shinyCursor, this.formCursor, !!this.genderCursor);
if (!dexEntry.caught) {
if (shiny === undefined)
shiny = defaultDexEntry.shiny;
if (formIndex === undefined)
formIndex = defaultDexEntry.formIndex;
if (female === undefined)
female = defaultDexEntry.female;
} else {
shiny = !!this.shinyCursor;
formIndex = this.formCursor;
female = !!this.genderCursor;
}
if (this.assetLoadCancelled) {
this.assetLoadCancelled.value = true;
this.assetLoadCancelled = null;
}
if (this.speciesStarterDexTree) {
const assetLoadCancelled = new Utils.BooleanHolder(false);
this.assetLoadCancelled = assetLoadCancelled;
species.loadAssets(this.scene, female, formIndex, shiny, true).then(() => {
if (assetLoadCancelled.value)
return;
this.assetLoadCancelled = null;
this.speciesLoaded.set(species.speciesId, true);
this.pokemonSprite.play(species.getSpriteKey(female, formIndex, shiny));
this.pokemonSprite.setVisible(true);
});
species.generateIconAnim(this.scene, this.speciesStarterDexEntry.female, this.speciesStarterDexEntry.formIndex);
(this.starterSelectGenIconContainers[this.genCursor].getAt(this.cursor) as Phaser.GameObjects.Sprite).play(species.getIconKey(female, formIndex));
let count: integer;
const calcUnlockedCount = (tree: StarterDexUnlockTree, root?: boolean) => {
if (root)
count = 0;
if (!tree.entry) {
for (let key of tree[tree.key].keys())
calcUnlockedCount(tree[tree.key].get(key));
} else if (tree.entry.caught)
count++;
};
let tree = this.speciesStarterDexTree;
calcUnlockedCount(tree, true);
this.canCycleShiny = count > 1;
tree = (tree.shiny as Map<boolean, StarterDexUnlockTree>).get(!!this.shinyCursor);
if (this.lastSpecies.forms?.length) {
calcUnlockedCount(tree, true);
this.canCycleForm = count > 1;
tree = (tree.formIndex as Map<integer, StarterDexUnlockTree>).get(this.formCursor);
} else
this.canCycleForm = false;
if (this.lastSpecies.malePercent !== null) {
calcUnlockedCount(tree, true);
this.canCycleGender = count > 1;
} else
this.canCycleGender = false;
}
} else {
}
this.updateInstructions();
}
popStarter(): void {
this.starterGens.pop();
this.starterCursors.pop();
this.starterDetails.pop();
this.starterCursorObjs[this.starterCursors.length].setVisible(false);
this.starterIcons[this.starterCursors.length].play('pkmn_icon__000');
}