Implement support for relearner only moves (#1667)

Currently only used by Zangoose
This commit is contained in:
Xavion3 2024-07-04 05:13:25 +10:00 committed by GitHub
parent 126174efe4
commit ef5a29f9b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 61 deletions

View File

@ -5827,20 +5827,20 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
[ 56, Moves.SKY_ATTACK ], [ 56, Moves.SKY_ATTACK ],
], ],
[Species.ZANGOOSE]: [ [Species.ZANGOOSE]: [
[ -1, Moves.DOUBLE_KICK ],
[ -1, Moves.DISABLE ],
[ -1, Moves.COUNTER ],
[ -1, Moves.FURY_SWIPES ],
[ -1, Moves.CURSE ],
[ -1, Moves.FLAIL ],
[ -1, Moves.BELLY_DRUM ],
[ -1, Moves.FEINT ],
[ -1, Moves.NIGHT_SLASH ],
[ -1, Moves.DOUBLE_HIT ],
[ -1, Moves.QUICK_GUARD ],
[ -1, Moves.FINAL_GAMBIT ],
[ 1, Moves.SCRATCH ], [ 1, Moves.SCRATCH ],
[ 1, Moves.LEER ], [ 1, Moves.LEER ],
[ 1, Moves.DOUBLE_KICK ],
[ 1, Moves.DISABLE ],
[ 1, Moves.COUNTER ],
[ 1, Moves.FURY_SWIPES ],
[ 1, Moves.CURSE ],
[ 1, Moves.FLAIL ],
[ 1, Moves.BELLY_DRUM ],
[ 1, Moves.FEINT ],
[ 1, Moves.NIGHT_SLASH ],
[ 1, Moves.DOUBLE_HIT ],
[ 1, Moves.QUICK_GUARD ],
[ 1, Moves.FINAL_GAMBIT ],
[ 5, Moves.QUICK_ATTACK ], [ 5, Moves.QUICK_ATTACK ],
[ 8, Moves.FURY_CUTTER ], [ 8, Moves.FURY_CUTTER ],
[ 12, Moves.METAL_CLAW ], [ 12, Moves.METAL_CLAW ],

View File

@ -779,7 +779,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
} }
// This could definitely be written better and more accurate to the getSpeciesForLevel logic, but it is only for generating movesets for evolved Pokemon // This could definitely be written better and more accurate to the getSpeciesForLevel logic, but it is only for generating movesets for evolved Pokemon
getSimulatedEvolutionChain(currentLevel: integer, forTrainer: boolean = false, isBoss: boolean = false, player: boolean = false) { getSimulatedEvolutionChain(currentLevel: integer, forTrainer: boolean = false, isBoss: boolean = false, player: boolean = false): [Species, integer][] {
const ret = []; const ret = [];
if (pokemonPrevolutions.hasOwnProperty(this.speciesId)) { if (pokemonPrevolutions.hasOwnProperty(this.speciesId)) {
const prevolutionLevels = this.getPrevolutionLevels().reverse(); const prevolutionLevels = this.getPrevolutionLevels().reverse();

View File

@ -849,8 +849,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return ret; return ret;
} }
/**
* All moves that could be relearned by this pokemon at this point. Used for memory mushrooms.
* @returns {Moves[]} The valid moves
*/
getLearnableLevelMoves(): Moves[] { getLearnableLevelMoves(): Moves[] {
return this.getLevelMoves(1, true).map(lm => lm[1]).filter(lm => !this.moveset.filter(m => m.moveId === lm).length).filter((move: Moves, i: integer, array: Moves[]) => array.indexOf(move) === i); return this.getLevelMoves(1, true, false, true).map(lm => lm[1]).filter(lm => !this.moveset.filter(m => m.moveId === lm).length).filter((move: Moves, i: integer, array: Moves[]) => array.indexOf(move) === i);
} }
/** /**
@ -1235,7 +1239,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return null; return null;
} }
getLevelMoves(startingLevel?: integer, includeEvolutionMoves: boolean = false, simulateEvolutionChain: boolean = false): LevelMoves { /**
* Gets all level up moves in a given range for a particular pokemon.
* @param {integer} startingLevel Don't include moves below this level
* @param {boolean} includeEvolutionMoves Whether to include evolution moves
* @param {boolean} simulateEvolutionChain Whether to include moves from prior evolutions
* @param {boolean} includeRelearnerMoves Whether to include moves that would require a relearner. Note the move relearner inherently allows evolution moves
* @returns {LevelMoves} A list of moves and the levels they can be learned at
*/
getLevelMoves(startingLevel?: integer, includeEvolutionMoves: boolean = false, simulateEvolutionChain: boolean = false, includeRelearnerMoves: boolean = false): LevelMoves {
const ret: LevelMoves = []; const ret: LevelMoves = [];
let levelMoves: LevelMoves = []; let levelMoves: LevelMoves = [];
if (!startingLevel) { if (!startingLevel) {
@ -1246,62 +1258,45 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
for (let e = 0; e < evolutionChain.length; e++) { for (let e = 0; e < evolutionChain.length; e++) {
// TODO: Might need to pass specific form index in simulated evolution chain // TODO: Might need to pass specific form index in simulated evolution chain
const speciesLevelMoves = getPokemonSpeciesForm(evolutionChain[e][0] as Species, this.formIndex).getLevelMoves(); const speciesLevelMoves = getPokemonSpeciesForm(evolutionChain[e][0] as Species, this.formIndex).getLevelMoves();
levelMoves.push(...speciesLevelMoves.filter(lm => (includeEvolutionMoves && !lm[0]) || ((!e || lm[0] > 1) && (e === evolutionChain.length - 1 || lm[0] <= evolutionChain[e + 1][1])))); if (includeRelearnerMoves) {
} levelMoves.push(...speciesLevelMoves);
levelMoves.sort((lma: [integer, integer], lmb: [integer, integer]) => lma[0] > lmb[0] ? 1 : lma[0] < lmb[0] ? -1 : 0); } else {
const uniqueMoves: Moves[] = []; levelMoves.push(...speciesLevelMoves.filter(lm => (includeEvolutionMoves && lm[0] === 0) || ((!e || lm[0] > 1) && (e === evolutionChain.length - 1 || lm[0] <= evolutionChain[e + 1][1]))));
levelMoves = levelMoves.filter(lm => {
if (uniqueMoves.find(m => m === lm[1])) {
return false;
} }
uniqueMoves.push(lm[1]); }
return true;
});
} else { } else {
levelMoves = this.getSpeciesForm(true).getLevelMoves(); levelMoves = this.getSpeciesForm(true).getLevelMoves().filter(lm => (includeEvolutionMoves && lm[0] === 0) || (includeRelearnerMoves && lm[0] === -1) || lm[0] > 0);
} }
if (this.fusionSpecies) { if (this.fusionSpecies) {
const evolutionLevelMoves = levelMoves.slice(0, Math.max(levelMoves.findIndex(lm => !!lm[0]), 0)); if (simulateEvolutionChain) {
const fusionLevelMoves = this.getFusionSpeciesForm(true).getLevelMoves(); const fusionEvolutionChain = this.fusionSpecies.getSimulatedEvolutionChain(this.level, this.hasTrainer(), this.isBoss(), this.isPlayer());
const fusionEvolutionLevelMoves = fusionLevelMoves.slice(0, Math.max(fusionLevelMoves.findIndex(flm => !!flm[0]), 0)); for (let e = 0; e < fusionEvolutionChain.length; e++) {
const newLevelMoves: LevelMoves = []; // TODO: Might need to pass specific form index in simulated evolution chain
while (levelMoves.length && levelMoves[0][0] < startingLevel) { const speciesLevelMoves = getPokemonSpeciesForm(fusionEvolutionChain[e][0] as Species, this.fusionFormIndex).getLevelMoves();
levelMoves.shift(); if (includeRelearnerMoves) {
} levelMoves.push(...speciesLevelMoves.filter(lm => (includeEvolutionMoves && lm[0] === 0) || lm[0] !== 0));
while (fusionLevelMoves.length && fusionLevelMoves[0][0] < startingLevel) { } else {
fusionLevelMoves.shift(); levelMoves.push(...speciesLevelMoves.filter(lm => (includeEvolutionMoves && lm[0] === 0) || ((!e || lm[0] > 1) && (e === fusionEvolutionChain.length - 1 || lm[0] <= fusionEvolutionChain[e + 1][1]))));
}
if (includeEvolutionMoves) {
for (const elm of evolutionLevelMoves.reverse()) {
levelMoves.unshift(elm);
}
for (const felm of fusionEvolutionLevelMoves.reverse()) {
fusionLevelMoves.unshift(felm);
}
}
for (let l = includeEvolutionMoves ? 0 : startingLevel; l <= this.level; l++) {
if (l === 1 && startingLevel > 1) {
l = startingLevel;
}
while (levelMoves.length && levelMoves[0][0] === l) {
const levelMove = levelMoves.shift();
if (!newLevelMoves.find(lm => lm[1] === levelMove[1])) {
newLevelMoves.push(levelMove);
}
}
while (fusionLevelMoves.length && fusionLevelMoves[0][0] === l) {
const fusionLevelMove = fusionLevelMoves.shift();
if (!newLevelMoves.find(lm => lm[1] === fusionLevelMove[1])) {
newLevelMoves.push(fusionLevelMove);
} }
} }
} else {
levelMoves.push(...this.getFusionSpeciesForm(true).getLevelMoves().filter(lm => (includeEvolutionMoves && lm[0] === 0) || (includeRelearnerMoves && lm[0] === -1) || lm[0] > 0));
} }
levelMoves = newLevelMoves;
} }
levelMoves.sort((lma: [integer, integer], lmb: [integer, integer]) => lma[0] > lmb[0] ? 1 : lma[0] < lmb[0] ? -1 : 0);
const uniqueMoves: Moves[] = [];
levelMoves = levelMoves.filter(lm => {
if (uniqueMoves.find(m => m === lm[1])) {
return false;
}
uniqueMoves.push(lm[1]);
return true;
});
if (levelMoves) { if (levelMoves) {
for (const lm of levelMoves) { for (const lm of levelMoves) {
const level = lm[0]; const level = lm[0];
if ((!includeEvolutionMoves || level) && level < startingLevel) { if (!includeRelearnerMoves && ((level > 0 && level < startingLevel) || (!includeEvolutionMoves && level === 0) || level < 0)) {
continue; continue;
} else if (level > this.level) { } else if (level > this.level) {
break; break;

View File

@ -2366,7 +2366,7 @@ 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] > 0 && lm[0] <= 5).map(lm => lm[1]));
if (speciesEggMoves.hasOwnProperty(species.speciesId)) { if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
for (let em = 0; em < 4; em++) { for (let em = 0; em < 4; em++) {
if (this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em)) { if (this.scene.gameData.starterData[species.speciesId].eggMoves & Math.pow(2, em)) {