mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-17 10:46:53 -05:00
* Add PMOTS Adding Restrictions and Roulettemons Random Battles * Update pokedex.ts * Update random-teams.ts * Update config/formats.ts Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com> * Update config/formats.ts Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com> * Update config/formats.ts Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com> Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com>
118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
import {PRNG, PRNGSeed} from '../../../sim/prng';
|
|
import RandomTeams from '../../random-teams';
|
|
|
|
export class RandomRoulettemonsTeams extends RandomTeams {
|
|
constructor(format: Format | string, prng: PRNG | PRNGSeed | null) {
|
|
super(format, prng);
|
|
this.noStab = [...this.noStab, 'gigaimpact'];
|
|
}
|
|
|
|
getPokemonPool(
|
|
type: string,
|
|
pokemonToExclude: RandomTeamsTypes.RandomSet[] = [],
|
|
isMonotype = false,
|
|
) {
|
|
const pokemonPool = [];
|
|
for (let species of this.dex.species.all()) {
|
|
if (species.heightm) continue;
|
|
if (isMonotype) {
|
|
if (!species.types.includes(type)) continue;
|
|
if (typeof species.battleOnly === 'string') {
|
|
species = this.dex.species.get(species.battleOnly);
|
|
if (!species.types.includes(type)) continue;
|
|
}
|
|
}
|
|
pokemonPool.push(species.id);
|
|
}
|
|
return pokemonPool;
|
|
}
|
|
randomTeam() {
|
|
this.enforceNoDirectCustomBanlistChanges();
|
|
|
|
const seed = this.prng.seed;
|
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
|
|
|
// For Monotype
|
|
const isMonotype = !!this.forceMonotype || ruleTable.has('sametypeclause');
|
|
const typePool = this.dex.types.names();
|
|
const type = this.forceMonotype || this.sample(typePool);
|
|
|
|
const baseFormes: {[k: string]: number} = {};
|
|
|
|
const typeCount: {[k: string]: number} = {};
|
|
const typeComboCount: {[k: string]: number} = {};
|
|
const teamDetails: RandomTeamsTypes.TeamDetails = {};
|
|
|
|
const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
|
|
while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
|
|
const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
|
|
if (!species.exists) continue;
|
|
// Check if the forme has moves for random battle
|
|
if (this.format.gameType === 'singles') {
|
|
if (!species.randomBattleMoves?.length) continue;
|
|
} else {
|
|
if (!species.randomDoubleBattleMoves?.length) continue;
|
|
}
|
|
// Limit to one of each species (Species Clause)
|
|
if (baseFormes[species.baseSpecies]) continue;
|
|
|
|
// Adjust rate for species with multiple sets
|
|
// TODO: investigate automating this by searching for Pokémon with multiple sets
|
|
|
|
const types = species.types;
|
|
const typeCombo = types.slice().sort().join();
|
|
// Dynamically scale limits for different team sizes. The default and minimum value is 1.
|
|
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
|
|
|
|
// Limit one of any type combination, two in Monotype
|
|
if (!this.forceMonotype && typeComboCount[typeCombo] >= (isMonotype ? 2 : 1) * limitFactor) continue;
|
|
|
|
const set = this.randomSet(species, teamDetails, pokemon.length === 0,
|
|
this.format.gameType !== 'singles', this.dex.formats.getRuleTable(this.format).has('dynamaxclause'));
|
|
|
|
// Okay, the set passes, add it to our team
|
|
pokemon.push(set);
|
|
|
|
// Now that our Pokemon has passed all checks, we can increment our counters
|
|
baseFormes[species.baseSpecies] = 1;
|
|
|
|
// Increment type counters
|
|
for (const typeName of types) {
|
|
if (typeName in typeCount) {
|
|
typeCount[typeName]++;
|
|
} else {
|
|
typeCount[typeName] = 1;
|
|
}
|
|
}
|
|
if (typeCombo in typeComboCount) {
|
|
typeComboCount[typeCombo]++;
|
|
} else {
|
|
typeComboCount[typeCombo] = 1;
|
|
}
|
|
|
|
// Track what the team has
|
|
if (set.ability === 'Drizzle' || set.moves.includes('raindance')) teamDetails.rain = 1;
|
|
if (set.ability === 'Drought' || set.moves.includes('sunnyday')) teamDetails.sun = 1;
|
|
if (set.ability === 'Sand Stream') teamDetails.sand = 1;
|
|
if (set.ability === 'Snow Warning') teamDetails.hail = 1;
|
|
if (set.moves.includes('spikes')) teamDetails.spikes = (teamDetails.spikes || 0) + 1;
|
|
if (set.moves.includes('stealthrock')) teamDetails.stealthRock = 1;
|
|
if (set.moves.includes('stickyweb')) teamDetails.stickyWeb = 1;
|
|
if (set.moves.includes('toxicspikes')) teamDetails.toxicSpikes = 1;
|
|
if (set.moves.includes('defog')) teamDetails.defog = 1;
|
|
if (set.moves.includes('rapidspin')) teamDetails.rapidSpin = 1;
|
|
if (set.moves.includes('auroraveil') || (set.moves.includes('reflect') && set.moves.includes('lightscreen'))) {
|
|
teamDetails.screens = 1;
|
|
}
|
|
}
|
|
if (pokemon.length < this.maxTeamSize && pokemon.length < 12) { // large teams sometimes cannot be built
|
|
throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
|
|
}
|
|
|
|
return pokemon;
|
|
}
|
|
}
|
|
|
|
export default RandomRoulettemonsTeams;
|