@pkmn/sim 0.5.22 → 0.5.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/build/config/formats.js +296 -325
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/aliases.js +4 -4
  4. package/build/data/aliases.js.map +1 -1
  5. package/build/data/conditions.js +1 -1
  6. package/build/data/conditions.js.map +1 -1
  7. package/build/data/formats-data.js +7 -8
  8. package/build/data/formats-data.js.map +1 -1
  9. package/build/data/mods/gen1/formats-data.js +1 -1
  10. package/build/data/mods/gen1/formats-data.js.map +1 -1
  11. package/build/data/mods/gen1/moves.js +5 -0
  12. package/build/data/mods/gen1/moves.js.map +1 -1
  13. package/build/data/mods/gen1/scripts.js +4 -2
  14. package/build/data/mods/gen1/scripts.js.map +1 -1
  15. package/build/data/mods/gen3/formats-data.js +3 -3
  16. package/build/data/mods/gen3/formats-data.js.map +1 -1
  17. package/build/data/mods/gen6/formats-data.js +64 -64
  18. package/build/data/mods/gen6/formats-data.js.map +1 -1
  19. package/build/data/rulesets.js +108 -1
  20. package/build/data/rulesets.js.map +1 -1
  21. package/build/sim/battle-stream.js +3 -0
  22. package/build/sim/battle-stream.js.map +1 -1
  23. package/build/sim/exported-global-types.d.ts +2 -0
  24. package/build/sim/global-types.d.ts +2 -0
  25. package/build/sim/pokemon.d.ts +1 -0
  26. package/build/sim/pokemon.js +1 -0
  27. package/build/sim/pokemon.js.map +1 -1
  28. package/config/formats.ts +294 -318
  29. package/data/aliases.ts +4 -4
  30. package/data/conditions.ts +1 -1
  31. package/data/formats-data.ts +7 -8
  32. package/data/mods/gen1/formats-data.ts +1 -1
  33. package/data/mods/gen1/moves.ts +5 -0
  34. package/data/mods/gen1/scripts.ts +3 -2
  35. package/data/mods/gen3/formats-data.ts +3 -3
  36. package/data/mods/gen6/formats-data.ts +64 -64
  37. package/data/rulesets.ts +92 -1
  38. package/package.json +2 -2
  39. package/sim/battle-stream.ts +3 -0
  40. package/sim/exported-global-types.ts +2 -0
  41. package/sim/global-types.ts +2 -0
  42. package/sim/pokemon.ts +2 -0
@@ -218,8 +218,9 @@ exports.Formats = [
218
218
  mod: 'gen8',
219
219
  ruleset: ['[Gen 8] PU'],
220
220
  banlist: [
221
- 'PU', 'Arctovish', 'Aurorus', 'Basculin', 'Centiskorch', 'Drampa', 'Exeggutor-Alola', 'Gallade', 'Haunter', 'Magmortar', 'Magneton', 'Malamar',
222
- 'Omastar', 'Rotom-Frost', 'Turtonator', 'Vanilluxe', 'Vikavolt', 'Silvally-Dragon', 'Silvally-Ground', 'Sneasel', 'Damp Rock', 'Grassy Seed',
221
+ 'PU', 'Arctovish', 'Aurorus', 'Basculin', 'Centiskorch', 'Drampa', 'Exeggutor-Alola', 'Gallade', 'Haunter', 'Magmortar', 'Magneton',
222
+ 'Malamar', 'Ninjask', 'Omastar', 'Rotom-Frost', 'Turtonator', 'Vanilluxe', 'Vikavolt', 'Silvally-Dragon', 'Silvally-Ground', 'Sneasel',
223
+ 'Damp Rock', 'Grassy Seed',
223
224
  ],
224
225
  },
225
226
  {
@@ -268,6 +269,16 @@ exports.Formats = [
268
269
  ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'Limit Two Restricted'],
269
270
  restricted: ['Restricted Legendary'],
270
271
  },
272
+ {
273
+ name: "[Gen 8] I Choose 'Chu!",
274
+ threads: [
275
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3705481/">I Choose 'Chu! Discussion</a>`,
276
+ ],
277
+ mod: 'gen8',
278
+ ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8'],
279
+ banlist: ['All Pokemon', 'Raichu-Alola + Sing'],
280
+ unbanlist: ['Pichu', 'Pikachu', 'Raichu'],
281
+ },
271
282
  {
272
283
  name: "[Gen 8] Custom Game",
273
284
  mod: 'gen8',
@@ -418,17 +429,6 @@ exports.Formats = [
418
429
  }
419
430
  },
420
431
  },
421
- {
422
- name: "[Gen 8] Jump! Magikarp!",
423
- desc: `Every team must contain Magikarp and bring it to the game.`,
424
- threads: [
425
- `&bullet; <a href="https://www.smogon.com/forums/threads/3704588/">Jump! Magikarp!</a>`,
426
- ],
427
- mod: 'gen8',
428
- gameType: 'doubles',
429
- ruleset: ['Flat Rules', '!! Picked Team Size = 2', '!! Adjust Level = 50', 'Min Source Gen = 8', 'Force Select = Magikarp'],
430
- banlist: ['Sub-Legendary'],
431
- },
432
432
  {
433
433
  name: "[Gen 8] Doubles Custom Game",
434
434
  mod: 'gen8',
@@ -581,272 +581,42 @@ exports.Formats = [
581
581
  column: 2,
582
582
  },
583
583
  {
584
- name: "[Gen 8] Broken Record",
585
- desc: `Pok&eacute;mon can hold a TR to use that move in battle.`,
584
+ name: "[Gen 8] Re-Evolution",
585
+ desc: `Pok&eacute;mon gain the stat changes they would gain from evolving again.`,
586
586
  threads: [
587
- `&bullet; <a href="https://www.smogon.com/forums/threads/3701270/">Broken Record</a>`,
587
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3703643/">Re-Evolution</a>`,
588
588
  ],
589
589
  mod: 'gen8',
590
- ruleset: ['Standard', '!Sleep Clause Mod', 'Sleep Moves Clause', 'Dynamax Clause'],
590
+ ruleset: ['Standard', 'Re-Evolution Mod', 'Evasion Abilities Clause', 'Dynamax Clause'],
591
591
  banlist: [
592
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Genesect', 'Giratina',
593
- 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala',
594
- 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza',
595
- 'Regieleki', 'Reshiram', 'Rillaboom', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta',
596
- 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Magnet Pull', 'Moody', 'Power Construct', 'Shadow Tag', 'TR29 (Baton Pass)',
597
- 'TR82 (Stored Power)', 'Baton Pass',
592
+ 'Darmanitan-Galar', 'Gyarados', 'Lunala', 'Milotic', 'Naganadel', 'Solgaleo', 'Urshifu-Base', 'Volcarona',
593
+ 'Zacian-Crowned', 'Arena Trap', 'Moody', 'Shadow Tag', 'Bright Powder', 'King\'s Rock', 'Lax Incense', 'Baton Pass',
598
594
  ],
599
- onValidateSet(set) {
600
- if (!set.item)
601
- return;
602
- const item = this.dex.items.get(set.item);
603
- if (!/^tr\d\d/i.test(item.name))
604
- return;
605
- const moveName = item.desc.split('move ')[1].split('.')[0];
606
- if (set.moves.map(this.toID).includes(this.toID(moveName))) {
607
- return [
608
- `${set.species} can't run ${item.name} (${moveName}) as its item because it already has that move in its moveset.`,
609
- ];
610
- }
611
- },
612
- onValidateTeam(team) {
613
- const trs = new Set();
614
- for (const set of team) {
615
- if (!set.item)
616
- continue;
617
- const item = this.dex.items.get(set.item).name;
618
- if (!/^tr\d\d/i.test(item))
619
- continue;
620
- if (trs.has(item)) {
621
- return [`Your team already has a Pok\u00e9mon with ${item}.`];
622
- }
623
- trs.add(item);
624
- }
625
- },
626
- onTakeItem(item) {
627
- return !/^tr\d\d/i.test(item.name);
628
- },
629
- onModifyMove(move) {
630
- if (move.id === 'knockoff') {
631
- move.onBasePower = function (basePower, source, target, m) {
632
- const item = target.getItem();
633
- if (!this.singleEvent('TakeItem', item, target.itemState, target, target, m, item))
634
- return;
635
- // Very hardcode but I'd prefer to not make a mod for one damage calculation change
636
- if (item.id && !/^tr\d\d/i.test(item.id)) {
637
- return this.chainModify(1.5);
638
- }
639
- };
640
- }
641
- },
642
- onBegin() {
643
- for (const pokemon of this.getAllPokemon()) {
644
- const item = pokemon.getItem();
645
- if (/^tr\d\d/i.test(item.name)) {
646
- const move = this.dex.moves.get(item.desc.split('move ')[1].split('.')[0]);
647
- pokemon.moveSlots = pokemon.baseMoveSlots = [
648
- ...pokemon.baseMoveSlots, {
649
- id: move.id,
650
- move: move.name,
651
- pp: move.pp * 8 / 5,
652
- maxpp: move.pp * 8 / 5,
653
- target: move.target,
654
- disabled: false,
655
- disabledSource: '',
656
- used: false,
657
- },
658
- ];
659
- }
660
- }
661
- },
662
595
  },
663
596
  {
664
- name: "[Gen 8] Inheritance",
665
- desc: `Pok&eacute;mon may use the ability and moves of another, as long as they forfeit their own learnset.`,
597
+ name: "[Gen 8] Category Swap",
598
+ desc: `All physical moves become special, and all special moves become physical.`,
666
599
  threads: [
667
- `&bullet; <a href="https://www.smogon.com/forums/threads/3656811/">Inheritance</a>`,
600
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3702709/">Category Swap</a>`,
668
601
  ],
669
602
  mod: 'gen8',
670
- // searchShow: false,
671
- ruleset: ['Standard', '!Sleep Clause Mod', 'Sleep Moves Clause', '2 Ability Clause', 'Dynamax Clause'],
603
+ ruleset: ['Standard', 'Dynamax Clause'],
672
604
  banlist: [
673
- 'Blacephalon', 'Blaziken', 'Butterfree', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chansey', 'Combusken', 'Cresselia', 'Darmanitan-Galar', 'Dialga', 'Dracovish',
674
- 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala',
675
- 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Natu', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Regieleki',
676
- 'Regigigas', 'Reshiram', 'Sableye', 'Shedinja', 'Solgaleo', 'Spectrier', 'Tapu Koko', 'Toxtricity', 'Torkoal', 'Urshifu-Base', 'Xatu', 'Xerneas', 'Yveltal',
677
- 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zeraora', 'Zekrom', 'Arena Trap', 'Contrary', 'Drizzle', 'Huge Power', 'Imposter', 'Innards Out',
678
- 'Libero', 'Moody', 'Power Construct', 'Pure Power', 'Quick Draw', 'Shadow Tag', 'Sheer Force', 'Simple', 'Unaware', 'Unburden', 'Water Bubble', 'King\'s Rock',
679
- 'Quick Claw', 'Baton Pass', 'Bolt Beak', 'Fishious Rend', 'Shell Smash', 'Thousand Arrows',
605
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin', 'Groudon',
606
+ 'Ho-Oh', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala', 'Mewtwo', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane',
607
+ 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Solgaleo', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned',
608
+ 'Zekrom', 'Arena Trap', 'Moody', 'Power Construct', 'Shadow Tag', 'King\'s Rock', 'Baton Pass', 'Draco Meteor', 'Overheat',
680
609
  ],
681
- getEvoFamily(speciesid) {
682
- let species = Dex.species.get(speciesid);
683
- while (species.prevo) {
684
- species = Dex.species.get(species.prevo);
685
- }
686
- return species.id;
687
- },
688
- validateSet(set, teamHas) {
689
- const unreleased = (pokemon) => pokemon.tier === "Unreleased" && pokemon.isNonstandard === "Unobtainable";
690
- if (!teamHas.abilityMap) {
691
- teamHas.abilityMap = Object.create(null);
692
- for (const pokemon of Dex.species.all()) {
693
- if (pokemon.isNonstandard || unreleased(pokemon))
694
- continue;
695
- if (pokemon.requiredAbility || pokemon.requiredItem || pokemon.requiredMove)
696
- continue;
697
- if (this.ruleTable.isBannedSpecies(pokemon))
698
- continue;
699
- for (const key of Object.values(pokemon.abilities)) {
700
- const abilityId = this.dex.toID(key);
701
- if (abilityId in teamHas.abilityMap) {
702
- teamHas.abilityMap[abilityId][pokemon.evos ? 'push' : 'unshift'](pokemon.id);
703
- }
704
- else {
705
- teamHas.abilityMap[abilityId] = [pokemon.id];
706
- }
707
- }
708
- }
709
- }
710
- const problem = this.validateForme(set);
711
- if (problem.length)
712
- return problem;
713
- const species = this.dex.species.get(set.species);
714
- if (!species.exists || species.num < 1)
715
- return [`The Pok\u00e9mon "${set.species}" does not exist.`];
716
- if (species.isNonstandard || unreleased(species)) {
717
- return [`${species.name} is not obtainable in Generation ${this.dex.gen}.`];
718
- }
719
- const name = set.name;
720
- if (this.ruleTable.isBannedSpecies(species)) {
721
- return this.validateSet(set, teamHas);
722
- }
723
- const ability = this.dex.abilities.get(set.ability);
724
- if (!ability.exists || ability.isNonstandard)
725
- return [`${name} needs to have a valid ability.`];
726
- const pokemonWithAbility = teamHas.abilityMap[ability.id];
727
- if (!pokemonWithAbility)
728
- return [`${ability.name} is not available on a legal Pok\u00e9mon.`];
729
- this.format.debug = true;
730
- if (!teamHas.abilitySources)
731
- teamHas.abilitySources = Object.create(null);
732
- const validSources = teamHas.abilitySources[this.dex.toID(set.species)] = []; // Evolution families
733
- let canonicalSource = ''; // Specific for the basic implementation of Donor Clause (see onValidateTeam).
734
- for (const donor of pokemonWithAbility) {
735
- const donorSpecies = this.dex.species.get(donor);
736
- let format = this.format;
737
- if (!format.getEvoFamily)
738
- format = this.dex.formats.get('gen8inheritance');
739
- const evoFamily = format.getEvoFamily(donorSpecies.id);
740
- if (validSources.includes(evoFamily))
741
- continue;
742
- set.species = donorSpecies.name;
743
- set.name = donorSpecies.baseSpecies;
744
- const problems = this.validateSet(set, teamHas) || [];
745
- if (!problems.length) {
746
- validSources.push(evoFamily);
747
- canonicalSource = donorSpecies.name;
748
- }
749
- // Specific for the basic implementation of Donor Clause (see onValidateTeam).
750
- if (validSources.length > 1)
751
- break;
752
- }
753
- this.format.debug = false;
754
- set.name = name;
755
- set.species = species.name;
756
- if (!validSources.length) {
757
- if (pokemonWithAbility.length > 1)
758
- return [`${name}'s set is illegal.`];
759
- return [`${name} has an illegal set with an ability from ${this.dex.species.get(pokemonWithAbility[0]).name}.`];
760
- }
761
- // Protocol: Include the data of the donor species in the `ability` data slot.
762
- // Afterwards, we are going to reset the name to what the user intended.
763
- set.ability = `${set.ability}0${canonicalSource}`;
764
- return null;
765
- },
766
- onValidateTeam(team, f, teamHas) {
767
- if (this.ruleTable.has('2abilityclause')) {
768
- const abilityTable = new Map();
769
- const base = {
770
- airlock: 'cloudnine',
771
- battlearmor: 'shellarmor',
772
- clearbody: 'whitesmoke',
773
- dazzling: 'queenlymajesty',
774
- emergencyexit: 'wimpout',
775
- filter: 'solidrock',
776
- gooey: 'tanglinghair',
777
- insomnia: 'vitalspirit',
778
- ironbarbs: 'roughskin',
779
- libero: 'protean',
780
- minus: 'plus',
781
- moxie: 'chillingneigh',
782
- powerofalchemy: 'receiver',
783
- propellertail: 'stalwart',
784
- teravolt: 'moldbreaker',
785
- turboblaze: 'moldbreaker',
786
- };
787
- for (const set of team) {
788
- let ability = this.toID(set.ability.split('0')[0]);
789
- if (!ability)
790
- continue;
791
- if (ability in base)
792
- ability = base[ability];
793
- if ((abilityTable.get(ability) || 0) >= 2) {
794
- return [
795
- `You are limited to two of each ability by 2 Ability Clause.`,
796
- `(You have more than two ${this.dex.abilities.get(ability).name} variants)`,
797
- ];
798
- }
799
- abilityTable.set(ability, (abilityTable.get(ability) || 0) + 1);
800
- }
801
- }
802
- // Donor Clause
803
- const evoFamilyLists = [];
804
- for (const set of team) {
805
- const abilitySources = teamHas.abilitySources?.[this.dex.toID(set.species)];
806
- if (!abilitySources)
807
- continue;
808
- let format = this.format;
809
- if (!format.getEvoFamily)
810
- format = this.dex.formats.get('gen8inheritance');
811
- evoFamilyLists.push(abilitySources.map(format.getEvoFamily));
812
- }
813
- // Checking actual full incompatibility would require expensive algebra.
814
- // Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
815
- const requiredFamilies = Object.create(null);
816
- for (const evoFamilies of evoFamilyLists) {
817
- if (evoFamilies.length !== 1)
818
- continue;
819
- const [familyId] = evoFamilies;
820
- if (!(familyId in requiredFamilies))
821
- requiredFamilies[familyId] = 1;
822
- requiredFamilies[familyId]++;
823
- if (requiredFamilies[familyId] > 2) {
824
- return [
825
- `You are limited to up to two inheritances from each evolution family by the Donor Clause.`,
826
- `(You inherit more than twice from ${this.dex.species.get(familyId).name}).`,
827
- ];
828
- }
610
+ onModifyMove(move) {
611
+ if (move.category === 'Status')
612
+ return;
613
+ if (move.category === 'Special') {
614
+ move.category = 'Physical';
829
615
  }
830
- },
831
- onBegin() {
832
- for (const pokemon of this.getAllPokemon()) {
833
- if (pokemon.baseAbility.includes('0')) {
834
- const donor = pokemon.baseAbility.split('0')[1];
835
- pokemon.m.donor = this.toID(donor);
836
- pokemon.baseAbility = this.toID(pokemon.baseAbility.split('0')[0]);
837
- pokemon.ability = pokemon.baseAbility;
838
- }
616
+ else {
617
+ move.category = 'Special';
839
618
  }
840
619
  },
841
- onSwitchIn(pokemon) {
842
- if (!pokemon.m.donor)
843
- return;
844
- const donorTemplate = this.dex.species.get(pokemon.m.donor);
845
- if (!donorTemplate.exists)
846
- return;
847
- // Place volatiles on the Pokémon to show the donor details.
848
- this.add('-start', pokemon, donorTemplate.name, '[silent]');
849
- },
850
620
  },
851
621
  // Other Metagames
852
622
  ///////////////////////////////////////////////////////////////////
@@ -1007,8 +777,8 @@ exports.Formats = [
1007
777
  mod: 'gen8',
1008
778
  ruleset: ['Standard', 'Dynamax Clause', 'Sleep Moves Clause'],
1009
779
  banlist: [
1010
- 'Blissey', 'Calyrex-Shadow', 'Chansey', 'Crawdaunt', 'Dragapult', 'Eternatus', 'Hawlucha', 'Marowak-Alola', 'Melmetal',
1011
- 'Pikachu', 'Toxapex', 'Xerneas', 'Zacian', 'Zacian-Crowned', 'Uber > 1', 'AG ++ Uber > 1', 'Arena Trap', 'Huge Power',
780
+ 'Blissey', 'Calyrex-Shadow', 'Chansey', 'Crawdaunt', 'Dragapult', 'Eternatus', 'Hawlucha', 'Marowak-Alola', 'Melmetal', 'Nidoking',
781
+ 'Nidoqueen', 'Pikachu', 'Toxapex', 'Xerneas', 'Zacian', 'Zacian-Crowned', 'Uber > 1', 'AG ++ Uber > 1', 'Arena Trap', 'Huge Power',
1012
782
  'Moody', 'Pure Power', 'Shadow Tag', 'Swift Swim', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw',
1013
783
  'Baton Pass',
1014
784
  ],
@@ -1215,16 +985,6 @@ exports.Formats = [
1215
985
  gameType: 'doubles',
1216
986
  ruleset: ['Flat Rules', 'Min Source Gen = 8'],
1217
987
  },
1218
- {
1219
- name: "[Gen 8 BDSP] Pure Hackmons",
1220
- desc: `Anything that can be hacked in-game and is usable in local battles is allowed.`,
1221
- threads: [
1222
- `&bullet; <a href="https://www.smogon.com/forums/threads/3693868/">Pure Hackmons</a>`,
1223
- ],
1224
- mod: 'gen8bdsp',
1225
- searchShow: false,
1226
- ruleset: ['-Nonexistent', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause'],
1227
- },
1228
988
  {
1229
989
  section: "Challengeable OMs",
1230
990
  column: 2,
@@ -1396,6 +1156,195 @@ exports.Formats = [
1396
1156
  }
1397
1157
  },
1398
1158
  },
1159
+ {
1160
+ name: "[Gen 8] Inheritance",
1161
+ desc: `Pok&eacute;mon may use the ability and moves of another, as long as they forfeit their own learnset.`,
1162
+ threads: [
1163
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3656811/">Inheritance</a>`,
1164
+ ],
1165
+ mod: 'gen8',
1166
+ searchShow: false,
1167
+ ruleset: ['Standard', '!Sleep Clause Mod', 'Sleep Moves Clause', '2 Ability Clause', 'Dynamax Clause'],
1168
+ banlist: [
1169
+ 'Blacephalon', 'Blaziken', 'Butterfree', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chansey', 'Combusken', 'Cresselia', 'Darmanitan-Galar', 'Dialga',
1170
+ 'Dracovish', 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Lugia',
1171
+ 'Lunala', 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Natu', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza',
1172
+ 'Regieleki', 'Regigigas', 'Reshiram', 'Sableye', 'Shedinja', 'Solgaleo', 'Spectrier', 'Tapu Koko', 'Toxtricity', 'Torkoal', 'Urshifu-Base',
1173
+ 'Xatu', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zeraora', 'Zekrom', 'Arena Trap', 'Contrary',
1174
+ 'Drizzle', 'Huge Power', 'Imposter', 'Innards Out', 'Libero', 'Moody', 'Power Construct', 'Pure Power', 'Quick Draw', 'Shadow Tag', 'Sheer Force',
1175
+ 'Simple', 'Unaware', 'Unburden', 'Water Bubble', 'King\'s Rock', 'Quick Claw', 'Baton Pass', 'Bolt Beak', 'Fishious Rend', 'Shell Smash',
1176
+ 'Thousand Arrows',
1177
+ ],
1178
+ getEvoFamily(speciesid) {
1179
+ let species = Dex.species.get(speciesid);
1180
+ while (species.prevo) {
1181
+ species = Dex.species.get(species.prevo);
1182
+ }
1183
+ return species.id;
1184
+ },
1185
+ validateSet(set, teamHas) {
1186
+ const unreleased = (pokemon) => pokemon.tier === "Unreleased" && pokemon.isNonstandard === "Unobtainable";
1187
+ if (!teamHas.abilityMap) {
1188
+ teamHas.abilityMap = Object.create(null);
1189
+ for (const pokemon of Dex.species.all()) {
1190
+ if (pokemon.isNonstandard || unreleased(pokemon))
1191
+ continue;
1192
+ if (pokemon.requiredAbility || pokemon.requiredItem || pokemon.requiredMove)
1193
+ continue;
1194
+ if (this.ruleTable.isBannedSpecies(pokemon))
1195
+ continue;
1196
+ for (const key of Object.values(pokemon.abilities)) {
1197
+ const abilityId = this.dex.toID(key);
1198
+ if (abilityId in teamHas.abilityMap) {
1199
+ teamHas.abilityMap[abilityId][pokemon.evos ? 'push' : 'unshift'](pokemon.id);
1200
+ }
1201
+ else {
1202
+ teamHas.abilityMap[abilityId] = [pokemon.id];
1203
+ }
1204
+ }
1205
+ }
1206
+ }
1207
+ const problem = this.validateForme(set);
1208
+ if (problem.length)
1209
+ return problem;
1210
+ const species = this.dex.species.get(set.species);
1211
+ if (!species.exists || species.num < 1)
1212
+ return [`The Pok\u00e9mon "${set.species}" does not exist.`];
1213
+ if (species.isNonstandard || unreleased(species)) {
1214
+ return [`${species.name} is not obtainable in Generation ${this.dex.gen}.`];
1215
+ }
1216
+ const name = set.name;
1217
+ if (this.ruleTable.isBannedSpecies(species)) {
1218
+ return this.validateSet(set, teamHas);
1219
+ }
1220
+ const ability = this.dex.abilities.get(set.ability);
1221
+ if (!ability.exists || ability.isNonstandard)
1222
+ return [`${name} needs to have a valid ability.`];
1223
+ const pokemonWithAbility = teamHas.abilityMap[ability.id];
1224
+ if (!pokemonWithAbility)
1225
+ return [`${ability.name} is not available on a legal Pok\u00e9mon.`];
1226
+ this.format.debug = true;
1227
+ if (!teamHas.abilitySources)
1228
+ teamHas.abilitySources = Object.create(null);
1229
+ const validSources = teamHas.abilitySources[this.dex.toID(set.species)] = []; // Evolution families
1230
+ let canonicalSource = ''; // Specific for the basic implementation of Donor Clause (see onValidateTeam).
1231
+ for (const donor of pokemonWithAbility) {
1232
+ const donorSpecies = this.dex.species.get(donor);
1233
+ let format = this.format;
1234
+ if (!format.getEvoFamily)
1235
+ format = this.dex.formats.get('gen8inheritance');
1236
+ const evoFamily = format.getEvoFamily(donorSpecies.id);
1237
+ if (validSources.includes(evoFamily))
1238
+ continue;
1239
+ set.species = donorSpecies.name;
1240
+ set.name = donorSpecies.baseSpecies;
1241
+ const problems = this.validateSet(set, teamHas) || [];
1242
+ if (!problems.length) {
1243
+ validSources.push(evoFamily);
1244
+ canonicalSource = donorSpecies.name;
1245
+ }
1246
+ // Specific for the basic implementation of Donor Clause (see onValidateTeam).
1247
+ if (validSources.length > 1)
1248
+ break;
1249
+ }
1250
+ this.format.debug = false;
1251
+ set.name = name;
1252
+ set.species = species.name;
1253
+ if (!validSources.length) {
1254
+ if (pokemonWithAbility.length > 1)
1255
+ return [`${name}'s set is illegal.`];
1256
+ return [`${name} has an illegal set with an ability from ${this.dex.species.get(pokemonWithAbility[0]).name}.`];
1257
+ }
1258
+ // Protocol: Include the data of the donor species in the `ability` data slot.
1259
+ // Afterwards, we are going to reset the name to what the user intended.
1260
+ set.ability = `${set.ability}0${canonicalSource}`;
1261
+ return null;
1262
+ },
1263
+ onValidateTeam(team, f, teamHas) {
1264
+ if (this.ruleTable.has('2abilityclause')) {
1265
+ const abilityTable = new Map();
1266
+ const base = {
1267
+ airlock: 'cloudnine',
1268
+ battlearmor: 'shellarmor',
1269
+ clearbody: 'whitesmoke',
1270
+ dazzling: 'queenlymajesty',
1271
+ emergencyexit: 'wimpout',
1272
+ filter: 'solidrock',
1273
+ gooey: 'tanglinghair',
1274
+ insomnia: 'vitalspirit',
1275
+ ironbarbs: 'roughskin',
1276
+ libero: 'protean',
1277
+ minus: 'plus',
1278
+ moxie: 'chillingneigh',
1279
+ powerofalchemy: 'receiver',
1280
+ propellertail: 'stalwart',
1281
+ teravolt: 'moldbreaker',
1282
+ turboblaze: 'moldbreaker',
1283
+ };
1284
+ for (const set of team) {
1285
+ let ability = this.toID(set.ability.split('0')[0]);
1286
+ if (!ability)
1287
+ continue;
1288
+ if (ability in base)
1289
+ ability = base[ability];
1290
+ if ((abilityTable.get(ability) || 0) >= 2) {
1291
+ return [
1292
+ `You are limited to two of each ability by 2 Ability Clause.`,
1293
+ `(You have more than two ${this.dex.abilities.get(ability).name} variants)`,
1294
+ ];
1295
+ }
1296
+ abilityTable.set(ability, (abilityTable.get(ability) || 0) + 1);
1297
+ }
1298
+ }
1299
+ // Donor Clause
1300
+ const evoFamilyLists = [];
1301
+ for (const set of team) {
1302
+ const abilitySources = teamHas.abilitySources?.[this.dex.toID(set.species)];
1303
+ if (!abilitySources)
1304
+ continue;
1305
+ let format = this.format;
1306
+ if (!format.getEvoFamily)
1307
+ format = this.dex.formats.get('gen8inheritance');
1308
+ evoFamilyLists.push(abilitySources.map(format.getEvoFamily));
1309
+ }
1310
+ // Checking actual full incompatibility would require expensive algebra.
1311
+ // Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
1312
+ const requiredFamilies = Object.create(null);
1313
+ for (const evoFamilies of evoFamilyLists) {
1314
+ if (evoFamilies.length !== 1)
1315
+ continue;
1316
+ const [familyId] = evoFamilies;
1317
+ if (!(familyId in requiredFamilies))
1318
+ requiredFamilies[familyId] = 1;
1319
+ requiredFamilies[familyId]++;
1320
+ if (requiredFamilies[familyId] > 2) {
1321
+ return [
1322
+ `You are limited to up to two inheritances from each evolution family by the Donor Clause.`,
1323
+ `(You inherit more than twice from ${this.dex.species.get(familyId).name}).`,
1324
+ ];
1325
+ }
1326
+ }
1327
+ },
1328
+ onBegin() {
1329
+ for (const pokemon of this.getAllPokemon()) {
1330
+ if (pokemon.baseAbility.includes('0')) {
1331
+ const donor = pokemon.baseAbility.split('0')[1];
1332
+ pokemon.m.donor = this.toID(donor);
1333
+ pokemon.baseAbility = this.toID(pokemon.baseAbility.split('0')[0]);
1334
+ pokemon.ability = pokemon.baseAbility;
1335
+ }
1336
+ }
1337
+ },
1338
+ onSwitchIn(pokemon) {
1339
+ if (!pokemon.m.donor)
1340
+ return;
1341
+ const donorTemplate = this.dex.species.get(pokemon.m.donor);
1342
+ if (!donorTemplate.exists)
1343
+ return;
1344
+ // Place volatiles on the Pokémon to show the donor details.
1345
+ this.add('-start', pokemon, donorTemplate.name, '[silent]');
1346
+ },
1347
+ },
1399
1348
  {
1400
1349
  name: "[Gen 8] Linked",
1401
1350
  desc: `The first two moves in a Pok&eacute;mon's moveset are used simultaneously.`,
@@ -1761,6 +1710,16 @@ exports.Formats = [
1761
1710
  pokemon.m.innates = undefined;
1762
1711
  },
1763
1712
  },
1713
+ {
1714
+ name: "[Gen 8] Pure Hackmons",
1715
+ desc: `Anything that can be hacked in-game and is usable in local battles is allowed.`,
1716
+ threads: [
1717
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3656851/">Pure Hackmons</a>`,
1718
+ ],
1719
+ mod: 'gen8',
1720
+ searchShow: false,
1721
+ ruleset: ['-Nonexistent', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause'],
1722
+ },
1764
1723
  {
1765
1724
  name: "[Gen 8] Shared Power",
1766
1725
  desc: `Once a Pok&eacute;mon switches in, its ability is shared with the rest of the team.`,
@@ -2377,44 +2336,36 @@ exports.Formats = [
2377
2336
  column: 3,
2378
2337
  },
2379
2338
  {
2380
- name: "[Gen 2] Ubers",
2339
+ name: "[Gen 3] Ubers",
2381
2340
  threads: [
2382
- `&bullet; <a href="https://www.smogon.com/forums/posts/8286282/">GSC Ubers</a>`,
2341
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8286280/">ADV Ubers</a>`,
2383
2342
  ],
2384
- mod: 'gen2',
2343
+ mod: 'gen3',
2385
2344
  // searchShow: false,
2386
- ruleset: ['Standard'],
2345
+ ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
2346
+ banlist: ['Wobbuffet + Leftovers'],
2387
2347
  },
2388
2348
  {
2389
- name: "[Gen 3] 1v1",
2390
- desc: `Bring three Pok&eacute;mon to Team Preview and choose one to battle.`,
2349
+ name: "[Gen 5] RU",
2391
2350
  threads: [
2392
- `&bullet; <a href="https://www.smogon.com/forums/posts/8031456/">ADV 1v1</a>`,
2351
+ `&bullet; <a href="https://www.smogon.com/forums/posts/6431094/">BW2 Sample Teams</a>`,
2352
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3473124/">BW2 RU Viability Rankings</a>`,
2393
2353
  ],
2394
- mod: 'gen3',
2354
+ mod: 'gen5',
2395
2355
  // searchShow: false,
2396
- ruleset: [
2397
- 'Picked Team Size = 1', 'Max Team Size = 3',
2398
- '[Gen 3] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview', '!Freeze Clause Mod',
2399
- ],
2400
- banlist: [
2401
- 'Clefable', 'Slaking', 'Snorlax', 'Suicune', 'Zapdos', 'Destiny Bond', 'Explosion', 'Ingrain', 'Perish Song',
2402
- 'Self-Destruct', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw',
2403
- ],
2404
- unbanlist: ['Mr. Mime', 'Wobbuffet', 'Wynaut', 'Sand Veil'],
2356
+ ruleset: ['[Gen 5] UU', 'Baton Pass Clause', '!Sleep Clause Mod', 'Sleep Moves Clause'],
2357
+ banlist: ['UU', 'RUBL', 'Shadow Tag', 'Shell Smash + Baton Pass'],
2358
+ unbanlist: ['Prankster + Assist', 'Prankster + Copycat', 'Baton Pass'],
2405
2359
  },
2406
2360
  {
2407
- name: "[Gen 1] Stadium OU",
2361
+ name: "[Gen 7 Let's Go] UU",
2408
2362
  threads: [
2409
- `&bullet; <a href="https://www.smogon.com/forums/threads/3685877/">Stadium OU Viability Rankings</a>`,
2363
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3659882/">LGPE UU Metagame Discussion &amp; Resources</a>`,
2410
2364
  ],
2411
- mod: 'gen1stadium',
2365
+ mod: 'gen7letsgo',
2412
2366
  // searchShow: false,
2413
- ruleset: ['Standard', 'Team Preview'],
2414
- banlist: ['Uber',
2415
- 'Nidoking + Fury Attack + Thrash', 'Exeggutor + Poison Powder + Stomp', 'Exeggutor + Sleep Powder + Stomp',
2416
- 'Exeggutor + Stun Spore + Stomp', 'Jolteon + Focus Energy + Thunder Shock', 'Flareon + Focus Energy + Ember',
2417
- ],
2367
+ ruleset: ['[Gen 7 Let\'s Go] OU'],
2368
+ banlist: ['OU', 'UUBL'],
2418
2369
  },
2419
2370
  // Past Gens OU
2420
2371
  ///////////////////////////////////////////////////////////////////
@@ -3199,18 +3150,6 @@ exports.Formats = [
3199
3150
  ruleset: ['Standard', 'Evasion Abilities Clause', 'Swagger Clause', 'Sleep Clause Mod'],
3200
3151
  banlist: ['Uber', 'OU', 'UUBL', 'Arena Trap', 'Drought', 'Sand Stream', 'Snow Warning', 'Prankster + Assist', 'Prankster + Copycat', 'Baton Pass'],
3201
3152
  },
3202
- {
3203
- name: "[Gen 5] RU",
3204
- threads: [
3205
- `&bullet; <a href="https://www.smogon.com/forums/posts/6431094/">BW2 Sample Teams</a>`,
3206
- `&bullet; <a href="https://www.smogon.com/forums/threads/3473124/">BW2 RU Viability Rankings</a>`,
3207
- ],
3208
- mod: 'gen5',
3209
- searchShow: false,
3210
- ruleset: ['[Gen 5] UU', 'Baton Pass Clause', '!Sleep Clause Mod', 'Sleep Moves Clause'],
3211
- banlist: ['UU', 'RUBL', 'Shadow Tag', 'Shell Smash + Baton Pass'],
3212
- unbanlist: ['Prankster + Assist', 'Prankster + Copycat', 'Baton Pass'],
3213
- },
3214
3153
  {
3215
3154
  name: "[Gen 5] NU",
3216
3155
  threads: [
@@ -3280,6 +3219,7 @@ exports.Formats = [
3280
3219
  searchShow: false,
3281
3220
  ruleset: ['[Gen 5] PU'],
3282
3221
  banlist: ['PU', 'Articuno', 'Dragonair', 'Glalie', 'Machoke', 'Marowak', 'Omanyte', 'Regigigas', 'Trubbish', 'Whirlipede', 'Baton Pass'],
3222
+ unbanlist: ['Damp Rock'],
3283
3223
  },
3284
3224
  {
3285
3225
  name: "[Gen 5] GBU Singles",
@@ -3461,7 +3401,7 @@ exports.Formats = [
3461
3401
  ruleset: ['[Gen 4] PU'],
3462
3402
  banlist: [
3463
3403
  'Ampharos', 'Armaldo', 'Bellossom', 'Dragonair', 'Electabuzz', 'Gabite', 'Gastrodon', 'Glaceon', 'Glalie',
3464
- 'Golduck', 'Gorebyss', 'Hippopotas', 'Kadabra', 'Machoke', 'Magmar', 'Mantine', 'Marowak', 'Metang',
3404
+ 'Golduck', 'Gorebyss', 'Hippopotas', 'Kadabra', 'Lapras', 'Machoke', 'Magmar', 'Mantine', 'Marowak', 'Metang',
3465
3405
  'Misdreavus', 'Monferno', 'Mr. Mime', 'Muk', 'Murkrow', 'Pinsir', 'Politoed', 'Purugly', 'Quagsire',
3466
3406
  'Raichu', 'Rampardos', 'Rapidash', 'Regigigas', 'Relicanth', 'Rhydon', 'Scyther', 'Sneasel', 'Snover',
3467
3407
  'Solrock', 'Tangela', 'Torkoal', 'Victreebel', 'Xatu', 'Zangoose', 'Damp Rock',
@@ -3525,16 +3465,6 @@ exports.Formats = [
3525
3465
  section: "Past Generations",
3526
3466
  column: 5,
3527
3467
  },
3528
- {
3529
- name: "[Gen 3] Ubers",
3530
- threads: [
3531
- `&bullet; <a href="https://www.smogon.com/forums/posts/8286280/">ADV Ubers</a>`,
3532
- ],
3533
- mod: 'gen3',
3534
- searchShow: false,
3535
- ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
3536
- banlist: ['Wobbuffet + Leftovers'],
3537
- },
3538
3468
  {
3539
3469
  name: "[Gen 3] UU",
3540
3470
  threads: [
@@ -3556,6 +3486,24 @@ exports.Formats = [
3556
3486
  ruleset: ['Standard'],
3557
3487
  banlist: ['Uber', 'OU', 'UUBL', 'UU', 'Smeargle + Ingrain'],
3558
3488
  },
3489
+ {
3490
+ name: "[Gen 3] 1v1",
3491
+ desc: `Bring three Pok&eacute;mon to Team Preview and choose one to battle.`,
3492
+ threads: [
3493
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8031456/">ADV 1v1</a>`,
3494
+ ],
3495
+ mod: 'gen3',
3496
+ searchShow: false,
3497
+ ruleset: [
3498
+ 'Picked Team Size = 1', 'Max Team Size = 3',
3499
+ '[Gen 3] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview', '!Freeze Clause Mod',
3500
+ ],
3501
+ banlist: [
3502
+ 'Clefable', 'Slaking', 'Snorlax', 'Suicune', 'Zapdos', 'Destiny Bond', 'Explosion', 'Ingrain', 'Perish Song',
3503
+ 'Self-Destruct', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw',
3504
+ ],
3505
+ unbanlist: ['Mr. Mime', 'Wobbuffet', 'Wynaut', 'Sand Veil'],
3506
+ },
3559
3507
  {
3560
3508
  name: "[Gen 3] Doubles OU",
3561
3509
  threads: [
@@ -3584,6 +3532,15 @@ exports.Formats = [
3584
3532
  debug: true,
3585
3533
  ruleset: ['HP Percentage Mod', 'Cancel Mod', 'Max Team Size = 24', 'Max Move Count = 24', 'Max Level = 9999', 'Default Level = 100'],
3586
3534
  },
3535
+ {
3536
+ name: "[Gen 2] Ubers",
3537
+ threads: [
3538
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8286282/">GSC Ubers</a>`,
3539
+ ],
3540
+ mod: 'gen2',
3541
+ searchShow: false,
3542
+ ruleset: ['Standard'],
3543
+ },
3587
3544
  {
3588
3545
  name: "[Gen 2] UU",
3589
3546
  threads: [`&bullet; <a href="https://www.smogon.com/forums/threads/3576710/">GSC UU</a>`],
@@ -3591,6 +3548,7 @@ exports.Formats = [
3591
3548
  searchShow: false,
3592
3549
  ruleset: ['[Gen 2] OU'],
3593
3550
  banlist: ['OU', 'UUBL'],
3551
+ unbanlist: ['Mean Look + Baton Pass', 'Spider Web + Baton Pass'],
3594
3552
  },
3595
3553
  {
3596
3554
  name: "[Gen 2] NU",
@@ -3673,7 +3631,7 @@ exports.Formats = [
3673
3631
  ],
3674
3632
  mod: 'gen1',
3675
3633
  searchShow: false,
3676
- ruleset: ['[Gen 1] UU'],
3634
+ ruleset: ['[Gen 1] UU', '!APT Clause'],
3677
3635
  banlist: ['UU', 'NUBL'],
3678
3636
  },
3679
3637
  {
@@ -3697,6 +3655,19 @@ exports.Formats = [
3697
3655
  ],
3698
3656
  banlist: ['Uber'],
3699
3657
  },
3658
+ {
3659
+ name: "[Gen 1] Stadium OU",
3660
+ threads: [
3661
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3685877/">Stadium OU Viability Rankings</a>`,
3662
+ ],
3663
+ mod: 'gen1stadium',
3664
+ searchShow: false,
3665
+ ruleset: ['Standard', 'Team Preview'],
3666
+ banlist: ['Uber',
3667
+ 'Nidoking + Fury Attack + Thrash', 'Exeggutor + Poison Powder + Stomp', 'Exeggutor + Sleep Powder + Stomp',
3668
+ 'Exeggutor + Stun Spore + Stomp', 'Jolteon + Focus Energy + Thunder Shock', 'Flareon + Focus Energy + Ember',
3669
+ ],
3670
+ },
3700
3671
  {
3701
3672
  name: "[Gen 1] Tradebacks OU",
3702
3673
  desc: `RBY OU with movepool additions from the Time Capsule.`,