Add egg moves logic

pull/16/head
Flashfyre 2024-02-25 12:45:41 -05:00
parent 7f77507d2b
commit 649717a3cd
7 changed files with 151 additions and 16 deletions

43
src/data/egg-moves.ts Normal file
View File

@ -0,0 +1,43 @@
import { Moves } from "./enums/moves";
import { Species } from "./enums/species";
import { allMoves } from "./move";
import * as Utils from "../utils";
export const speciesEggMoves = {
};
function parseEggMoves(content: string): void {
let output = '';
const speciesNames = Utils.getEnumKeys(Species);
const speciesValues = Utils.getEnumValues(Species);
const lines = content.split(/\n/g);
lines.forEach((line, l) => {
const cols = line.split(',').slice(0, 5);
const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, '').toLowerCase());
const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, '_');
const species = speciesValues[speciesNames.findIndex(s => s === enumSpeciesName)];
let eggMoves: Moves[] = [];
for (let m = 0; m < 4; m++) {
const moveName = cols[m + 1].trim();
const moveIndex = moveName !== 'N/A' ? moveNames.findIndex(mn => mn === moveName.toLowerCase()) : -1;
eggMoves.push(moveIndex > -1 ? moveIndex as Moves : Moves.NONE);
}
if (eggMoves.find(m => m !== Moves.NONE))
output += `[Species.${Species[species]}]: [ ${eggMoves.map(m => `Moves.${Moves[m]}`).join(', ')} ],\n`;
});
console.log(output);
}
const eggMovesStr = ``;
if (eggMovesStr) {
setTimeout(() => {
parseEggMoves(eggMovesStr);
}, 1000);
}

View File

@ -7,7 +7,8 @@ import { Type } from './type';
import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from './pokemon-level-moves'; import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from './pokemon-level-moves';
import { uncatchableSpecies } from './biomes'; import { uncatchableSpecies } from './biomes';
import * as Utils from '../utils'; import * as Utils from '../utils';
import { StarterMoveset } from '../system/game-data'; import { StarterEggMoveData, StarterMoveset } from '../system/game-data';
import { speciesEggMoves } from './egg-moves';
export enum Region { export enum Region {
NORMAL, NORMAL,
@ -98,6 +99,13 @@ export abstract class PokemonSpeciesForm {
this.genderDiffs = genderDiffs; this.genderDiffs = genderDiffs;
} }
getRootSpeciesId(): Species {
let ret = this.speciesId;
while (pokemonPrevolutions.hasOwnProperty(ret))
ret = pokemonPrevolutions[ret];
return ret;
}
isOfType(type: integer): boolean { isOfType(type: integer): boolean {
return this.type1 === type || (this.type2 !== null && this.type2 === type); return this.type1 === type || (this.type2 !== null && this.type2 === type);
} }
@ -261,8 +269,14 @@ export abstract class PokemonSpeciesForm {
return ret; return ret;
} }
validateStarterMoveset(moveset: StarterMoveset): boolean { validateStarterMoveset(moveset: StarterMoveset, eggMoves: integer): boolean {
const rootSpeciesId = this.getRootSpeciesId();
for (let moveId of moveset) { for (let moveId of moveset) {
if (speciesEggMoves.hasOwnProperty(rootSpeciesId)) {
const eggMoveIndex = speciesEggMoves[rootSpeciesId].findIndex(m => m === moveId);
if (eggMoveIndex > -1 && eggMoves & Math.pow(2, eggMoveIndex))
continue;
}
if (pokemonFormLevelMoves.hasOwnProperty(this.speciesId) && pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)) { if (pokemonFormLevelMoves.hasOwnProperty(this.speciesId) && pokemonFormLevelMoves[this.speciesId].hasOwnProperty(this.formIndex)) {
if (!pokemonFormLevelMoves[this.speciesId][this.formIndex].find(lm => lm[0] <= 5 && lm[1] === moveId)) if (!pokemonFormLevelMoves[this.speciesId][this.formIndex].find(lm => lm[0] <= 5 && lm[1] === moveId))
return false; return false;

View File

@ -15,6 +15,7 @@ import { Gender, getGenderColor, getGenderSymbol } from "./data/gender";
import { achvs } from "./system/achv"; import { achvs } from "./system/achv";
import { addWindow } from "./ui/window"; import { addWindow } from "./ui/window";
import { getNatureName } from "./data/nature"; import { getNatureName } from "./data/nature";
import { pokemonPrevolutions } from "./data/pokemon-evolutions";
export class EggHatchPhase extends Phase { export class EggHatchPhase extends Phase {
private egg: Egg; private egg: Egg;
@ -33,6 +34,7 @@ export class EggHatchPhase extends Phase {
private statsContainer: StatsContainer; private statsContainer: StatsContainer;
private pokemon: PlayerPokemon; private pokemon: PlayerPokemon;
private eggMoveIndex: integer;
private canSkip: boolean; private canSkip: boolean;
private skipped: boolean; private skipped: boolean;
private evolutionBgm: AnySound; private evolutionBgm: AnySound;
@ -293,8 +295,10 @@ export class EggHatchPhase extends Phase {
this.scene.ui.showText(`${this.pokemon.name} hatched from the egg!`, null, () => { this.scene.ui.showText(`${this.pokemon.name} hatched from the egg!`, null, () => {
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => {
this.scene.ui.showText(null, 0); this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => {
this.end(); this.scene.ui.showText(null, 0);
this.end();
});
}); });
}, null, true, 3000); }, null, true, 3000);
//this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm()); //this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
@ -412,7 +416,7 @@ export class EggHatchPhase extends Phase {
let speciesPool = Object.keys(speciesStarters) let speciesPool = Object.keys(speciesStarters)
.filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue) .filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue)
.map(s => parseInt(s) as Species) .map(s => parseInt(s) as Species)
.filter(s => getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1); .filter(s => !pokemonPrevolutions.hasOwnProperty(s) && getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1);
if (this.egg.gachaType === GachaType.TYPE) { if (this.egg.gachaType === GachaType.TYPE) {
let tryOverrideType: boolean; let tryOverrideType: boolean;
@ -473,6 +477,12 @@ export class EggHatchPhase extends Phase {
for (let s = 0; s < ret.ivs.length; s++) for (let s = 0; s < ret.ivs.length; s++)
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]); ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
}, ret.id, EGG_SEED.toString()); }, ret.id, EGG_SEED.toString());
this.scene.executeWithSeedOffset(() => {
const rand = Utils.randSeedInt(10);
this.eggMoveIndex = rand ? Math.floor((rand - 1) / 3) : 3;
}, this.egg.id, EGG_SEED.toString());
return ret; return ret;
} }

View File

@ -1712,8 +1712,8 @@ export class TurnEndPhase extends FieldPhase {
pokemon.lapseTags(BattlerTagLapseType.TURN_END); pokemon.lapseTags(BattlerTagLapseType.TURN_END);
if (pokemon.summonData.disabledMove && !--pokemon.summonData.disabledTurns) { if (pokemon.summonData.disabledMove && !--pokemon.summonData.disabledTurns) {
pokemon.summonData.disabledMove = Moves.NONE;
this.scene.pushPhase(new MessagePhase(this.scene, `${allMoves[pokemon.summonData.disabledMove].name} is disabled\nno more!`)); this.scene.pushPhase(new MessagePhase(this.scene, `${allMoves[pokemon.summonData.disabledMove].name} is disabled\nno more!`));
pokemon.summonData.disabledMove = Moves.NONE;
} }
const hasUsableBerry = !!this.scene.findModifier(m => m instanceof BerryModifier && m.shouldApply([ pokemon ]), pokemon.isPlayer()); const hasUsableBerry = !!this.scene.findModifier(m => m instanceof BerryModifier && m.shouldApply([ pokemon ]), pokemon.isPlayer());

View File

@ -1925,7 +1925,7 @@ export class PlayerPokemon extends Pokemon {
} }
tryPopulateMoveset(moveset: StarterMoveset): boolean { tryPopulateMoveset(moveset: StarterMoveset): boolean {
if (!this.getSpeciesForm().validateStarterMoveset(moveset)) if (!this.getSpeciesForm().validateStarterMoveset(moveset, this.scene.gameData.starterEggMoveData[this.species.getRootSpeciesId()]))
return false; return false;
this.moveset = moveset.map(m => new PokemonMove(m)); this.moveset = moveset.map(m => new PokemonMove(m));

View File

@ -25,6 +25,8 @@ import { GameStats } from "./game-stats";
import { Tutorial } from "../tutorial"; import { Tutorial } from "../tutorial";
import { BattleSpec } from "../enums/battle-spec"; import { BattleSpec } from "../enums/battle-spec";
import { Moves } from "../data/enums/moves"; import { Moves } from "../data/enums/moves";
import { speciesEggMoves } from "../data/egg-moves";
import { allMoves } from "../data/move";
const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary
@ -60,6 +62,7 @@ interface SystemSaveData {
gender: PlayerGender; gender: PlayerGender;
dexData: DexData; dexData: DexData;
starterMoveData: StarterMoveData; starterMoveData: StarterMoveData;
starterEggMoveData: StarterEggMoveData;
gameStats: GameStats; gameStats: GameStats;
unlocks: Unlocks; unlocks: Unlocks;
achvUnlocks: AchvUnlocks; achvUnlocks: AchvUnlocks;
@ -146,6 +149,10 @@ export interface StarterFormMoveData {
[key: integer]: StarterMoveset [key: integer]: StarterMoveset
} }
export interface StarterEggMoveData {
[key: integer]: integer
}
export interface TutorialFlags { export interface TutorialFlags {
[key: string]: boolean [key: string]: boolean
} }
@ -172,6 +179,8 @@ export class GameData {
public starterMoveData: StarterMoveData; public starterMoveData: StarterMoveData;
public starterEggMoveData: StarterEggMoveData;
public gameStats: GameStats; public gameStats: GameStats;
public unlocks: Unlocks; public unlocks: Unlocks;
@ -188,6 +197,7 @@ export class GameData {
this.trainerId = Utils.randSeedInt(65536); this.trainerId = Utils.randSeedInt(65536);
this.secretId = Utils.randSeedInt(65536); this.secretId = Utils.randSeedInt(65536);
this.starterMoveData = {}; this.starterMoveData = {};
this.starterEggMoveData = {};
this.gameStats = new GameStats(); this.gameStats = new GameStats();
this.unlocks = { this.unlocks = {
[Unlockables.ENDLESS_MODE]: false, [Unlockables.ENDLESS_MODE]: false,
@ -204,6 +214,7 @@ export class GameData {
}; };
this.eggs = []; this.eggs = [];
this.initDexData(); this.initDexData();
this.initEggMoveData();
} }
public saveSystem(): Promise<boolean> { public saveSystem(): Promise<boolean> {
@ -220,6 +231,7 @@ export class GameData {
gender: this.gender, gender: this.gender,
dexData: this.dexData, dexData: this.dexData,
starterMoveData: this.starterMoveData, starterMoveData: this.starterMoveData,
starterEggMoveData: this.starterEggMoveData,
gameStats: this.gameStats, gameStats: this.gameStats,
unlocks: this.unlocks, unlocks: this.unlocks,
achvUnlocks: this.achvUnlocks, achvUnlocks: this.achvUnlocks,
@ -279,6 +291,13 @@ export class GameData {
this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0); this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0);
this.starterMoveData = systemData.starterMoveData || {}; this.starterMoveData = systemData.starterMoveData || {};
if (systemData.starterEggMoveData)
this.starterEggMoveData = systemData.starterEggMoveData;
else {
this.starterEggMoveData = {};
this.initEggMoveData();
}
if (systemData.gameStats) if (systemData.gameStats)
this.gameStats = systemData.gameStats; this.gameStats = systemData.gameStats;
@ -806,6 +825,15 @@ export class GameData {
this.dexData = data; this.dexData = data;
} }
private initEggMoveData(): void {
const data: StarterEggMoveData = {};
const starterSpeciesIds = Object.keys(speciesEggMoves).map(k => parseInt(k) as Species);
for (let speciesId of starterSpeciesIds)
data[speciesId] = 0;
}
setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void { setPokemonSeen(pokemon: Pokemon, incrementCount: boolean = true): void {
const dexEntry = this.dexData[pokemon.species.speciesId]; const dexEntry = this.dexData[pokemon.species.speciesId];
dexEntry.seenAttr |= pokemon.getDexAttr(); dexEntry.seenAttr |= pokemon.getDexAttr();
@ -822,7 +850,7 @@ export class GameData {
} }
setPokemonSpeciesCaught(pokemon: Pokemon, species: PokemonSpecies, incrementCount: boolean = true, fromEgg: boolean = false): Promise<void> { setPokemonSpeciesCaught(pokemon: Pokemon, species: PokemonSpecies, incrementCount: boolean = true, fromEgg: boolean = false): Promise<void> {
return new Promise<void>((resolve) => { return new Promise<void>(resolve => {
const dexEntry = this.dexData[species.speciesId]; const dexEntry = this.dexData[species.speciesId];
const caughtAttr = dexEntry.caughtAttr; const caughtAttr = dexEntry.caughtAttr;
dexEntry.caughtAttr |= pokemon.getDexAttr(); dexEntry.caughtAttr |= pokemon.getDexAttr();
@ -868,6 +896,31 @@ export class GameData {
}); });
} }
setEggMoveUnlocked(species: PokemonSpecies, eggMoveIndex: integer): Promise<boolean> {
return new Promise<boolean>(resolve => {
const speciesId = species.speciesId;
if (!speciesEggMoves.hasOwnProperty(speciesId) || !speciesEggMoves[speciesId][eggMoveIndex]) {
resolve(false);
return;
}
if (!this.starterEggMoveData.hasOwnProperty(speciesId))
this.starterEggMoveData[speciesId] = 0;
const value = Math.pow(2, eggMoveIndex);
if (this.starterEggMoveData[speciesId] & eggMoveIndex) {
resolve(false);
return;
}
this.starterEggMoveData[speciesId] |= value;
this.scene.playSoundWithoutBgm('level_up_fanfare', 1500);
this.scene.ui.showText(`${eggMoveIndex === 3 ? 'Rare ' : ''}Egg Move unlocked: ${allMoves[speciesEggMoves[speciesId][eggMoveIndex]].name}`, null, () => resolve(true), null, true);
});
}
updateSpeciesDexIvs(speciesId: Species, ivs: integer[]): void { updateSpeciesDexIvs(speciesId: Species, ivs: integer[]): void {
let dexEntry: DexEntry; let dexEntry: DexEntry;
do { do {

View File

@ -22,6 +22,7 @@ import { LevelMoves, pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "../
import { allMoves } from "../data/move"; import { allMoves } from "../data/move";
import { Type } from "../data/type"; import { Type } from "../data/type";
import { Moves } from "../data/enums/moves"; import { Moves } from "../data/enums/moves";
import { speciesEggMoves } from "../data/egg-moves";
export type StarterSelectCallback = (starters: Starter[]) => void; export type StarterSelectCallback = (starters: Starter[]) => void;
@ -144,12 +145,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonNameText.setOrigin(0, 0); this.pokemonNameText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNameText); this.starterSelectContainer.add(this.pokemonNameText);
this.pokemonGrowthRateLabelText = addTextObject(this.scene, 8, 103, 'Growth Rate:', TextStyle.SUMMARY, { fontSize: '48px' }); this.pokemonGrowthRateLabelText = addTextObject(this.scene, 8, 106, 'Growth Rate:', TextStyle.SUMMARY, { fontSize: '36px' });
this.pokemonGrowthRateLabelText.setOrigin(0, 0); this.pokemonGrowthRateLabelText.setOrigin(0, 0);
this.pokemonGrowthRateLabelText.setVisible(false); this.pokemonGrowthRateLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonGrowthRateLabelText); this.starterSelectContainer.add(this.pokemonGrowthRateLabelText);
this.pokemonGrowthRateText = addTextObject(this.scene, 44, 103, '', TextStyle.SUMMARY_PINK, { fontSize: '48px' }); this.pokemonGrowthRateText = addTextObject(this.scene, 34, 106, '', TextStyle.SUMMARY_PINK, { fontSize: '36px' });
this.pokemonGrowthRateText.setOrigin(0, 0); this.pokemonGrowthRateText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonGrowthRateText); this.starterSelectContainer.add(this.pokemonGrowthRateText);
@ -344,9 +345,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.pokemonMovesContainer); this.starterSelectContainer.add(this.pokemonMovesContainer);
this.pokemonEggMovesContainer = this.scene.add.container(102, 94); this.pokemonEggMovesContainer = this.scene.add.container(102, 85);
this.pokemonEggMovesContainer.setScale(0.25); this.pokemonEggMovesContainer.setScale(0.375);
this.pokemonEggMovesContainer.setVisible(false);
const eggMovesLabel = addTextObject(this.scene, -46, 0, 'Egg Moves', TextStyle.SUMMARY); const eggMovesLabel = addTextObject(this.scene, -46, 0, 'Egg Moves', TextStyle.SUMMARY);
eggMovesLabel.setOrigin(0.5, 0); eggMovesLabel.setOrigin(0.5, 0);
@ -617,9 +617,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}; };
}).concat({ }).concat({
label: 'Cancel', label: 'Cancel',
handler: () => { handler: () => showSwapOptions(this.starterMoveset)
showSwapOptions(this.starterMoveset);
}
}), }),
maxOptions: 8, maxOptions: 8,
yOffset: 19 yOffset: 19
@ -1106,6 +1104,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
else else
levelMoves = pokemonSpeciesLevelMoves[species.speciesId]; levelMoves = pokemonSpeciesLevelMoves[species.speciesId];
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1])); this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] <= 5).map(lm => lm[1]));
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
for (let em = 0; em < 4; em++) {
if (this.scene.gameData.starterEggMoveData[species.speciesId] & Math.pow(2, em))
this.speciesStarterMoves.push(speciesEggMoves[species.speciesId][em]);
}
}
const speciesMoveData = this.scene.gameData.starterMoveData[species.speciesId]; const speciesMoveData = this.scene.gameData.starterMoveData[species.speciesId];
let moveData: StarterMoveset = speciesMoveData let moveData: StarterMoveset = speciesMoveData
@ -1134,6 +1138,17 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonMoveContainers[m].setVisible(!!move); this.pokemonMoveContainers[m].setVisible(!!move);
} }
const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId);
for (let em = 0; em < 4; em++) {
const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null;
const eggMoveUnlocked = eggMove && this.scene.gameData.starterEggMoveData.hasOwnProperty(species.speciesId) && this.scene.gameData.starterEggMoveData[species.speciesId] & Math.pow(2, em);
this.pokemonEggMoveBgs[em].setFrame(Type[eggMove ? eggMove.type : Type.UNKNOWN].toString().toLowerCase());
this.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : '???');
}
this.pokemonEggMovesContainer.setVisible(hasEggMoves);
this.pokemonAdditionalMoveCountLabel.setText(`(+${Math.max(this.speciesStarterMoves.length - 4, 0)})`); this.pokemonAdditionalMoveCountLabel.setText(`(+${Math.max(this.speciesStarterMoves.length - 4, 0)})`);
this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4); this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4);