diff --git a/config/formats.ts b/config/formats.ts index b340d0655af51..979797b46fc9e 100644 --- a/config/formats.ts +++ b/config/formats.ts @@ -3069,6 +3069,22 @@ export const Formats: FormatList = [ } }, }, + { + name: "[Gen 9] Draft Factory", + desc: `Replay a random matchup from Smogon's Draft League tournaments.`, + team: 'draft', + ruleset: ['Obtainable', 'Species Clause', 'HP Percentage Mod', 'Cancel Mod', 'Team Preview', 'Sleep Clause Mod', 'Endless Battle Clause'], + onBegin() { + for (const [i, side] of this.sides.entries()) { + // Order of team is not changed from the data doc + for (const [j, set] of this.teamGenerator.matchup[i].entries()) { + if (!set.teraCaptain) { + side.pokemon[j].canTerastallize = false; + } + } + } + }, + }, { name: "[Gen 8] Random Battle", desc: `Randomized teams of level-balanced Pokémon with sets that are generated to be competitively viable.`, diff --git a/data/draft-factory.ts b/data/draft-factory.ts new file mode 100644 index 0000000000000..0367cdebec144 --- /dev/null +++ b/data/draft-factory.ts @@ -0,0 +1,68 @@ +import {PRNG} from "../sim/prng"; +import {deepClone} from "../lib/utils"; + +interface DraftPokemonSet extends Partial { + teraCaptain?: boolean; +} + +const sampleData: [DraftPokemonSet[], DraftPokemonSet[]][] = [ + [ + [ + { + name: 'Fred', + species: 'Furret', + item: 'Choice Scarf', + ability: 'Frisk', + moves: ['trick', 'doubleedge', 'knockoff', 'uturn'], + nature: 'Jolly', + evs: {hp: 8, atk: 252, def: 0, spa: 0, spd: 0, spe: 252}, + teraCaptain: true, + teraType: 'Normal', + }, + ], + [ + { + species: 'Ampharos', + item: 'Choice Specs', + ability: 'Static', + moves: ['dazzlinggleam', 'thunderbolt', 'focusblast', 'voltswitch'], + nature: 'Modest', + evs: {hp: 248, atk: 0, def: 8, spa: 252, spd: 0, spe: 0}, + }, + ], + ], +]; + +export default class DraftFactory { + dex: ModdedDex; + format: Format; + prng: PRNG; + matchup?: [DraftPokemonSet[], DraftPokemonSet[]]; + playerIndex: number; + swapTeams: boolean; + constructor(format: Format | string, seed: PRNG | PRNGSeed | null) { + this.dex = Dex.forFormat(format); + this.format = Dex.formats.get(format); + this.prng = seed instanceof PRNG ? seed : new PRNG(seed); + this.playerIndex = 0; + this.swapTeams = this.prng.randomChance(1, 2); + } + + setSeed(seed: PRNGSeed) { + this.prng.seed = seed; + } + + getTeam(options?: PlayerOptions | null): PokemonSet[] { + if (this.playerIndex > 1) throw new Error("Can't generate more than 2 teams"); + + if (!this.matchup) { + this.matchup = deepClone(sampleData[this.prng.next(sampleData.length)]); + if (this.swapTeams) this.matchup!.push(this.matchup!.shift()!); + } + + const team: PokemonSet[] = this.matchup![this.playerIndex] as PokemonSet[]; + + this.playerIndex++; + return team; + } +} diff --git a/sim/teams.ts b/sim/teams.ts index 41eebc38d7471..bf795108f5530 100644 --- a/sim/teams.ts +++ b/sim/teams.ts @@ -619,6 +619,8 @@ export const Teams = new class Teams { let TeamGenerator; if (toID(format).includes('gen9computergeneratedteams')) { TeamGenerator = require(Dex.forFormat(format).dataDir + '/cg-teams').default; + } else if (toID(format).includes('gen9draftfactory')) { + TeamGenerator = require(Dex.forFormat(format).dataDir + '/draft-factory').default; } else if (toID(format).includes('gen7randomdoublesbattle')) { TeamGenerator = require(Dex.forFormat(format).dataDir + '/random-doubles-teams').default; } else { diff --git a/test/random-battles/draft-factory.js b/test/random-battles/draft-factory.js new file mode 100644 index 0000000000000..f1292b46a8d12 --- /dev/null +++ b/test/random-battles/draft-factory.js @@ -0,0 +1,54 @@ +'use strict'; + +const assert = require('../assert'); +const common = require('../common'); +const DraftFactory = require('../../dist/data/draft-factory').default; + +let battle; + +describe.only('Draft Factory', () => { + afterEach(() => battle.destroy()); + + it('should only allow the designated Tera Captains to Terastallize', () => { + battle = common.createBattle({formatid: 'gen9draftfactory'}); + // Manually create a team generator instance and rig it with data + battle.teamGenerator = new DraftFactory(battle.format, null); + battle.teamGenerator.swapTeams = false; + battle.teamGenerator.matchup = [ + [ + { + species: 'Furret', + ability: 'keeneye', + moves: ['sleeptalk'], + teraCaptain: true, + teraType: 'Normal', + }, + { + species: 'Ampharos', + ability: 'static', + moves: ['sleeptalk'], + }, + ], + [ + { + species: 'Nincada', + ability: 'compoundeyes', + moves: ['sleeptalk'], + }, + { + species: 'Marshtomp', + ability: 'torrent', + moves: ['sleeptalk'], + teraCaptain: true, + teraType: 'Fighting', + }, + ], + ]; + battle.setPlayer('p1', {}); + battle.setPlayer('p2', {}); + battle.makeChoices(); // team preview + assert.throws(() => { battle.choose('p2', 'move 1 terastallize'); }, `${battle.p2.pokemon[0].name} should not be able to tera`); + battle.makeChoices('move 1 terastallize', 'switch 2'); + battle.makeChoices('auto', 'move 1 terastallize'); + }); +});