diff --git a/sim/team-validator.ts b/sim/team-validator.ts index 90befa2195..07953271da 100644 --- a/sim/team-validator.ts +++ b/sim/team-validator.ts @@ -112,6 +112,11 @@ export class PokemonSources { * Used to deal with compatibility issues for prevo/evo-exclusive moves */ learnsetDomain?: string[] | null; + /** + * A list of moves which are incompatible with a Pokemon GO origin, + * used to generate error messages + */ + goIncompatibleMoves?: string[]; /** * Some Pokemon evolve by having a move in their learnset (like Piloswine * with Ancient Power). These can only carry three other moves from their @@ -311,6 +316,16 @@ export class PokemonSources { this.dreamWorldMoveCount += other.dreamWorldMoveCount; if (other.sourcesAfter > this.sourcesAfter) this.sourcesAfter = other.sourcesAfter; if (other.isHidden) this.isHidden = true; + + if (other.sourcesBefore < 8 && !other.sources.some(source => source === '8V') && this.restrictiveMoves) { + this.addGoIncompatibleMove(this.restrictiveMoves[this.restrictiveMoves.length - 1]); + } + } + + addGoIncompatibleMove(move: string) { + if (!this.goIncompatibleMoves) this.goIncompatibleMoves = []; + if (move) this.goIncompatibleMoves.push(move); + this.isFromPokemonGo = false; } } @@ -854,6 +869,16 @@ export class TeamValidator { if (ruleTable.has('obtainablemoves')) { moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist); problems.push(...moveProblems); + + const incompatibleMoves = setSources.goIncompatibleMoves; + if (pokemonGoProblems && incompatibleMoves) { + if (incompatibleMoves?.length) { + pokemonGoProblems.push(`${name}'s move${incompatibleMoves.length === 1 ? `` : `s`} ${incompatibleMoves.join(`, `)} ` + + `${incompatibleMoves.length === 1 ? `is` : `are`} incompatible with a Pokemon GO origin.`); + } else { + pokemonGoProblems.push(`${name} has moves which are incompatible with a Pokemon GO origin.`); + } + } } let eventOnlyData; @@ -1005,7 +1030,6 @@ export class TeamValidator { // Hardcoded forced validation for Pokemon GO const pokemonGoOnlySpecies = ['meltan', 'melmetal', 'gimmighoulroaming']; if (ruleTable.has('obtainablemisc') && (pokemonGoOnlySpecies.includes(species.id))) { - setSources.isFromPokemonGo = true; if (pokemonGoProblems?.length) { problems.push(`${name} is only obtainable from Pokemon GO, and failed to validate because:`); for (const pokemonGoProblem of pokemonGoProblems) { @@ -1014,17 +1038,6 @@ export class TeamValidator { } } - // Attempt move validation again after verifying Pokemon GO origin - if (ruleTable.has('obtainablemoves') && setSources.isFromPokemonGo) { - setSources.restrictiveMoves = []; - setSources.sources = ['8V']; - setSources.sourcesBefore = 0; - if (moveProblems && !moveProblems.length) { - problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, - moveLegalityWhitelist)); - } - } - if (ruleTable.has('obtainablemoves')) { if (species.id === 'keldeo' && set.moves.includes('secretsword') && this.minSourceGen > 5 && dex.gen <= 7) { problems.push(`${name} has Secret Sword, which is only compatible with Keldeo-Ordinary obtained from Gen 5.`); @@ -2359,9 +2372,11 @@ export class TeamValidator { if (otherProblems) { problems = otherProblems; } else { + setSources.isFromPokemonGo = false; return null; } } else { + setSources.isFromPokemonGo = false; return null; } } else { @@ -2655,8 +2670,7 @@ export class TeamValidator { } else if (this.ruleTable.has('pomegglitchclause') && level >= 5 && learnedGen === 3 && species.canHatch) { // Pomeg Glitch learned = `${learnedGen}Epomeg` as MoveSource; - } else if (species.gender !== 'N' && - learnedGen >= 2 && species.canHatch && !setSources.isFromPokemonGo) { + } else if (species.gender !== 'N' && learnedGen >= 2 && species.canHatch) { // available as egg move if (species.gender === 'M' && !this.motherCanLearn(toID(species.mother), moveid)) { // male-only Pokemon can have level-up egg moves if it can have a mother that learns the move @@ -2678,10 +2692,8 @@ export class TeamValidator { if (learnedGen === dex.gen && learned.charAt(1) !== 'R') { // current-gen level-up, TM or tutor moves: // always available - if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly && - setSources.isFromPokemonGo && species.evoLevel) { - cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`; - continue; + if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly && species.evoLevel) { + setSources.addGoIncompatibleMove(move.name); } if (!moveSources.moveEvoCarryCount && !babyOnly) return null; } @@ -2740,9 +2752,8 @@ export class TeamValidator { } else if (learned.charAt(1) === 'V' && this.minSourceGen < learnedGen) { // Virtual Console or Let's Go transfer moves: // only if that was the source - if (learned === '8V' && setSources.isFromPokemonGo && babyOnly && species.evoLevel) { - cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`; - continue; + if (learned === '8V' && babyOnly && species.evoLevel) { + setSources.addGoIncompatibleMove(move.name); } moveSources.add(learned); } @@ -2822,8 +2833,7 @@ export class TeamValidator { } const checkedSpecies = babyOnly ? fullLearnset[fullLearnset.length - 1].species : baseSpecies; - if (checkedSpecies && setSources.isFromPokemonGo && - (setSources.pokemonGoSource === 'purified' || checkedSpecies.id === 'mew')) { + if (checkedSpecies && (setSources.pokemonGoSource === 'purified' || checkedSpecies.id === 'mew')) { // Pokemon that cannot be sent from Pokemon GO to Let's Go can only access Let's Go moves through HOME // It can only obtain a chain of four level up moves and cannot have TM moves const pokemonGoData = dex.species.getPokemonGoData(checkedSpecies.id); @@ -2836,10 +2846,8 @@ export class TeamValidator { for (const restrictiveMove in pokemonGoData.LGPERestrictiveMoves) { const moveLevel = pokemonGoData.LGPERestrictiveMoves[restrictiveMove]; if (toID(move) === restrictiveMove) { - if (!moveLevel) { - return `'s move ${move.name} is incompatible with its Pokemon GO origin.`; - } else if (set.level && set.level < moveLevel) { - return ` must be at least level ${moveLevel} to learn ${move.name} due to its Pokemon GO origin.`; + if (!moveLevel || (set.level && set.level < moveLevel)) { + setSources.addGoIncompatibleMove(move.name); } } if (levelUpMoveCount) levelUpMoveCount++; @@ -2847,7 +2855,8 @@ export class TeamValidator { if (!levelUpMoveCount) { levelUpMoveCount++; } else if (levelUpMoveCount > 4) { - return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible with its Pokemon GO origin.`; + // Moves which are only incompatible when together + setSources.addGoIncompatibleMove(''); } } } @@ -2901,7 +2910,6 @@ export class TeamValidator { // prevents a crash if OMs override `checkCanLearn` to keep validating after an error setSources.sources = backupSources; setSources.sourcesBefore = backupSourcesBefore; - if (setSources.isFromPokemonGo) return `'s move ${move.name} is incompatible with its Pokemon GO origin.`; return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible.`; }