@pkmn/sim 0.4.19 → 0.4.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 (88) hide show
  1. package/build/config/formats.js +752 -743
  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 +4 -1
  6. package/build/data/conditions.js.map +1 -1
  7. package/build/data/formats-data.js +27 -27
  8. package/build/data/formats-data.js.map +1 -1
  9. package/build/data/learnsets.js +10 -10
  10. package/build/data/learnsets.js.map +1 -1
  11. package/build/data/mods/gen1/moves.js +1 -1
  12. package/build/data/mods/gen1/moves.js.map +1 -1
  13. package/build/data/mods/gen1/scripts.js +18 -22
  14. package/build/data/mods/gen1/scripts.js.map +1 -1
  15. package/build/data/mods/gen2/scripts.js +16 -23
  16. package/build/data/mods/gen2/scripts.js.map +1 -1
  17. package/build/data/mods/gen3/moves.js +2 -1
  18. package/build/data/mods/gen3/moves.js.map +1 -1
  19. package/build/data/mods/gen4/conditions.js +6 -0
  20. package/build/data/mods/gen4/conditions.js.map +1 -1
  21. package/build/data/mods/gen4/moves.js +2 -1
  22. package/build/data/mods/gen4/moves.js.map +1 -1
  23. package/build/data/mods/gen4/scripts.js +2 -1
  24. package/build/data/mods/gen4/scripts.js.map +1 -1
  25. package/build/data/mods/gen6/conditions.js +4 -1
  26. package/build/data/mods/gen6/conditions.js.map +1 -1
  27. package/build/data/mods/gen7/formats-data.js +2 -2
  28. package/build/data/mods/gen7/formats-data.js.map +1 -1
  29. package/build/data/mods/gen7/moves.js +8 -0
  30. package/build/data/mods/gen7/moves.js.map +1 -1
  31. package/build/data/moves.js +26 -14
  32. package/build/data/moves.js.map +1 -1
  33. package/build/data/rulesets.js +258 -16
  34. package/build/data/rulesets.js.map +1 -1
  35. package/build/data/tags.js +3 -3
  36. package/build/data/tags.js.map +1 -1
  37. package/build/lib/streams.d.ts +1 -199
  38. package/build/lib/streams.js +11 -772
  39. package/build/lib/streams.js.map +1 -1
  40. package/build/sim/battle-actions.d.ts +1 -1
  41. package/build/sim/battle-actions.js +18 -42
  42. package/build/sim/battle-actions.js.map +1 -1
  43. package/build/sim/battle.d.ts +1 -0
  44. package/build/sim/battle.js +5 -0
  45. package/build/sim/battle.js.map +1 -1
  46. package/build/sim/dex-moves.d.ts +31 -11
  47. package/build/sim/dex-moves.js +4 -3
  48. package/build/sim/dex-moves.js.map +1 -1
  49. package/build/sim/dex-species.js +11 -1
  50. package/build/sim/dex-species.js.map +1 -1
  51. package/build/sim/exported-global-types.d.ts +4 -0
  52. package/build/sim/global-types.d.ts +4 -0
  53. package/build/sim/pokemon.js +1 -1
  54. package/build/sim/pokemon.js.map +1 -1
  55. package/build/sim/side.js +2 -2
  56. package/build/sim/side.js.map +1 -1
  57. package/build/sim/team-validator.d.ts +4 -0
  58. package/build/sim/team-validator.js +37 -11
  59. package/build/sim/team-validator.js.map +1 -1
  60. package/config/formats.ts +649 -630
  61. package/data/aliases.ts +4 -4
  62. package/data/conditions.ts +4 -1
  63. package/data/formats-data.ts +27 -27
  64. package/data/learnsets.ts +10 -10
  65. package/data/mods/gen1/moves.ts +1 -1
  66. package/data/mods/gen1/scripts.ts +23 -19
  67. package/data/mods/gen2/scripts.ts +20 -19
  68. package/data/mods/gen3/moves.ts +2 -1
  69. package/data/mods/gen4/conditions.ts +6 -0
  70. package/data/mods/gen4/moves.ts +2 -1
  71. package/data/mods/gen4/scripts.ts +1 -1
  72. package/data/mods/gen6/conditions.ts +4 -1
  73. package/data/mods/gen7/formats-data.ts +2 -2
  74. package/data/mods/gen7/moves.ts +8 -0
  75. package/data/moves.ts +23 -14
  76. package/data/rulesets.ts +235 -16
  77. package/data/tags.ts +3 -3
  78. package/lib/streams.ts +1 -874
  79. package/package.json +4 -3
  80. package/sim/battle-actions.ts +19 -40
  81. package/sim/battle.ts +6 -0
  82. package/sim/dex-moves.ts +35 -13
  83. package/sim/dex-species.ts +10 -1
  84. package/sim/exported-global-types.ts +4 -0
  85. package/sim/global-types.ts +4 -0
  86. package/sim/pokemon.ts +1 -1
  87. package/sim/side.ts +2 -2
  88. package/sim/team-validator.ts +41 -10
package/config/formats.ts CHANGED
@@ -55,6 +55,13 @@ export const Formats: FormatList = [
55
55
  rated: false,
56
56
  ruleset: ['Obtainable', 'Species Clause', 'HP Percentage Mod', 'Cancel Mod', 'Sleep Clause Mod'],
57
57
  },
58
+ {
59
+ name: "[Gen 8] Random Battle (Blitz)",
60
+
61
+ mod: 'gen8',
62
+ team: 'random',
63
+ ruleset: ['[Gen 8] Random Battle', 'Blitz'],
64
+ },
58
65
  {
59
66
  name: "[Gen 8] Multi Random Battle",
60
67
 
@@ -236,9 +243,9 @@ export const Formats: FormatList = [
236
243
  ruleset: ['[Gen 8] LC'],
237
244
  banlist: [
238
245
  // LC OU
239
- 'Abra', 'Archen', 'Carvanha', 'Dewpider', 'Diglett-Base', 'Dwebble', 'Ferroseed', 'Foongus', 'Frillish', 'Grookey',
240
- 'Koffing', 'Larvesta', 'Magnemite', 'Mareanie', 'Mienfoo', 'Mudbray', 'Munchlax', 'Natu', 'Onix', 'Pawniard', 'Ponyta',
241
- 'Ponyta-Galar', 'Porygon', 'Slowpoke', 'Spritzee', 'Staryu', 'Timburr', 'Trapinch', 'Tyrunt', 'Vulpix',
246
+ 'Abra', 'Archen', 'Carvanha', 'Diglett-Base', 'Dwebble', 'Ferroseed', 'Foongus', 'Frillish', 'Grookey', 'Koffing',
247
+ 'Larvesta', 'Magnemite', 'Mareanie', 'Mienfoo', 'Mudbray', 'Munchlax', 'Natu', 'Onix', 'Pawniard', 'Ponyta',
248
+ 'Ponyta-Galar', 'Porygon', 'Slowpoke-Base', 'Spritzee', 'Staryu', 'Timburr', 'Trapinch', 'Tyrunt', 'Vulpix',
242
249
  // LC UUBL
243
250
  'Farfetch\u2019d-Galar', 'Scorbunny', 'Shellder', 'Wingull',
244
251
  ],
@@ -255,11 +262,23 @@ export const Formats: FormatList = [
255
262
  ruleset: ['[Gen 8] OU', '+CAP'],
256
263
  banlist: ['Crucibellite'],
257
264
  },
265
+ {
266
+ name: "[Gen 8] CAP LC",
267
+ threads: [
268
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3691918/">CAP LC Metagame Discussion</a>`,
269
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8997714/">CAP LC Sample Teams</a>`,
270
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8997713/">CAP LC Viability Rankings</a>`,
271
+ ],
272
+
273
+ mod: 'gen8',
274
+ searchShow: false,
275
+ ruleset: ['[Gen 8] LC', '+CAP'],
276
+ },
258
277
  {
259
278
  name: "[Gen 8] Battle Stadium Singles",
260
279
 
261
280
  mod: 'gen8',
262
- ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'Limit One Restricted', 'Dynamax Clause'],
281
+ ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'Limit One Restricted'],
263
282
  restricted: ['Restricted Legendary'],
264
283
  },
265
284
  {
@@ -346,16 +365,11 @@ export const Formats: FormatList = [
346
365
  banlist: ['Corsola-Galar', 'Cutiefly', 'Ponyta-Base', 'Scyther', 'Sneasel', 'Swirlix', 'Tangela', 'Vulpix', 'Vulpix-Alola'],
347
366
  },
348
367
  {
349
- name: "[Gen 8] VGC 2021 Series 10",
350
- threads: [
351
- `&bullet; <a href="https://www.smogon.com/forums/threads/3677186/">VGC 2021 Series 10 Metagame Discussion</a>`,
352
- `&bullet; <a href="https://www.smogon.com/forums/threads/3689153/">VGC 2021 Series 10 Sample Teams</a>`,
353
- `&bullet; <a href="https://www.smogon.com/forums/threads/3688166/">VGC 2021 Series 10 Viability Rankings</a>`,
354
- ],
368
+ name: "[Gen 8] VGC 2021 Series 11",
355
369
 
356
370
  mod: 'gen8',
357
371
  gameType: 'doubles',
358
- ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'VGC Timer', 'Limit One Restricted', 'Dynamax Clause'],
372
+ ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'VGC Timer', 'Limit One Restricted'],
359
373
  restricted: ['Restricted Legendary'],
360
374
  },
361
375
  {
@@ -374,31 +388,6 @@ export const Formats: FormatList = [
374
388
  searchShow: false,
375
389
  ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'VGC Timer'],
376
390
  },
377
- {
378
- name: "[Gen 8] Spooky Cup 2021",
379
-
380
- mod: 'gen8',
381
- gameType: 'doubles',
382
- ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8'],
383
- onValidateSet(set) {
384
- const spookyMonsList = [
385
- 'Vileplume', 'Tentacruel', 'Gengar', 'Marowak', 'Weezing', 'Mr. Mime', 'Pinsir', 'Ditto', 'Omastar', 'Kabutops', 'Aerodactyl',
386
- 'Noctowl', 'Crobat', 'Espeon', 'Umbreon', 'Wobbuffet', 'Shiftry', 'Shedinja', 'Exploud', 'Sableye', 'Mawile', 'Sharpedo',
387
- 'Lunatone', 'Crawdaunt', 'Baltoy', 'Claydol', 'Absol', 'Glalie', 'Drifblim', 'Skuntank', 'Spiritomb', 'Drapion', 'Toxicroak',
388
- 'Abomasnow', 'Weavile', 'Tangrowth', 'Electivire', 'Magmortar', 'Dusknoir', 'Froslass', 'Rotom', 'Liepard', 'Gigalith',
389
- 'Swoobat', 'Scolipede', 'Basculin', 'Krookodile', 'Sigilyph', 'Cofagrigus', 'Garbodor', 'Zoroark', 'Gothitelle', 'Jellicent',
390
- 'Galvantula', 'Beheeyem', 'Chandelure', 'Golurk', 'Bisharp', 'Mandibuzz', 'Hydreigon', 'Volcarona', 'Pangoro', 'Meowstic',
391
- 'Aegislash', 'Slurpuff', 'Malamar', 'Trevenant', 'Gourgeist', 'Noivern', 'Decidueye', 'Incineroar', 'Toxapex', 'Araquanid',
392
- 'Shiinotic', 'Salazzle', 'Bewear', 'Golisopod', 'Palossand', 'Silvally', 'Mimikyu', 'Dhelmise', 'Nihilego', 'Xurkitree',
393
- 'Guzzlord', 'Poipole', 'Naganadel', 'Blacephalon', 'Corviknight', 'Orbeetle', 'Thievul', 'Coalossal', 'Centiskorch', 'Grapploct',
394
- 'Polteageist', 'Hatterene', 'Grimmsnarl', 'Obstagoon', 'Cursola', 'Mr. Rime', 'Runerigus', 'Dracovish', 'Dragapult', 'Spectrier',
395
- ];
396
- const species = this.dex.species.get(set.species);
397
- if (!spookyMonsList.includes(species.baseSpecies) && species.id !== 'lycanrocmidnight') {
398
- return [`${species.name} is banned for not looking spooky enough.`];
399
- }
400
- },
401
- },
402
391
  {
403
392
  name: "[Gen 8] 2v2 Doubles",
404
393
  desc: `Double battle where you bring four Pok&eacute;mon to Team Preview and choose only two.`,
@@ -523,11 +512,10 @@ export const Formats: FormatList = [
523
512
  ],
524
513
  // Used to distinguish UU from below UU in the client
525
514
  restricted: [
526
- 'Absol-Mega', 'Aegislash', 'Aggron-Mega', 'Altaria-Mega', 'Amoonguss', 'Beedrill-Mega', 'Bisharp', 'Breloom', 'Buzzwole', 'Celesteela',
527
- 'Chesnaught', 'Crobat', 'Donphan', 'Dragonite', 'Hippowdon', 'Honchkrow', 'Hoopa-Unbound', 'Infernape', 'Jirachi', 'Keldeo', 'Krookodile',
528
- 'Mamoswine', 'Mandibuzz', 'Manectric-Mega', 'Melmetal', 'Mew', 'Mienshao', 'Moltres-Base', 'Nihilego', 'Porygon2', 'Regieleki', 'Ribombee',
529
- 'Rotom-Heat', 'Rotom-Wash', 'Sableye-Mega', 'Scizor', 'Shuckle', 'Skarmory', 'Slowking', 'Slowking-Galar', 'Staraptor', 'Swampert', 'Tangrowth',
530
- 'Umbreon', 'Urshifu-Rapid-Strike',
515
+ 'Absol-Mega', 'Aegislash', 'Alomomola', 'Altaria-Mega', 'Amoonguss', 'Beedrill-Mega', 'Bisharp', 'Breloom', 'Celesteela',
516
+ 'Donphan', 'Dragonite', 'Hippowdon', 'Infernape', 'Keldeo', 'Krookodile', 'Mandibuzz', 'Manectric-Mega', 'Melmetal', 'Mew',
517
+ 'Moltres-Base', 'Porygon2', 'Regieleki', 'Rotom-Heat', 'Rotom-Wash', 'Scizor', 'Skarmory', 'Slowking', 'Slowking-Galar',
518
+ 'Swampert-Base', 'Tangrowth', 'Umbreon', 'Urshifu-Rapid-Strike',
531
519
  ],
532
520
  },
533
521
  {
@@ -544,8 +532,8 @@ export const Formats: FormatList = [
544
532
  'Arceus', 'Blastoise-Mega', 'Blaziken', 'Calyrex-Ice', 'Calyrex-Shadow', 'Darkrai', 'Deoxys-Base', 'Deoxys-Attack', 'Dialga', 'Dracovish', 'Dragapult',
545
533
  'Eternatus', 'Genesect', 'Gengar-Mega', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Hoopa-Unbound', 'Kangaskhan-Mega', 'Kartana', 'Kyogre',
546
534
  'Kyurem-Black', 'Kyurem-White', 'Lucario-Mega', 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Mawile-Mega', 'Medicham-Mega', 'Metagross-Mega', 'Mewtwo',
547
- 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Salamence-Mega', 'Shaymin-Sky', 'Solgaleo',
548
- 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base',
535
+ 'Moltres-Galar', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Salamence-Mega', 'Shaymin-Sky',
536
+ 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base',
549
537
  'Battle Bond', 'Moody', 'Power Construct', 'Shadow Tag',
550
538
  'Bright Powder', 'Damp Rock', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw', 'Smooth Rock', 'Terrain Extender', 'Baton Pass',
551
539
  ],
@@ -573,6 +561,7 @@ export const Formats: FormatList = [
573
561
  ],
574
562
 
575
563
  mod: "fusionevolutionuu",
564
+ searchShow: false,
576
565
  ruleset: ['Standard NatDex', 'OHKO Clause', 'Evasion Moves Clause', 'Species Clause', 'Dynamax Clause', 'Sleep Clause Mod', 'Z-Move Clause', 'Data Mod', 'Mega Data Mod'],
577
566
  banlist: [
578
567
  'All Pokemon', 'Lopunnite', 'Tapu Lop-Mega', 'Red Orb', 'Grousle-Primal',
@@ -619,241 +608,45 @@ export const Formats: FormatList = [
619
608
  column: 2,
620
609
  },
621
610
  {
622
- name: "[Gen 8] Inheritance",
623
- desc: `Pok&eacute;mon may use the ability and moves of another, as long as they forfeit their own learnset.`,
611
+ name: "[Gen 8] Sketchmons",
612
+ desc: `Pok&eacute;mon can learn one of any move they don't normally learn, barring the few that are banned.`,
624
613
  threads: [
625
- `&bullet; <a href="https://www.smogon.com/forums/threads/3656811/">Inheritance</a>`,
614
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3680298/">Sketchmons</a>`,
626
615
  ],
627
616
 
628
617
  mod: 'gen8',
629
- // searchShow: false,
630
- ruleset: ['Standard', '2 Ability Clause', 'Dynamax Clause'],
618
+ ruleset: ['Standard', 'Dynamax Clause', 'Sketchmons Move Legality'],
631
619
  banlist: [
632
- 'Blacephalon', 'Blaziken', 'Butterfree', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chansey', 'Combusken', 'Cresselia', 'Darmanitan-Galar', 'Dialga', 'Dracovish',
633
- 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala',
634
- 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Natu', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Regieleki',
635
- 'Regigigas', 'Reshiram', 'Sableye', 'Shedinja', 'Solgaleo', 'Spectrier', 'Tapu Koko', 'Toxtricity', 'Torkoal', 'Urshifu-Base', 'Xatu', 'Xerneas', 'Yveltal',
636
- 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zeraora', 'Zekrom', 'Arena Trap', 'Contrary', 'Drizzle', 'Huge Power', 'Imposter', 'Innards Out',
637
- 'Libero', 'Moody', 'Power Construct', 'Pure Power', 'Quick Draw', 'Shadow Tag', 'Sheer Force', 'Simple', 'Unaware', 'Unburden', 'Water Bubble', 'King\'s Rock',
638
- 'Quick Claw', 'Baton Pass', 'Bolt Beak', 'Fishious Rend', 'Shell Smash', 'Thousand Arrows',
620
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Genesect',
621
+ 'Giratina', 'Giratina-Origin', 'Groudon', 'Hawlucha', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base',
622
+ 'Lugia', 'Lunala', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa',
623
+ 'Porygon-Z', 'Rayquaza', 'Regieleki', 'Reshiram', 'Rillaboom', 'Shedinja', 'Solgaleo', 'Spectrier', 'Swoobat', 'Tapu Bulu',
624
+ 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zeraora', 'Zygarde-Base',
625
+ 'Arena Trap', 'Moody', 'Power Construct', 'Sand Rush', 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
626
+ ],
627
+ restricted: [
628
+ 'Acupressure', 'Astral Barrage', 'Belly Drum', 'Bolt Beak', 'Clangorous Soul', 'Double Iron Bash', 'Electrify', 'Extreme Speed',
629
+ 'Fishious Rend', 'Geomancy', 'Glacial Lance', 'Lovely Kiss', 'No Retreat', 'Oblivion Wing', 'Octolock', 'Quiver Dance', 'Secret Sword',
630
+ 'Shell Smash', 'Shift Gear', 'Sleep Powder', 'Spore', 'Thousand Arrows', 'Transform', 'V-create', 'Wicked Blow',
639
631
  ],
640
- getEvoFamily(speciesid) {
641
- let species = Dex.species.get(speciesid);
642
- while (species.prevo) {
643
- species = Dex.species.get(species.prevo);
644
- }
645
- return species.id;
646
- },
647
- validateSet(set, teamHas) {
648
- const unreleased = (pokemon: Species) => pokemon.tier === "Unreleased" && pokemon.isNonstandard === "Unobtainable";
649
- if (!teamHas.abilityMap) {
650
- teamHas.abilityMap = Object.create(null);
651
- for (const pokemon of Dex.species.all()) {
652
- if (pokemon.isNonstandard || unreleased(pokemon)) continue;
653
- if (pokemon.requiredAbility || pokemon.requiredItem || pokemon.requiredMove) continue;
654
- if (this.ruleTable.isBannedSpecies(pokemon)) continue;
655
-
656
- for (const key of Object.values(pokemon.abilities)) {
657
- const abilityId = this.dex.toID(key);
658
- if (abilityId in teamHas.abilityMap) {
659
- teamHas.abilityMap[abilityId][pokemon.evos ? 'push' : 'unshift'](pokemon.id);
660
- } else {
661
- teamHas.abilityMap[abilityId] = [pokemon.id];
662
- }
663
- }
664
- }
665
- }
666
-
667
- const problem = this.validateForme(set);
668
- if (problem.length) return problem;
669
-
670
- const species = this.dex.species.get(set.species);
671
- if (!species.exists || species.num < 1) return [`The Pok\u00e9mon "${set.species}" does not exist.`];
672
- if (species.isNonstandard || unreleased(species)) {
673
- return [`${species.name} is not obtainable in Generation ${this.dex.gen}.`];
674
- }
675
-
676
- const name = set.name;
677
- if (this.ruleTable.isBannedSpecies(species)) {
678
- return this.validateSet(set, teamHas);
679
- }
680
-
681
- const ability = this.dex.abilities.get(set.ability);
682
- if (!ability.exists || ability.isNonstandard) return [`${name} needs to have a valid ability.`];
683
- const pokemonWithAbility = teamHas.abilityMap[ability.id];
684
- if (!pokemonWithAbility) return [`${ability.name} is not available on a legal Pok\u00e9mon.`];
685
-
686
- (this.format as any).debug = true;
687
-
688
- if (!teamHas.abilitySources) teamHas.abilitySources = Object.create(null);
689
- const validSources: string[] = teamHas.abilitySources[this.dex.toID(set.species)] = []; // Evolution families
690
-
691
- let canonicalSource = ''; // Specific for the basic implementation of Donor Clause (see onValidateTeam).
692
-
693
- for (const donor of pokemonWithAbility) {
694
- const donorSpecies = this.dex.species.get(donor);
695
- let format = this.format;
696
- if (!format.getEvoFamily) format = this.dex.formats.get('gen8inheritance');
697
- const evoFamily = format.getEvoFamily!(donorSpecies.id);
698
- if (validSources.includes(evoFamily)) continue;
699
-
700
- set.species = donorSpecies.name;
701
- set.name = donorSpecies.baseSpecies;
702
- const problems = this.validateSet(set, teamHas) || [];
703
- if (!problems.length) {
704
- validSources.push(evoFamily);
705
- canonicalSource = donorSpecies.name;
706
- }
707
- // Specific for the basic implementation of Donor Clause (see onValidateTeam).
708
- if (validSources.length > 1) break;
709
- }
710
- (this.format as any).debug = false;
711
-
712
- set.name = name;
713
- set.species = species.name;
714
- if (!validSources.length) {
715
- if (pokemonWithAbility.length > 1) return [`${name}'s set is illegal.`];
716
- return [`${name} has an illegal set with an ability from ${this.dex.species.get(pokemonWithAbility[0]).name}.`];
717
- }
718
-
719
- // Protocol: Include the data of the donor species in the `ability` data slot.
720
- // Afterwards, we are going to reset the name to what the user intended.
721
- set.ability = `${set.ability}0${canonicalSource}`;
722
- return null;
723
- },
724
- onValidateTeam(team, f, teamHas) {
725
- if (this.format.ruleTable?.has('2abilityclause')) {
726
- const abilityTable = new Map<string, number>();
727
- const base: {[k: string]: string} = {
728
- airlock: 'cloudnine',
729
- battlearmor: 'shellarmor',
730
- clearbody: 'whitesmoke',
731
- dazzling: 'queenlymajesty',
732
- emergencyexit: 'wimpout',
733
- filter: 'solidrock',
734
- gooey: 'tanglinghair',
735
- insomnia: 'vitalspirit',
736
- ironbarbs: 'roughskin',
737
- libero: 'protean',
738
- minus: 'plus',
739
- moxie: 'chillingneigh',
740
- powerofalchemy: 'receiver',
741
- propellertail: 'stalwart',
742
- teravolt: 'moldbreaker',
743
- turboblaze: 'moldbreaker',
744
- };
745
- for (const set of team) {
746
- let ability = this.toID(set.ability.split('0')[0]);
747
- if (!ability) continue;
748
- if (ability in base) ability = base[ability] as ID;
749
- if ((abilityTable.get(ability) || 0) >= 2) {
750
- return [
751
- `You are limited to two of each ability by 2 Ability Clause.`,
752
- `(You have more than two ${this.dex.abilities.get(ability).name} variants)`,
753
- ];
754
- }
755
- abilityTable.set(ability, (abilityTable.get(ability) || 0) + 1);
756
- }
757
- }
758
-
759
- // Donor Clause
760
- const evoFamilyLists = [];
761
- for (const set of team) {
762
- const abilitySources = teamHas.abilitySources?.[this.dex.toID(set.species)];
763
- if (!abilitySources) continue;
764
- let format = this.format;
765
- if (!format.getEvoFamily) format = this.dex.formats.get('gen8inheritance');
766
- evoFamilyLists.push(abilitySources.map(format.getEvoFamily!));
767
- }
768
-
769
- // Checking actual full incompatibility would require expensive algebra.
770
- // Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
771
- const requiredFamilies = Object.create(null);
772
- for (const evoFamilies of evoFamilyLists) {
773
- if (evoFamilies.length !== 1) continue;
774
- const [familyId] = evoFamilies;
775
- if (!(familyId in requiredFamilies)) requiredFamilies[familyId] = 1;
776
- requiredFamilies[familyId]++;
777
- if (requiredFamilies[familyId] > 2) {
778
- return [
779
- `You are limited to up to two inheritances from each evolution family by the Donor Clause.`,
780
- `(You inherit more than twice from ${this.dex.species.get(familyId).name}).`,
781
- ];
782
- }
783
- }
784
- },
785
- onBegin() {
786
- for (const pokemon of this.getAllPokemon()) {
787
- if (pokemon.baseAbility.includes('0')) {
788
- const donor = pokemon.baseAbility.split('0')[1];
789
- pokemon.m.donor = this.toID(donor);
790
- pokemon.baseAbility = this.toID(pokemon.baseAbility.split('0')[0]);
791
- pokemon.ability = pokemon.baseAbility;
792
- }
793
- }
794
- },
795
- onSwitchIn(pokemon) {
796
- if (!pokemon.m.donor) return;
797
- const donorTemplate = this.dex.species.get(pokemon.m.donor);
798
- if (!donorTemplate.exists) return;
799
- // Place volatiles on the Pokémon to show the donor details.
800
- this.add('-start', pokemon, donorTemplate.name, '[silent]');
801
- },
802
632
  },
803
633
  {
804
- name: "[Gen 8] Godly Gift",
805
- desc: `Each Pok&eacute;mon receives one base stat from a God (AG/Uber Pok&eacute;mon) depending on its position in the team. If there is no Uber Pok&eacute;mon, it uses the Pok&eacute;mon in the first slot.`,
634
+ name: "[Gen 8] AAA Doubles",
635
+ desc: `Pok&eacute;mon have access to almost any ability, in a doubles setting.`,
806
636
  threads: [
807
- `&bullet; <a href="https://www.smogon.com/forums/threads/3660461/">Godly Gift</a>`,
637
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8299984">AAA Doubles</a>`,
808
638
  ],
809
639
 
810
640
  mod: 'gen8',
811
- // searchShow: false,
812
- ruleset: ['Standard', 'Dynamax Clause'],
641
+ gameType: 'doubles',
642
+ ruleset: ['[Gen 8] Doubles OU', 'Sleep Clause Mod', '2 Ability Clause', '!Obtainable Abilities'],
813
643
  banlist: [
814
- 'Blissey', 'Calyrex-Shadow', 'Chansey', 'Marowak-Alola', 'Melmetal', 'Toxapex', 'Zacian', 'Zacian-Crowned',
815
- 'Uber > 1', 'AG ++ Uber > 1', 'Arena Trap', 'Huge Power', 'Moody', 'Pure Power', 'Shadow Tag', 'Baton Pass',
644
+ 'Kyurem-Black', 'Regigigas', 'Shedinja', 'Urshifu-Rapid-Strike', 'Zygarde-Base', 'Anger Point', 'Arena Trap', 'Comatose', 'Contrary',
645
+ 'Desolate Land', 'Fluffy', 'Fur Coat', 'Gorilla Tactics', 'Huge Power', 'Ice Scales', 'Illusion', 'Imposter', 'Innards Out', 'Intrepid Sword',
646
+ 'Libero', 'Moody', 'Neutralizing Gas', 'Parental Bond', 'Prankster', 'Primordial Sea', 'Protean', 'Pure Power', 'Rattled', 'Serene Grace',
647
+ 'Simple', 'Soul-Heart', 'Stakeout', 'Steam Engine', 'Speed Boost', 'Water Bubble', 'Water Compaction', 'Wonder Guard', 'King\'s Rock',
648
+ 'Weakness Policy', 'Beat Up', 'Stored Power',
816
649
  ],
817
- onValidateTeam(team) {
818
- const gods = new Set<string>();
819
- for (const set of team) {
820
- let species = this.dex.species.get(set.species);
821
- if (typeof species.battleOnly === 'string') species = this.dex.species.get(species.battleOnly);
822
- if (['ag', 'uber'].includes(this.toID(species.tier)) || this.toID(set.ability) === 'powerconstruct') {
823
- gods.add(species.name);
824
- }
825
- }
826
- if (gods.size > 1) {
827
- return [`You have too many Gods.`, `(${Array.from(gods).join(', ')} are Gods.)`];
828
- }
829
- },
830
- onModifySpeciesPriority: 3,
831
- onModifySpecies(species, target, source) {
832
- if (source || !target?.side) return;
833
- const god = target.side.team.find(set => {
834
- let godSpecies = this.dex.species.get(set.species);
835
- const validator = this.dex.formats.getRuleTable(this.dex.formats.get(`gen${this.gen}ou`));
836
- if (this.toID(set.ability) === 'powerconstruct') {
837
- return true;
838
- }
839
- if (set.item) {
840
- const item = this.dex.items.get(set.item);
841
- if (item.megaEvolves === set.species) godSpecies = this.dex.species.get(item.megaStone);
842
- }
843
- const isBanned = validator.isBannedSpecies(godSpecies);
844
- return isBanned;
845
- }) || target.side.team[0];
846
- const stat = Dex.stats.ids()[target.side.team.indexOf(target.set)];
847
- const newSpecies = this.dex.deepClone(species);
848
- let godSpecies = this.dex.species.get(god.species);
849
- if (godSpecies.forme === 'Crowned') {
850
- godSpecies = this.dex.species.get(godSpecies.changesFrom || godSpecies.baseSpecies);
851
- }
852
- newSpecies.bst -= newSpecies.baseStats[stat];
853
- newSpecies.baseStats[stat] = godSpecies.baseStats[stat];
854
- newSpecies.bst += newSpecies.baseStats[stat];
855
- return newSpecies;
856
- },
857
650
  },
858
651
 
859
652
  // Other Metagames
@@ -872,7 +665,7 @@ export const Formats: FormatList = [
872
665
  ],
873
666
 
874
667
  mod: 'gen8',
875
- ruleset: ['-Nonexistent', 'OHKO Clause', 'Evasion Moves Clause', 'Forme Clause', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Dynamax Clause', 'Sleep Clause Mod', 'Endless Battle Clause'],
668
+ ruleset: ['-Nonexistent', 'OHKO Clause', 'Evasion Moves Clause', 'Forme Clause', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Dynamax Clause', 'Sleep Moves Clause', 'Endless Battle Clause'],
876
669
  banlist: [
877
670
  'Calyrex-Shadow', 'Cramorant-Gorging', 'Darmanitan-Galar-Zen', 'Eternatus-Eternamax', 'Shedinja', 'Zacian-Crowned',
878
671
  'Arena Trap', 'Contrary', 'Gorilla Tactics', 'Huge Power', 'Illusion', 'Innards Out', 'Intrepid Sword', 'Libero',
@@ -924,7 +717,7 @@ export const Formats: FormatList = [
924
717
  const itemTable = new Set<ID>();
925
718
  for (const set of team) {
926
719
  const item = this.dex.items.get(set.item);
927
- if (!item?.megaStone) continue;
720
+ if (!item.megaStone) continue;
928
721
  const species = this.dex.species.get(set.species);
929
722
  if (species.isNonstandard) return [`${species.baseSpecies} does not exist in gen 8.`];
930
723
  if (this.ruleTable.isRestrictedSpecies(species) || this.toID(set.ability) === 'powerconstruct') {
@@ -975,7 +768,7 @@ export const Formats: FormatList = [
975
768
  'Archeops', 'Buzzwole', 'Calyrex-Ice', 'Calyrex-Shadow', 'Dialga', 'Dracovish', 'Dragapult', 'Dragonite', 'Eternatus', 'Gengar', 'Giratina', 'Giratina-Origin',
976
769
  'Groudon', 'Ho-Oh', 'Kartana', 'Keldeo', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo',
977
770
  'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Noivern', 'Palkia', 'Pheromosa', 'Rayquaza', 'Regigigas', 'Reshiram', 'Shedinja', 'Solgaleo', 'Spectrier',
978
- 'Urshifu-Base', 'Urshifu-Rapid-Strike', 'Victini', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta-Base', 'Zekrom', 'Zeraora', 'Zygarde-Base',
771
+ 'Urshifu-Base', 'Urshifu-Rapid-Strike', 'Victini', 'Weavile', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta-Base', 'Zekrom', 'Zeraora', 'Zygarde-Base',
979
772
  'Arena Trap', 'Comatose', 'Contrary', 'Fluffy', 'Fur Coat', 'Gorilla Tactics', 'Huge Power', 'Ice Scales', 'Illusion', 'Imposter', 'Innards Out', 'Intrepid Sword',
980
773
  'Libero', 'Magnet Pull', 'Moody', 'Neutralizing Gas', 'Parental Bond', 'Poison Heal', 'Power Construct', 'Protean', 'Pure Power', 'Shadow Tag', 'Simple', 'Stakeout',
981
774
  'Speed Boost', 'Water Bubble', 'Wonder Guard', 'King\'s Rock', 'Baton Pass',
@@ -1000,11 +793,12 @@ export const Formats: FormatList = [
1000
793
  mod: 'gen8',
1001
794
  ruleset: ['Standard', 'STABmons Move Legality', 'Dynamax Clause', 'Sleep Moves Clause'],
1002
795
  banlist: [
1003
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin',
1004
- 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus', 'Landorus-Therian', 'Lugia', 'Lunala', 'Marshadow', 'Mewtwo',
1005
- 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Porygon-Z', 'Rayquaza', 'Reshiram', 'Silvally', 'Solgaleo',
1006
- 'Spectrier', 'Tapu Koko', 'Thundurus-Base', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned',
1007
- 'Zapdos-Galar', 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Magnet Pull', 'Moody', 'Power Construct', 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
796
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Genesect', 'Garchomp', 'Giratina',
797
+ 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus', 'Landorus-Therian', 'Lugia', 'Lunala',
798
+ 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Porygon-Z', 'Rayquaza', 'Reshiram',
799
+ 'Silvally', 'Solgaleo', 'Spectrier', 'Tapu Bulu', 'Tapu Koko', 'Thundurus-Base', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned',
800
+ 'Zamazenta', 'Zamazenta-Crowned', 'Zapdos-Galar', 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Magnet Pull', 'Moody', 'Power Construct', 'Shadow Tag',
801
+ 'King\'s Rock', 'Baton Pass',
1008
802
  ],
1009
803
  restricted: [
1010
804
  'Acupressure', 'Astral Barrage', 'Belly Drum', 'Bolt Beak', 'Clangorous Soul', 'Double Iron Bash', 'Electrify', 'Extreme Speed', 'Fishious Rend',
@@ -1042,26 +836,66 @@ export const Formats: FormatList = [
1042
836
  'Kyurem-White', 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Mewtwo', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Rayquaza',
1043
837
  'Reshiram', 'Solgaleo', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom',
1044
838
  'Zygarde-Complete', 'Moody', 'Power Construct', 'Shadow Tag', 'Acupressure', 'Aromatic Mist', 'Baton Pass', 'Coaching', 'Court Change',
1045
- 'Decorate', 'Flatter', 'Floral Healing', 'Follow Me', 'Heal Pulse', 'Rage Powder', 'Swagger',
839
+ 'Decorate', 'Final Gambit', 'Flatter', 'Floral Healing', 'Flower Shield', 'Follow Me', 'Heal Pulse', 'Rage Powder', 'Swagger',
1046
840
  ],
1047
841
  },
1048
842
  {
1049
- name: "[Gen 8] Bonus Type",
1050
- desc: `Pok&eacute;mon can be nicknamed the name of a type to have that type added onto their current ones.`,
843
+ section: "BD/SP",
844
+ column: 2,
845
+ },
846
+ {
847
+ name: "[Gen 8 BDSP] Random Battle",
848
+ desc: `Randomized teams of level-balanced Pok&eacute;mon with sets that are generated to be competitively viable.`,
849
+
850
+ mod: 'gen8bdsp',
851
+ team: 'random',
852
+ searchShow: false,
853
+ challengeShow: false,
854
+ tournamentShow: false,
855
+ ruleset: ['[Gen 8] Random Battle'],
856
+ },
857
+ {
858
+ name: "[Gen 8 BDSP] OU",
1051
859
  threads: [
1052
- `&bullet; <a href="https://www.smogon.com/forums/threads/3683173/">Bonus Type</a>`,
860
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3693629/">BDSP OU Metagame Discussion</a>`,
861
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3693620/">BDSP OU Viability List</a>`,
1053
862
  ],
1054
863
 
1055
- mod: 'gen8',
864
+ mod: 'gen8bdsp',
865
+ ruleset: ['Standard'],
866
+ banlist: ['Uber', 'Arena Trap', 'Drizzle', 'Moody', 'Shadow Tag', 'King\'s Rock', 'Razor Fang', 'Baton Pass'],
867
+ },
868
+ {
869
+ name: "[Gen 8 BDSP] Doubles OU",
870
+
871
+ mod: 'gen8bdsp',
872
+ gameType: 'doubles',
1056
873
  searchShow: false,
1057
- ruleset: ['Standard', 'Dynamax Clause', 'Bonus Type Rule', '!Nickname Clause'],
1058
- banlist: [
1059
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Dragonite', 'Eternatus', 'Genesect',
1060
- 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia',
1061
- 'Lunala', 'Magearna', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa',
1062
- 'Rayquaza', 'Reshiram', 'Shedinja', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned',
1063
- 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Moody', 'Power Construct', 'Shadow Tag', 'Baton Pass',
874
+ ruleset: ['Standard Doubles'],
875
+ banlist: ['DUber'],
876
+ },
877
+ {
878
+ name: "[Gen 8 BDSP] Battle Festival Doubles",
879
+
880
+ mod: 'gen8bdsp',
881
+ gameType: 'doubles',
882
+ // VGC Timer is temporary
883
+ ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'VGC Timer'],
884
+ },
885
+ {
886
+ name: "[Gen 8 BDSP] Pure Hackmons",
887
+ desc: `Anything that can be hacked in-game and is usable in local battles is allowed.`,
888
+ threads: [
889
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3656851/">Pure Hackmons</a>`,
1064
890
  ],
891
+
892
+ mod: 'gen8bdsp',
893
+ searchShow: false,
894
+ ruleset: ['-Nonexistent', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause'],
895
+ },
896
+ {
897
+ section: "Challengeable OMs",
898
+ column: 2,
1065
899
  },
1066
900
  {
1067
901
  name: "[Gen 8] Camomons",
@@ -1074,10 +908,10 @@ export const Formats: FormatList = [
1074
908
  searchShow: false,
1075
909
  ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Dynamax Clause', 'Sleep Clause Mod', 'Endless Battle Clause'],
1076
910
  banlist: [
1077
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragonite', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin',
1078
- 'Groudon', 'Ho-Oh', 'Hydreigon', 'Kartana', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Latias', 'Latios', 'Lugia',
1079
- 'Lunala', 'Marshadow', 'Mewtwo', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Rayquaza', 'Reshiram', 'Shedinja', 'Slowking-Galar',
1080
- 'Solgaleo', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zeraora', 'Zygarde-Base',
911
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragonite', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin', 'Groudon',
912
+ 'Ho-Oh', 'Hydreigon', 'Kartana', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Latias', 'Latios', 'Lugia', 'Lunala', 'Marshadow',
913
+ 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Shedinja', 'Slowking-Galar', 'Solgaleo',
914
+ 'Tornadus-Therian', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zeraora', 'Zygarde-Base',
1081
915
  'Arena Trap', 'Moody', 'Power Construct', 'Shadow Tag', 'Baton Pass',
1082
916
  ],
1083
917
  onModifySpeciesPriority: 2,
@@ -1095,155 +929,431 @@ export const Formats: FormatList = [
1095
929
  },
1096
930
  },
1097
931
  {
1098
- name: "[Gen 8] Cross Evolution",
1099
- desc: `Give a Pok&eacute;mon a Pok&eacute;mon name of the next evolution stage as a nickname to inherit stat changes, typing, abilities, and up to 2 moves from the next stage Pok&eacute;mon.`,
932
+ name: "[Gen 8] Godly Gift",
933
+ desc: `Each Pok&eacute;mon receives one base stat from a God (AG/Uber Pok&eacute;mon) depending on its position in the team. If there is no Uber Pok&eacute;mon, it uses the Pok&eacute;mon in the first slot.`,
1100
934
  threads: [
1101
- `&bullet; <a href="https://www.smogon.com/forums/threads/3657562/">Cross Evolution</a>`,
935
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3660461/">Godly Gift</a>`,
1102
936
  ],
1103
937
 
1104
938
  mod: 'gen8',
1105
939
  searchShow: false,
1106
- ruleset: ['Standard', 'Overflow Stat Mod', 'Dynamax Clause'],
1107
- banlist: ['Corsola-Galar', 'Sneasel', 'Type: Null', 'Arena Trap', 'Ice Scales', 'Moody', 'King\'s Rock', 'Baton Pass'],
1108
- restricted: ['Chansey', 'Lunala', 'Shedinja', 'Solgaleo', 'Gorilla Tactics', 'Huge Power', 'Pure Power', 'Shadow Tag'],
940
+ ruleset: ['Standard', 'Dynamax Clause'],
941
+ banlist: [
942
+ 'Blissey', 'Calyrex-Shadow', 'Chansey', 'Hawlucha', 'Marowak-Alola', 'Melmetal', 'Pikachu', 'Toxapex', 'Zacian', 'Zacian-Crowned',
943
+ 'Uber > 1', 'AG ++ Uber > 1', 'Arena Trap', 'Huge Power', 'Moody', 'Pure Power', 'Shadow Tag', 'Baton Pass',
944
+ ],
1109
945
  onValidateTeam(team) {
1110
- const names = new Set<ID>();
946
+ const gods = new Set<string>();
1111
947
  for (const set of team) {
1112
- const name = set.name;
1113
- if (names.has(this.dex.toID(name))) {
1114
- return [
1115
- `Your Pok\u00e9mon must have different nicknames.`,
1116
- `(You have more than one Pok\u00e9mon named '${name}')`,
1117
- ];
948
+ let species = this.dex.species.get(set.species);
949
+ if (typeof species.battleOnly === 'string') species = this.dex.species.get(species.battleOnly);
950
+ if (['ag', 'uber'].includes(this.toID(species.tier)) || this.toID(set.ability) === 'powerconstruct') {
951
+ gods.add(species.name);
1118
952
  }
1119
- names.add(this.dex.toID(name));
1120
953
  }
1121
- if (!names.size) {
1122
- return [
1123
- `${this.format.name} works using nicknames; your team has 0 nicknamed Pok\u00e9mon.`,
1124
- `(If this was intentional, add a nickname to one Pok\u00e9mon that isn't the name of a Pok\u00e9mon species.)`,
1125
- ];
954
+ if (gods.size > 1) {
955
+ return [`You have too many Gods.`, `(${Array.from(gods).join(', ')} are Gods.)`];
1126
956
  }
1127
957
  },
1128
- checkCanLearn(move, species, lsetData, set) {
1129
- // @ts-ignore
1130
- if (!set.sp?.exists || !set.crossSpecies?.exists) {
1131
- return this.checkCanLearn(move, species, lsetData, set);
958
+ onModifySpeciesPriority: 3,
959
+ onModifySpecies(species, target, source) {
960
+ if (source || !target?.side) return;
961
+ const god = target.side.team.find(set => {
962
+ let godSpecies = this.dex.species.get(set.species);
963
+ const validator = this.dex.formats.getRuleTable(this.dex.formats.get(`gen${this.gen}ou`));
964
+ if (this.toID(set.ability) === 'powerconstruct') {
965
+ return true;
966
+ }
967
+ if (set.item) {
968
+ const item = this.dex.items.get(set.item);
969
+ if (item.megaEvolves === set.species) godSpecies = this.dex.species.get(item.megaStone);
970
+ }
971
+ const isBanned = validator.isBannedSpecies(godSpecies);
972
+ return isBanned;
973
+ }) || target.side.team[0];
974
+ const stat = Dex.stats.ids()[target.side.team.indexOf(target.set)];
975
+ const newSpecies = this.dex.deepClone(species);
976
+ let godSpecies = this.dex.species.get(god.species);
977
+ if (godSpecies.forme === 'Crowned') {
978
+ godSpecies = this.dex.species.get(godSpecies.changesFrom || godSpecies.baseSpecies);
1132
979
  }
1133
- // @ts-ignore
1134
- const problem = this.checkCanLearn(move, set.sp);
1135
- if (!problem) return null;
1136
- // @ts-ignore
1137
- if (!set.crossMovesLeft) return problem;
1138
- // @ts-ignore
1139
- if (this.checkCanLearn(move, set.crossSpecies)) return problem;
1140
- // @ts-ignore
1141
- set.crossMovesLeft--;
1142
- return null;
980
+ newSpecies.bst -= newSpecies.baseStats[stat];
981
+ newSpecies.baseStats[stat] = godSpecies.baseStats[stat];
982
+ newSpecies.bst += newSpecies.baseStats[stat];
983
+ return newSpecies;
984
+ },
985
+ },
986
+ {
987
+ name: "[Gen 8] Inheritance",
988
+ desc: `Pok&eacute;mon may use the ability and moves of another, as long as they forfeit their own learnset.`,
989
+ threads: [
990
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3656811/">Inheritance</a>`,
991
+ ],
992
+
993
+ mod: 'gen8',
994
+ searchShow: false,
995
+ ruleset: ['Standard', '2 Ability Clause', 'Dynamax Clause'],
996
+ banlist: [
997
+ 'Blacephalon', 'Blaziken', 'Butterfree', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chansey', 'Combusken', 'Cresselia', 'Darmanitan-Galar', 'Dialga', 'Dracovish',
998
+ 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala',
999
+ 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Natu', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Regieleki',
1000
+ 'Regigigas', 'Reshiram', 'Sableye', 'Shedinja', 'Solgaleo', 'Spectrier', 'Tapu Koko', 'Toxtricity', 'Torkoal', 'Urshifu-Base', 'Xatu', 'Xerneas', 'Yveltal',
1001
+ 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zeraora', 'Zekrom', 'Arena Trap', 'Contrary', 'Drizzle', 'Huge Power', 'Imposter', 'Innards Out',
1002
+ 'Libero', 'Moody', 'Power Construct', 'Pure Power', 'Quick Draw', 'Shadow Tag', 'Sheer Force', 'Simple', 'Unaware', 'Unburden', 'Water Bubble', 'King\'s Rock',
1003
+ 'Quick Claw', 'Baton Pass', 'Bolt Beak', 'Fishious Rend', 'Shell Smash', 'Thousand Arrows',
1004
+ ],
1005
+ getEvoFamily(speciesid) {
1006
+ let species = Dex.species.get(speciesid);
1007
+ while (species.prevo) {
1008
+ species = Dex.species.get(species.prevo);
1009
+ }
1010
+ return species.id;
1143
1011
  },
1144
1012
  validateSet(set, teamHas) {
1145
- const crossSpecies = this.dex.species.get(set.name);
1146
- const onChangeSet = this.dex.formats.get('Pokemon').onChangeSet;
1147
- let problems = onChangeSet?.call(this, set, this.format) || null;
1148
- if (Array.isArray(problems) && problems.length) return problems;
1149
- const crossNonstandard = !this.ruleTable.has('standardnatdex') && crossSpecies.isNonstandard === 'Past';
1150
- const crossIsCap = !this.ruleTable.has('+pokemontag:cap') && crossSpecies.isNonstandard === 'CAP';
1151
- if (!crossSpecies.exists || crossNonstandard || crossIsCap) return this.validateSet(set, teamHas);
1152
- const species = this.dex.species.get(set.species);
1153
- const check = this.checkSpecies(set, species, species, {});
1154
- if (check) return [check];
1155
- const nonstandard = !this.ruleTable.has('standardnatdex') && species.isNonstandard === 'Past';
1156
- const isCap = !this.ruleTable.has('+pokemontag:cap') && species.isNonstandard === 'CAP';
1157
- if (!species.exists || nonstandard || isCap || species === crossSpecies) return this.validateSet(set, teamHas);
1158
- if (!species.nfe) return [`${species.name} cannot cross evolve because it doesn't evolve.`];
1159
- const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
1160
- if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo) {
1161
- return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it isn't an evolution.`];
1013
+ const unreleased = (pokemon: Species) => pokemon.tier === "Unreleased" && pokemon.isNonstandard === "Unobtainable";
1014
+ if (!teamHas.abilityMap) {
1015
+ teamHas.abilityMap = Object.create(null);
1016
+ for (const pokemon of Dex.species.all()) {
1017
+ if (pokemon.isNonstandard || unreleased(pokemon)) continue;
1018
+ if (pokemon.requiredAbility || pokemon.requiredItem || pokemon.requiredMove) continue;
1019
+ if (this.ruleTable.isBannedSpecies(pokemon)) continue;
1020
+
1021
+ for (const key of Object.values(pokemon.abilities)) {
1022
+ const abilityId = this.dex.toID(key);
1023
+ if (abilityId in teamHas.abilityMap) {
1024
+ teamHas.abilityMap[abilityId][pokemon.evos ? 'push' : 'unshift'](pokemon.id);
1025
+ } else {
1026
+ teamHas.abilityMap[abilityId] = [pokemon.id];
1027
+ }
1028
+ }
1029
+ }
1162
1030
  }
1163
- if (this.ruleTable.isRestrictedSpecies(crossSpecies)) {
1164
- return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it is banned.`];
1031
+
1032
+ const problem = this.validateForme(set);
1033
+ if (problem.length) return problem;
1034
+
1035
+ const species = this.dex.species.get(set.species);
1036
+ if (!species.exists || species.num < 1) return [`The Pok\u00e9mon "${set.species}" does not exist.`];
1037
+ if (species.isNonstandard || unreleased(species)) {
1038
+ return [`${species.name} is not obtainable in Generation ${this.dex.gen}.`];
1165
1039
  }
1166
- const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
1167
- if (!crossPrevoSpecies.prevo !== !species.prevo) {
1168
- return [
1169
- `${species.name} cannot cross evolve into ${crossSpecies.name} because they are not consecutive evolution stages.`,
1170
- ];
1040
+
1041
+ const name = set.name;
1042
+ if (this.ruleTable.isBannedSpecies(species)) {
1043
+ return this.validateSet(set, teamHas);
1171
1044
  }
1045
+
1172
1046
  const ability = this.dex.abilities.get(set.ability);
1173
- if (!this.ruleTable.isRestricted(`ability:${ability.id}`) || Object.values(species.abilities).includes(ability.name)) {
1174
- set.species = crossSpecies.name;
1047
+ if (!ability.exists || ability.isNonstandard) return [`${name} needs to have a valid ability.`];
1048
+ const pokemonWithAbility = teamHas.abilityMap[ability.id];
1049
+ if (!pokemonWithAbility) return [`${ability.name} is not available on a legal Pok\u00e9mon.`];
1050
+
1051
+ (this.format as any).debug = true;
1052
+
1053
+ if (!teamHas.abilitySources) teamHas.abilitySources = Object.create(null);
1054
+ const validSources: string[] = teamHas.abilitySources[this.dex.toID(set.species)] = []; // Evolution families
1055
+
1056
+ let canonicalSource = ''; // Specific for the basic implementation of Donor Clause (see onValidateTeam).
1057
+
1058
+ for (const donor of pokemonWithAbility) {
1059
+ const donorSpecies = this.dex.species.get(donor);
1060
+ let format = this.format;
1061
+ if (!format.getEvoFamily) format = this.dex.formats.get('gen8inheritance');
1062
+ const evoFamily = format.getEvoFamily!(donorSpecies.id);
1063
+ if (validSources.includes(evoFamily)) continue;
1064
+
1065
+ set.species = donorSpecies.name;
1066
+ set.name = donorSpecies.baseSpecies;
1067
+ const problems = this.validateSet(set, teamHas) || [];
1068
+ if (!problems.length) {
1069
+ validSources.push(evoFamily);
1070
+ canonicalSource = donorSpecies.name;
1071
+ }
1072
+ // Specific for the basic implementation of Donor Clause (see onValidateTeam).
1073
+ if (validSources.length > 1) break;
1175
1074
  }
1075
+ (this.format as any).debug = false;
1176
1076
 
1177
- // @ts-ignore
1178
- set.sp = species;
1179
- // @ts-ignore
1180
- set.crossSpecies = crossSpecies;
1181
- // @ts-ignore
1182
- set.crossMovesLeft = 2;
1183
- problems = this.validateSet(set, teamHas);
1184
- set.name = crossSpecies.name;
1077
+ set.name = name;
1185
1078
  set.species = species.name;
1079
+ if (!validSources.length) {
1080
+ if (pokemonWithAbility.length > 1) return [`${name}'s set is illegal.`];
1081
+ return [`${name} has an illegal set with an ability from ${this.dex.species.get(pokemonWithAbility[0]).name}.`];
1082
+ }
1083
+
1084
+ // Protocol: Include the data of the donor species in the `ability` data slot.
1085
+ // Afterwards, we are going to reset the name to what the user intended.
1086
+ set.ability = `${set.ability}0${canonicalSource}`;
1087
+ return null;
1088
+ },
1089
+ onValidateTeam(team, f, teamHas) {
1090
+ if (this.ruleTable.has('2abilityclause')) {
1091
+ const abilityTable = new Map<string, number>();
1092
+ const base: {[k: string]: string} = {
1093
+ airlock: 'cloudnine',
1094
+ battlearmor: 'shellarmor',
1095
+ clearbody: 'whitesmoke',
1096
+ dazzling: 'queenlymajesty',
1097
+ emergencyexit: 'wimpout',
1098
+ filter: 'solidrock',
1099
+ gooey: 'tanglinghair',
1100
+ insomnia: 'vitalspirit',
1101
+ ironbarbs: 'roughskin',
1102
+ libero: 'protean',
1103
+ minus: 'plus',
1104
+ moxie: 'chillingneigh',
1105
+ powerofalchemy: 'receiver',
1106
+ propellertail: 'stalwart',
1107
+ teravolt: 'moldbreaker',
1108
+ turboblaze: 'moldbreaker',
1109
+ };
1110
+ for (const set of team) {
1111
+ let ability = this.toID(set.ability.split('0')[0]);
1112
+ if (!ability) continue;
1113
+ if (ability in base) ability = base[ability] as ID;
1114
+ if ((abilityTable.get(ability) || 0) >= 2) {
1115
+ return [
1116
+ `You are limited to two of each ability by 2 Ability Clause.`,
1117
+ `(You have more than two ${this.dex.abilities.get(ability).name} variants)`,
1118
+ ];
1119
+ }
1120
+ abilityTable.set(ability, (abilityTable.get(ability) || 0) + 1);
1121
+ }
1122
+ }
1123
+
1124
+ // Donor Clause
1125
+ const evoFamilyLists = [];
1126
+ for (const set of team) {
1127
+ const abilitySources = teamHas.abilitySources?.[this.dex.toID(set.species)];
1128
+ if (!abilitySources) continue;
1129
+ let format = this.format;
1130
+ if (!format.getEvoFamily) format = this.dex.formats.get('gen8inheritance');
1131
+ evoFamilyLists.push(abilitySources.map(format.getEvoFamily!));
1132
+ }
1133
+
1134
+ // Checking actual full incompatibility would require expensive algebra.
1135
+ // Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
1136
+ const requiredFamilies = Object.create(null);
1137
+ for (const evoFamilies of evoFamilyLists) {
1138
+ if (evoFamilies.length !== 1) continue;
1139
+ const [familyId] = evoFamilies;
1140
+ if (!(familyId in requiredFamilies)) requiredFamilies[familyId] = 1;
1141
+ requiredFamilies[familyId]++;
1142
+ if (requiredFamilies[familyId] > 2) {
1143
+ return [
1144
+ `You are limited to up to two inheritances from each evolution family by the Donor Clause.`,
1145
+ `(You inherit more than twice from ${this.dex.species.get(familyId).name}).`,
1146
+ ];
1147
+ }
1148
+ }
1149
+ },
1150
+ onBegin() {
1151
+ for (const pokemon of this.getAllPokemon()) {
1152
+ if (pokemon.baseAbility.includes('0')) {
1153
+ const donor = pokemon.baseAbility.split('0')[1];
1154
+ pokemon.m.donor = this.toID(donor);
1155
+ pokemon.baseAbility = this.toID(pokemon.baseAbility.split('0')[0]);
1156
+ pokemon.ability = pokemon.baseAbility;
1157
+ }
1158
+ }
1159
+ },
1160
+ onSwitchIn(pokemon) {
1161
+ if (!pokemon.m.donor) return;
1162
+ const donorTemplate = this.dex.species.get(pokemon.m.donor);
1163
+ if (!donorTemplate.exists) return;
1164
+ // Place volatiles on the Pokémon to show the donor details.
1165
+ this.add('-start', pokemon, donorTemplate.name, '[silent]');
1166
+ },
1167
+ },
1168
+ {
1169
+ name: "[Gen 8] Multibility",
1170
+ desc: `Run a second ability at the cost of giving up a Pok&eacute;mon's item slot.`,
1171
+ threads: [
1172
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3688892/">Multibility</a>`,
1173
+ ],
1174
+
1175
+ mod: 'gen8',
1176
+ searchShow: false,
1177
+ ruleset: ['Standard', 'Dynamax Clause', '2 Ability Clause', 'Sleep Moves Clause', '!Sleep Clause Mod'],
1178
+ banlist: [
1179
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragonite', 'Eternatus',
1180
+ 'Genesect', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White',
1181
+ 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane',
1182
+ 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Shedinja', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas',
1183
+ 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base', 'Arena Trap',
1184
+ 'Chlorophyll', 'Magnet Pull', 'Moody', 'Power Construct', 'Sand Rush', 'Shadow Tag', 'Slush Rush', 'Swift Swim',
1185
+ 'Stench', 'Trace', 'King\'s Rock', 'Baton Pass',
1186
+ ],
1187
+ restricted: [
1188
+ 'Comatose', 'Contrary', 'Fluffy', 'Fur Coat', 'Huge Power', 'Ice Scales', 'Illusion', 'Imposter', 'Innards Out',
1189
+ 'Intrepid Sword', 'Libero', 'Neutralizing Gas', 'Parental Bond', 'Protean', 'Pure Power', 'Simple', 'Speed Boost',
1190
+ 'Stakeout', 'Tinted Lens', 'Unaware', 'Water Bubble', 'Wonder Guard',
1191
+ 'Emergency Exit + Regenerator', 'Wimp Out + Regenerator',
1192
+ ],
1193
+ validateSet(set, teamHas) {
1194
+ const ability = this.dex.abilities.get(set.ability);
1195
+ const item = this.dex.abilities.get(set.item);
1196
+ if (!item.exists) return this.validateSet(set, teamHas);
1197
+ const problems = [];
1198
+ if (item.isNonstandard && !this.ruleTable.has(`+ability:${item.id}`)) {
1199
+ problems.push(`${item.name} is banned.`);
1200
+ }
1201
+ if (ability.id === item.id) {
1202
+ problems.push(`${set.species} has ${ability.name} as an ability and as an item.`);
1203
+ }
1204
+ if (this.ruleTable.isRestricted(`ability:${item.id}`) || this.ruleTable.isBanned(`ability:${item.id}`)) {
1205
+ problems.push(`${set.species}'s second ability (${item.name}) can only be used as an ability.`);
1206
+ }
1207
+ if ((ability.id === 'regenerator' && ['emergencyexit', 'wimpout'].includes(item.id)) ||
1208
+ (item.id === 'regenerator' && ['emergencyexit', 'wimpout'].includes(ability.id))) {
1209
+ problems.push(`${ability.name} and ${item.name} are banned together.`);
1210
+ }
1211
+ const itemStr = set.item;
1212
+ set.item = '';
1213
+ const problem = this.validateSet(set, teamHas);
1214
+ if (problem?.length) problems.push(...problem);
1215
+ set.item = itemStr;
1186
1216
  return problems;
1187
1217
  },
1188
- onModifySpecies(species, target, source, effect) {
1189
- if (!target) return; // chat
1190
- if (effect && ['imposter', 'transform'].includes(effect.id)) return;
1191
- if (target.set.name === target.set.species) return;
1192
- const crossSpecies = this.dex.species.get(target.set.name);
1193
- if (!crossSpecies.exists) return;
1194
- if (species.battleOnly || !species.nfe) return;
1195
- const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
1196
- if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo) return;
1197
- const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
1198
- if (!crossPrevoSpecies.prevo !== !species.prevo) return;
1199
-
1200
- const mixedSpecies = this.dex.deepClone(species);
1201
- mixedSpecies.baseSpecies = mixedSpecies.name = `${species.name}-${crossSpecies.name}`;
1202
- mixedSpecies.weightkg =
1203
- Math.max(0.1, +(species.weightkg + crossSpecies.weightkg - crossPrevoSpecies.weightkg)).toFixed(1);
1204
- mixedSpecies.nfe = false;
1205
- mixedSpecies.evos = [];
1206
- mixedSpecies.eggGroups = crossSpecies.eggGroups;
1207
- mixedSpecies.abilities = crossSpecies.abilities;
1208
- mixedSpecies.bst = 0;
1209
- let i: StatID;
1210
- for (i in species.baseStats) {
1211
- const statChange = crossSpecies.baseStats[i] - crossPrevoSpecies.baseStats[i];
1212
- mixedSpecies.baseStats[i] = this.clampIntRange(species.baseStats[i] + statChange, 1, 255);
1213
- mixedSpecies.bst += mixedSpecies.baseStats[i];
1218
+ onValidateTeam(team) {
1219
+ if (!this.ruleTable.has('2abilityclause')) return;
1220
+ const abilityTable = new Map<string, number>();
1221
+ const base: {[k: string]: string} = {
1222
+ airlock: 'cloudnine',
1223
+ battlearmor: 'shellarmor',
1224
+ clearbody: 'whitesmoke',
1225
+ dazzling: 'queenlymajesty',
1226
+ emergencyexit: 'wimpout',
1227
+ filter: 'solidrock',
1228
+ gooey: 'tanglinghair',
1229
+ insomnia: 'vitalspirit',
1230
+ ironbarbs: 'roughskin',
1231
+ libero: 'protean',
1232
+ minus: 'plus',
1233
+ moxie: 'chillingneigh',
1234
+ powerofalchemy: 'receiver',
1235
+ propellertail: 'stalwart',
1236
+ teravolt: 'moldbreaker',
1237
+ turboblaze: 'moldbreaker',
1238
+ };
1239
+ const abilities: [string, string][] = [];
1240
+ for (const set of team) {
1241
+ abilities.push([set.ability, set.item].map((abil) => {
1242
+ const id = this.toID(abil);
1243
+ return base[id] || id;
1244
+ }) as [string, string]);
1245
+ }
1246
+ for (const [abilityid, itemid] of abilities) {
1247
+ const ability = this.dex.abilities.get(abilityid);
1248
+ const item = this.dex.abilities.get(itemid);
1249
+ if (ability.exists) abilityTable.set(ability.id, (abilityTable.get(ability.id) || 0) + 1);
1250
+ if (item.exists) abilityTable.set(item.id, (abilityTable.get(item.id) || 0) + 1);
1214
1251
  }
1215
- if (crossSpecies.types[0] !== crossPrevoSpecies.types[0]) mixedSpecies.types[0] = crossSpecies.types[0];
1216
- if (crossSpecies.types[1] !== crossPrevoSpecies.types[1]) {
1217
- mixedSpecies.types[1] = crossSpecies.types[1] || crossSpecies.types[0];
1252
+ for (const [abilityid, size] of abilityTable) {
1253
+ if (size > 2) {
1254
+ return [
1255
+ `You are limited to two of each ability by 2 Ability Clause.`,
1256
+ `(You have more than two ${this.dex.abilities.get(abilityid).name} variants)`,
1257
+ ];
1258
+ }
1259
+ }
1260
+ },
1261
+ onSwitchOut(pokemon) {
1262
+ const item = this.dex.abilities.get(pokemon.item);
1263
+ if (item.exists) {
1264
+ this.singleEvent('End', item, pokemon.itemState, pokemon);
1218
1265
  }
1219
- if (mixedSpecies.types[0] === mixedSpecies.types[1]) mixedSpecies.types = [mixedSpecies.types[0]];
1220
-
1221
- return mixedSpecies;
1222
1266
  },
1223
- onBegin() {
1224
- for (const pokemon of this.getAllPokemon()) {
1225
- pokemon.baseSpecies = pokemon.species;
1267
+ onFaint(pokemon) {
1268
+ const item = this.dex.abilities.get(pokemon.item);
1269
+ if (item.exists) {
1270
+ this.singleEvent('End', item, pokemon.itemState, pokemon);
1226
1271
  }
1227
1272
  },
1228
- },
1229
- {
1230
- name: "[Gen 8] Inverse",
1231
- desc: `The type chart is inverted. Normal is super effective against Ghost, and vice versa, etc.`,
1232
- threads: [
1233
- `&bullet; <a href="https://www.smogon.com/forums/threads/3666858/">Inverse</a>`,
1234
- ],
1235
- mod: 'gen8',
1236
- searchShow: false,
1237
- ruleset: ['Standard', 'Dynamax Clause', 'Inverse Mod'],
1238
- banlist: [
1239
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darmanitan-Galar', 'Dialga', 'Diggersby', 'Dracovish',
1240
- 'Dracozolt', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana',
1241
- 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala', 'Marshadow', 'Mewtwo',
1242
- 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Porygon-Z', 'Rayquaza',
1243
- 'Regidrago', 'Regieleki', 'Reshiram', 'Rillaboom', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas',
1244
- 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta-Base', 'Zekrom', 'Arena Trap', 'Moody', 'Power Construct',
1245
- 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
1246
- ],
1273
+ field: {
1274
+ suppressingWeather() {
1275
+ for (const pokemon of this.battle.getAllActive()) {
1276
+ const item = this.battle.dex.abilities.get(pokemon.item);
1277
+ if (pokemon && !pokemon.ignoringAbility() &&
1278
+ (pokemon.getAbility().suppressWeather || (item.exists && item.suppressWeather))) {
1279
+ return true;
1280
+ }
1281
+ }
1282
+ return false;
1283
+ },
1284
+ },
1285
+ pokemon: {
1286
+ getItem() {
1287
+ const ability = this.battle.dex.abilities.get(this.item);
1288
+ if (!ability.exists) return Object.getPrototypeOf(this).getItem.call(this);
1289
+ return {...ability, ignoreKlutz: true, onTakeItem: false};
1290
+ },
1291
+ hasItem(item) {
1292
+ const ownItem = this.item;
1293
+ if (this.battle.dex.abilities.get(ownItem).exists) return false;
1294
+ if (this.ignoringItem()) return false;
1295
+ if (!Array.isArray(item)) return ownItem === this.battle.toID(item);
1296
+ return item.map(this.battle.toID).includes(ownItem);
1297
+ },
1298
+ hasAbility(ability) {
1299
+ if (this.ignoringAbility()) return false;
1300
+ if (Array.isArray(ability)) return ability.some(abil => this.hasAbility(abil));
1301
+ const abilityid = this.battle.toID(ability);
1302
+ const item = this.battle.dex.abilities.get(this.item);
1303
+ return this.ability === abilityid || (item.exists && item.id === abilityid);
1304
+ },
1305
+ ignoringAbility() {
1306
+ // Check if any active pokemon have the ability Neutralizing Gas
1307
+ let neutralizinggas = false;
1308
+ for (const pokemon of this.battle.getAllActive()) {
1309
+ // can't use hasAbility because it would lead to infinite recursion
1310
+ if ((pokemon.ability === ('neutralizinggas' as ID) || pokemon.item === ('neutralizinggas' as ID)) &&
1311
+ !pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending) {
1312
+ neutralizinggas = true;
1313
+ break;
1314
+ }
1315
+ }
1316
+ return !!(
1317
+ (this.battle.gen >= 5 && !this.isActive) ||
1318
+ ((this.volatiles['gastroacid'] || (neutralizinggas && this.ability !== ('neutralizinggas' as ID) &&
1319
+ this.item !== ('neutralizinggas' as ID))) && !this.getAbility().isPermanent));
1320
+ },
1321
+ ignoringItem() {
1322
+ let nGas = false;
1323
+ for (const pokemon of this.battle.getAllActive()) {
1324
+ // can't use hasAbility because it would lead to infinite recursion
1325
+ if (((pokemon.ability === ('neutralizinggas' as ID) && !pokemon.abilityState.ending) ||
1326
+ (pokemon.item === ('neutralizinggas' as ID) && !pokemon.itemState.ending)) &&
1327
+ !pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending) {
1328
+ nGas = true;
1329
+ break;
1330
+ }
1331
+ }
1332
+ const item = this.battle.dex.abilities.get(this.item);
1333
+ return !!((this.battle.gen >= 5 && !this.isActive) ||
1334
+ (this.hasAbility('klutz') && !this.getItem().ignoreKlutz) ||
1335
+ this.volatiles['embargo'] || this.battle.field.pseudoWeather['magicroom'] ||
1336
+ (item.exists && item.id !== 'neutralizinggas' && (nGas || this.volatiles['gastroacid'])));
1337
+ },
1338
+ takeItem(source) {
1339
+ if (!this.isActive) return false;
1340
+ if (!this.item) return false;
1341
+ if (this.battle.dex.abilities.get(this.item).exists) return false;
1342
+ if (!source) source = this;
1343
+ if (this.battle.gen === 4) {
1344
+ if (this.battle.toID(this.ability) === 'multitype') return false;
1345
+ if (source && this.battle.toID(source.ability) === 'multitype') return false;
1346
+ }
1347
+ const item = this.getItem();
1348
+ if (this.battle.runEvent('TakeItem', this, source, null, item)) {
1349
+ this.item = '';
1350
+ this.itemState = {id: '', target: this};
1351
+ this.pendingStaleness = undefined;
1352
+ return item;
1353
+ }
1354
+ return false;
1355
+ },
1356
+ },
1247
1357
  },
1248
1358
  {
1249
1359
  name: "[Gen 8] Nature Swap",
@@ -1300,17 +1410,6 @@ export const Formats: FormatList = [
1300
1410
  },
1301
1411
  },
1302
1412
  },
1303
- {
1304
- name: "[Gen 8] Pure Hackmons",
1305
- desc: `Anything that can be hacked in-game and is usable in local battles is allowed.`,
1306
- threads: [
1307
- `&bullet; <a href="https://www.smogon.com/forums/threads/3656851/">Pure Hackmons</a>`,
1308
- ],
1309
-
1310
- mod: 'gen8',
1311
- searchShow: false,
1312
- ruleset: ['-Nonexistent', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause'],
1313
- },
1314
1413
  {
1315
1414
  name: "[Gen 8] Shared Power",
1316
1415
  desc: `Once a Pok&eacute;mon switches in, its ability is shared with the rest of the team.`,
@@ -1372,29 +1471,6 @@ export const Formats: FormatList = [
1372
1471
  }
1373
1472
  },
1374
1473
  },
1375
- {
1376
- name: "[Gen 8] Sketchmons",
1377
- desc: `Pok&eacute;mon can learn one of any move they don't normally learn, barring the few that are banned.`,
1378
- threads: [
1379
- `&bullet; <a href="https://www.smogon.com/forums/threads/3680298/">Sketchmons</a>`,
1380
- ],
1381
- mod: 'gen8',
1382
- searchShow: false,
1383
- ruleset: ['Standard', 'Dynamax Clause', 'Sketchmons Move Legality'],
1384
- banlist: [
1385
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Genesect',
1386
- 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia',
1387
- 'Lunala', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Porygon-Z',
1388
- 'Rayquaza', 'Regieleki', 'Reshiram', 'Rillaboom', 'Shedinja', 'Solgaleo', 'Spectrier', 'Swoobat', 'Urshifu-Base', 'Xerneas',
1389
- 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zeraora', 'Zygarde-Base', 'Arena Trap',
1390
- 'Moody', 'Power Construct', 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
1391
- ],
1392
- restricted: [
1393
- 'Acupressure', 'Astral Barrage', 'Belly Drum', 'Bolt Beak', 'Clangorous Soul', 'Double Iron Bash', 'Electrify', 'Extreme Speed',
1394
- 'Fishious Rend', 'Geomancy', 'Glacial Lance', 'Lovely Kiss', 'No Retreat', 'Oblivion Wing', 'Octolock', 'Quiver Dance', 'Secret Sword',
1395
- 'Shell Smash', 'Shift Gear', 'Sleep Powder', 'Spore', 'Thousand Arrows', 'Transform', 'V-create', 'Wicked Blow',
1396
- ],
1397
- },
1398
1474
  {
1399
1475
  name: "[Gen 8] The Loser's Game",
1400
1476
  desc: `The first player to lose all of their Pok&eacute;mon wins.`,
@@ -1530,50 +1606,6 @@ export const Formats: FormatList = [
1530
1606
  },
1531
1607
  },
1532
1608
  },
1533
- {
1534
- name: "[Gen 8] Tier Shift",
1535
- desc: `Pok&eacute;mon below OU get their stats, excluding HP, boosted. UU/RUBL get +10, RU/NUBL get +20, NU/PUBL get +30, and PU or lower get +40.`,
1536
- threads: [
1537
- `&bullet; <a href="https://www.smogon.com/forums/threads/3662165/">Tier Shift</a>`,
1538
- ],
1539
-
1540
- mod: 'gen8',
1541
- searchShow: false,
1542
- ruleset: ['[Gen 8] OU', 'Overflow Stat Mod'],
1543
- banlist: ['Damp Rock', 'Eviolite', 'Heat Rock'],
1544
- unbanlist: ['Zamazenta-Crowned'],
1545
- onModifySpecies(species, target, source, effect) {
1546
- if (!species.baseStats) return;
1547
- const boosts: {[tier: string]: number} = {
1548
- uu: 10,
1549
- rubl: 10,
1550
- ru: 20,
1551
- nubl: 20,
1552
- nu: 30,
1553
- publ: 30,
1554
- pu: 40,
1555
- nfe: 40,
1556
- lc: 40,
1557
- };
1558
- let tier: string = this.toID(species.tier);
1559
- if (!(tier in boosts)) return;
1560
- // Non-Pokemon bans in lower tiers
1561
- if (target) {
1562
- if (target.set.item === 'lightclay') return;
1563
- if (['drizzle', 'drought', 'snowwarning'].includes(target.set.ability) && boosts[tier] > 20) tier = 'nubl';
1564
- }
1565
- const pokemon = this.dex.deepClone(species);
1566
- pokemon.bst = pokemon.baseStats['hp'];
1567
- const boost = boosts[tier];
1568
- let statName: StatID;
1569
- for (statName in pokemon.baseStats as StatsTable) {
1570
- if (statName === 'hp') continue;
1571
- pokemon.baseStats[statName] = this.clampIntRange(pokemon.baseStats[statName] + boost, 1, 255);
1572
- pokemon.bst += pokemon.baseStats[statName];
1573
- }
1574
- return pokemon;
1575
- },
1576
- },
1577
1609
  {
1578
1610
  name: "[Gen 8] Trademarked",
1579
1611
  desc: `Sacrifice your Pok&eacute;mon's ability for a status move that activates on switch-in.`,
@@ -1592,9 +1624,10 @@ export const Formats: FormatList = [
1592
1624
  'Arena Trap', 'Moody', 'Power Construct', 'Shadow Tag', 'Baton Pass',
1593
1625
  ],
1594
1626
  restricted: [
1595
- 'Baneful Bunker', 'Block', 'Copycat', 'Corrosive Gas', 'Detect', 'Destiny Bond', 'Disable', 'Encore', 'Fairy Lock', 'Ingrain', 'Instruct',
1596
- 'King\'s Shield', 'Mat Block', 'Mean Look', 'move:Metronome', 'Obstruct', 'Octolock', 'Nature Power', 'Parting Shot', 'Psycho Shift',
1597
- 'Protect', 'Roar', 'Skill Swap', 'Sleep Talk', 'Spiky Shield', 'Substitute', 'Teleport', 'Whirlwind', 'Wish', 'Yawn',
1627
+ 'Baneful Bunker', 'Block', 'Copycat', 'Corrosive Gas', 'Detect', 'Destiny Bond', 'Disable', 'Encore', 'Fairy Lock', 'Hypnosis', 'Ingrain',
1628
+ 'Instruct', 'Lovely Kiss', 'King\'s Shield', 'Mat Block', 'Mean Look', 'move:Metronome', 'Obstruct', 'Octolock', 'Nature Power', 'Parting Shot',
1629
+ 'Psycho Shift', 'Protect', 'Roar', 'Sing', 'Skill Swap', 'Sleep Powder', 'Sleep Talk', 'Spiky Shield', 'Spore', 'Substitute', 'Teleport',
1630
+ 'Whirlwind', 'Wish', 'Yawn',
1598
1631
  ],
1599
1632
  onValidateTeam(team, format, teamHas) {
1600
1633
  const problems = [];
@@ -1608,20 +1641,33 @@ export const Formats: FormatList = [
1608
1641
  validateSet(set, teamHas) {
1609
1642
  const dex = this.dex;
1610
1643
  const ability = dex.moves.get(set.ability);
1611
- // Prevent stack overflow
1612
- const overflowAbilityNames = ['Assist', 'Entrainment', 'Skill Swap'];
1613
- if (
1614
- overflowAbilityNames.includes(ability.name) || ability.category !== 'Status' || ability.status === 'slp' ||
1615
- this.ruleTable.isRestricted(`move:${ability.id}`) || set.moves.map(this.toID).includes(ability.id)
1616
- ) {
1644
+ if (!ability.exists) { // Not even a real move
1617
1645
  return this.validateSet(set, teamHas);
1618
1646
  }
1647
+ // Absolute trademark bans
1648
+ if (ability.category !== 'Status') {
1649
+ return [`${ability.name} is not a status move, and cannot be used as a trademark.`];
1650
+ }
1619
1651
  if (ability.forceSwitch || ability.selfSwitch) {
1620
1652
  return [
1621
1653
  `Force-switching and self-switching moves are banned from being used as trademarks.`,
1622
1654
  `(${ability.name} is a ${ability.forceSwitch ? 'force' : 'self'}-switching move.)`,
1623
1655
  ];
1624
1656
  }
1657
+ const irrevokablyRestricted = [
1658
+ 'Assist', 'Copycat', 'Metronome', 'Mirror Move', 'Sleep Talk', // Could call another unsafe trademark
1659
+ 'Skill Swap', // Self-propagates indefinitely
1660
+ ];
1661
+ if (irrevokablyRestricted.includes(ability.name)) {
1662
+ return [`${ability.name} cannot safely function as a trademark.`];
1663
+ }
1664
+ // Contingent trademark bans
1665
+ if (this.ruleTable.isRestricted(`move:${ability.id}`)) {
1666
+ return [`${ability.name} is restricted from being used as a trademark.`];
1667
+ }
1668
+ if (set.moves.map(this.toID).includes(ability.id)) {
1669
+ return [`${set.name} may not use ${ability.name} as both a trademark and one of its moves simultaneously.`];
1670
+ }
1625
1671
  const customRules = this.format.customRules || [];
1626
1672
  if (!customRules.includes('!obtainableabilities')) customRules.push('!obtainableabilities');
1627
1673
 
@@ -1660,71 +1706,6 @@ export const Formats: FormatList = [
1660
1706
  },
1661
1707
  },
1662
1708
  },
1663
- {
1664
- name: "[Gen 8] STABmons Mix and Mega",
1665
- desc: `Pok&eacute;mon can use any move of their typing, in addition to the moves they can normally learn. Mega evolve any Pok&eacute;mon with any mega stone and no limit. Boosts based on mega evolution from gen 7.`,
1666
- threads: [
1667
- `&bullet; <a href="https://www.smogon.com/forums/posts/8299984/">STABmons Mix and Mega</a>`,
1668
- ],
1669
-
1670
- mod: 'mixandmega',
1671
- searchShow: false,
1672
- ruleset: ['Standard', 'Dynamax Clause', 'Overflow Stat Mod', 'STABmons Move Legality'],
1673
- banlist: [
1674
- 'Calyrex-Shadow', 'Kyogre', 'Zacian', 'Zacian-Crowned', 'Moody', 'Shadow Tag', 'Beedrillite', 'Blazikenite', 'Gengarite',
1675
- 'Kangaskhanite', 'Mawilite', 'Medichamite', 'Pidgeotite', 'Baton Pass', 'Electrify', 'King\'s Rock',
1676
- ],
1677
- restricted: [
1678
- 'Calyrex-Ice', 'Dialga', 'Dragapult', 'Dragonite', 'Eternatus', 'Genesect', 'Gengar', 'Giratina', 'Giratina-Origin',
1679
- 'Groudon', 'Ho-Oh', 'Kartana', 'Keldeo', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Therian', 'Lugia', 'Lunala',
1680
- 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Rayquaza',
1681
- 'Regigigas', 'Reshiram', 'Spectrier', 'Tapu Koko', 'Urshifu', 'Urshifu-Rapid-Strike', 'Xerneas', 'Yveltal', 'Zekrom',
1682
- 'Zygarde-Base', 'Zygarde-Complete',
1683
- 'Acupressure', 'Astral Barrage', 'Belly Drum', 'Bolt Beak', 'Boomburst', 'Clangorous Soul', 'Double Iron Bash',
1684
- 'Extreme Speed', 'Fishious Rend', 'Geomancy', 'Glacial Lance', 'Lovely Kiss', 'Precipice Blades', 'Shell Smash',
1685
- 'Shift Gear', 'Sleep Powder', 'Spore', 'Thousand Arrows', 'Transform', 'V-create', 'Wicked Blow',
1686
- ],
1687
- onValidateTeam(team) {
1688
- const itemTable = new Set<ID>();
1689
- for (const set of team) {
1690
- const item = this.dex.items.get(set.item);
1691
- if (!item?.megaStone) continue;
1692
- const species = this.dex.species.get(set.species);
1693
- if (species.isNonstandard) return [`${species.baseSpecies} does not exist in gen 8.`];
1694
- if (this.ruleTable.isRestrictedSpecies(species) || this.toID(set.ability) === 'powerconstruct') {
1695
- return [`${species.name} is not allowed to hold ${item.name}.`];
1696
- }
1697
- if (itemTable.has(item.id)) {
1698
- return [`You are limited to one of each mega stone.`, `(You have more than one ${item.name})`];
1699
- }
1700
- itemTable.add(item.id);
1701
- }
1702
- },
1703
- onBegin() {
1704
- for (const pokemon of this.getAllPokemon()) {
1705
- pokemon.m.originalSpecies = pokemon.baseSpecies.name;
1706
- }
1707
- },
1708
- onSwitchIn(pokemon) {
1709
- // @ts-ignore
1710
- const oMegaSpecies = this.dex.species.get(pokemon.species.originalMega);
1711
- if (oMegaSpecies.exists && pokemon.m.originalSpecies !== oMegaSpecies.baseSpecies) {
1712
- // Place volatiles on the Pokémon to show its mega-evolved condition and details
1713
- this.add('-start', pokemon, oMegaSpecies.requiredItem || oMegaSpecies.requiredMove, '[silent]');
1714
- const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
1715
- if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
1716
- this.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
1717
- }
1718
- }
1719
- },
1720
- onSwitchOut(pokemon) {
1721
- // @ts-ignore
1722
- const oMegaSpecies = this.dex.species.get(pokemon.species.originalMega);
1723
- if (oMegaSpecies.exists && pokemon.m.originalSpecies !== oMegaSpecies.baseSpecies) {
1724
- this.add('-end', pokemon, oMegaSpecies.requiredItem || oMegaSpecies.requiredMove, '[silent]');
1725
- }
1726
- },
1727
- },
1728
1709
 
1729
1710
  // Randomized Metas
1730
1711
  ///////////////////////////////////////////////////////////////////
@@ -1745,6 +1726,7 @@ export const Formats: FormatList = [
1745
1726
 
1746
1727
  mod: 'gen8',
1747
1728
  team: 'random',
1729
+ searchShow: false,
1748
1730
  ruleset: ['[Gen 8] Random Battle', 'Dynamax Clause'],
1749
1731
  },
1750
1732
  {
@@ -1895,6 +1877,14 @@ export const Formats: FormatList = [
1895
1877
  team: 'randomFactory',
1896
1878
  ruleset: ['Obtainable', 'Sleep Clause Mod', 'Team Preview', 'HP Percentage Mod', 'Cancel Mod', 'Mega Rayquaza Clause'],
1897
1879
  },
1880
+ {
1881
+ name: "[Gen 7] Monotype Battle Factory",
1882
+ desc: `Randomized teams of Pok&eacute;mon with competitively-viable sets that all share a type.`,
1883
+
1884
+ mod: 'gen7',
1885
+ team: 'randomFactory',
1886
+ ruleset: ['[Gen 7] Battle Factory', 'Same Type Clause'],
1887
+ },
1898
1888
  {
1899
1889
  name: "[Gen 7] BSS Factory",
1900
1890
  desc: `Randomized 3v3 Singles featuring Pok&eacute;mon and movesets popular in Battle Spot Singles.`,
@@ -2012,41 +2002,40 @@ export const Formats: FormatList = [
2012
2002
  column: 3,
2013
2003
  },
2014
2004
  {
2015
- name: "[Gen 4] Ubers",
2005
+ name: "[Gen 6] Ubers",
2016
2006
  threads: [
2017
- `&bullet; <a href="https://www.smogon.com/forums/posts/8286279/">DPP Ubers</a>`,
2007
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8286277/">ORAS Ubers</a>`,
2018
2008
  ],
2019
2009
 
2020
- mod: 'gen4',
2010
+ mod: 'gen6',
2021
2011
  // searchShow: false,
2022
- ruleset: ['Standard'],
2023
- banlist: ['AG'],
2012
+ ruleset: ['Standard', 'Swagger Clause', 'Mega Rayquaza Clause'],
2024
2013
  },
2025
2014
  {
2026
- name: "[Gen 3] 1v1",
2027
- desc: `Bring three Pok&eacute;mon to Team Preview and choose one to battle.`,
2015
+ name: "[Gen 4] UU",
2028
2016
  threads: [
2029
- `&bullet; <a href="https://www.smogon.com/forums/posts/8031456/">ADV 1v1</a>`,
2017
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3532624/">DPP UU Metagame Discussion</a>`,
2018
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3503638/">DPP UU Viability Rankings</a>`,
2030
2019
  ],
2031
2020
 
2032
- mod: 'gen3',
2021
+ mod: 'gen4',
2033
2022
  // searchShow: false,
2034
- ruleset: [
2035
- 'Picked Team Size = 1', 'Max Team Size = 3',
2036
- '[Gen 3] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview',
2037
- ],
2038
- banlist: ['Clefable', 'Slaking', 'Snorlax', 'Suicune', 'Destiny Bond', 'Explosion', 'Ingrain', 'Perish Song', 'Self-Destruct', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw'],
2023
+ ruleset: ['[Gen 4] OU'],
2024
+ banlist: ['OU', 'UUBL'],
2025
+ unbanlist: ['Arena Trap'],
2039
2026
  },
2040
2027
  {
2041
- name: "[Gen 1] Tradebacks OU",
2042
- desc: `RBY OU with movepool additions from the Time Capsule.`,
2028
+ name: "[Gen 3] Doubles OU",
2043
2029
  threads: [
2044
- `&bullet; <a href="https://www.smogon.com/articles/rby-tradebacks-ou">RBY Tradebacks OU</a>`,
2030
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3666831/">ADV Doubles OU</a>`,
2045
2031
  ],
2046
2032
 
2047
- mod: 'gen1',
2033
+ mod: 'gen3',
2048
2034
  // searchShow: false,
2049
- ruleset: ['[Gen 1] OU', 'Allow Tradeback'],
2035
+ gameType: 'doubles',
2036
+ ruleset: ['Standard', '!Sleep Clause Mod', '!Switch Priority Clause Mod'],
2037
+ banlist: ['Uber'],
2038
+ unbanlist: ['Deoxys-Speed', 'Wobbuffet', 'Wynaut'],
2050
2039
  },
2051
2040
 
2052
2041
  // Past Gens OU
@@ -2089,7 +2078,7 @@ export const Formats: FormatList = [
2089
2078
 
2090
2079
  mod: 'gen5',
2091
2080
  ruleset: ['Standard', 'Evasion Abilities Clause', 'Baton Pass Clause', 'Sleep Moves Clause', 'Swagger Clause'],
2092
- banlist: ['Uber', 'Arena Trap', 'Drizzle ++ Swift Swim', 'Drought ++ Chlorophyll', 'Sand Rush', 'Shadow Tag', 'King\'s Rock', 'Razor Fang', 'Soul Dew'],
2081
+ banlist: ['Uber', 'Arena Trap', 'Drizzle ++ Swift Swim', 'Drought ++ Chlorophyll', 'Sand Rush', 'Shadow Tag', 'King\'s Rock', 'Razor Fang', 'Soul Dew', 'Assist'],
2093
2082
  },
2094
2083
  {
2095
2084
  name: "[Gen 4] OU",
@@ -2538,7 +2527,7 @@ export const Formats: FormatList = [
2538
2527
  `&bullet; <a href="https://www.smogon.com/forums/threads/3590391/">VGC 2017 Sample Teams</a>`,
2539
2528
  ],
2540
2529
 
2541
- mod: 'vgc17',
2530
+ mod: 'gen7sm',
2542
2531
  gameType: 'doubles',
2543
2532
  searchShow: false,
2544
2533
  timer: {
@@ -2550,7 +2539,7 @@ export const Formats: FormatList = [
2550
2539
  timeoutAutoChoose: true,
2551
2540
  dcTimerBank: false,
2552
2541
  },
2553
- ruleset: ['Flat Rules', 'Alola Pokedex', '!! Adjust Level = 50', 'Min Source Gen = 7'],
2542
+ ruleset: ['Flat Rules', 'Old Alola Pokedex', '!! Adjust Level = 50', 'Min Source Gen = 7'],
2554
2543
  banlist: ['Mega', 'Custap Berry', 'Enigma Berry', 'Jaboca Berry', 'Micle Berry', 'Rowap Berry'],
2555
2544
  },
2556
2545
  {
@@ -2586,16 +2575,6 @@ export const Formats: FormatList = [
2586
2575
  section: "OR/AS Singles",
2587
2576
  column: 4,
2588
2577
  },
2589
- {
2590
- name: "[Gen 6] Ubers",
2591
- threads: [
2592
- `&bullet; <a href="https://www.smogon.com/forums/posts/8286277/">ORAS Ubers</a>`,
2593
- ],
2594
-
2595
- mod: 'gen6',
2596
- searchShow: false,
2597
- ruleset: ['Standard', 'Swagger Clause', 'Mega Rayquaza Clause'],
2598
- },
2599
2578
  {
2600
2579
  name: "[Gen 6] UU",
2601
2580
  threads: [
@@ -2670,11 +2649,12 @@ export const Formats: FormatList = [
2670
2649
  searchShow: false,
2671
2650
  ruleset: ['Standard', 'Swagger Clause', 'Same Type Clause'],
2672
2651
  banlist: [
2673
- 'Aegislash', 'Altaria-Mega', 'Arceus', 'Blaziken', 'Charizard-Mega-X', 'Darkrai', 'Deoxys-Base', 'Deoxys-Attack', 'Dialga',
2674
- 'Genesect', 'Gengar-Mega', 'Giratina', 'Giratina-Origin', 'Greninja', 'Groudon', 'Ho-Oh', 'Hoopa-Unbound', 'Kangaskhan-Mega',
2675
- 'Kyogre', 'Kyurem-White', 'Lucario-Mega', 'Lugia', 'Mawile-Mega', 'Medicham-Mega', 'Metagross-Mega', 'Mewtwo', 'Palkia', 'Rayquaza',
2676
- 'Reshiram', 'Sableye-Mega', 'Salamence-Mega', 'Shaymin-Sky', 'Slowbro-Mega', 'Talonflame', 'Xerneas', 'Yveltal', 'Zekrom',
2677
- 'Shadow Tag', 'Damp Rock', 'Smooth Rock', 'Soul Dew', 'Baton Pass',
2652
+ 'Aegislash', 'Altaria-Mega', 'Arceus', 'Blaziken', 'Darkrai', 'Deoxys-Base', 'Deoxys-Attack', 'Dialga', 'Genesect', 'Gengar-Mega',
2653
+ 'Giratina', 'Giratina-Origin', 'Greninja', 'Groudon', 'Ho-Oh', 'Hoopa-Unbound', 'Kangaskhan-Mega', 'Kyogre', 'Kyurem-White',
2654
+ 'Lucario-Mega', 'Lugia', 'Mawile-Mega', 'Medicham-Mega', 'Metagross-Mega', 'Mewtwo', 'Palkia', 'Rayquaza', 'Reshiram', 'Sableye-Mega',
2655
+ 'Salamence-Mega', 'Shaymin-Sky', 'Slowbro-Mega', 'Talonflame', 'Xerneas', 'Yveltal', 'Zekrom',
2656
+ 'Shadow Tag', 'Bright Powder', 'Damp Rock', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw', 'Razor Fang', 'Smooth Rock',
2657
+ 'Soul Dew', 'Baton Pass',
2678
2658
  ],
2679
2659
  },
2680
2660
  {
@@ -2780,17 +2760,18 @@ export const Formats: FormatList = [
2780
2760
  banlist: ['Soul Dew'],
2781
2761
  },
2782
2762
  {
2783
- name: "[Gen 6] Battle Spot Doubles",
2763
+ name: "[Gen 6] VGC 2015",
2784
2764
  threads: [
2765
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3524352/">VGC 2015 Rules</a>`,
2785
2766
  `&bullet; <a href="https://www.smogon.com/forums/threads/3560820/">ORAS Battle Spot Doubles Discussion</a>`,
2786
- `&bullet; <a href="https://www.smogon.com/forums/threads/3560824/">ORAS BSD Viability Rankings</a>`,
2767
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3530547/">VGC 2015 Viability Rankings</a>`,
2787
2768
  ],
2788
2769
 
2789
2770
  mod: 'gen6',
2790
2771
  gameType: 'doubles',
2791
2772
  searchShow: false,
2792
2773
  ruleset: ['Flat Rules', 'Min Source Gen = 6'],
2793
- banlist: ['Soul Dew'],
2774
+ banlist: ['Soul Dew', 'Articuno + Snow Cloak', 'Zapdos + Static', 'Moltres + Flame Body', 'Dragonite + Barrier'],
2794
2775
  },
2795
2776
  {
2796
2777
  name: "[Gen 6] VGC 2014",
@@ -2804,6 +2785,19 @@ export const Formats: FormatList = [
2804
2785
  searchShow: false,
2805
2786
  ruleset: ['Flat Rules', 'Kalos Pokedex', 'Min Source Gen = 6'],
2806
2787
  },
2788
+ {
2789
+ name: "[Gen 6] Battle Spot Doubles",
2790
+ threads: [
2791
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3560820/">ORAS Battle Spot Doubles Discussion</a>`,
2792
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3560824/">ORAS BSD Viability Rankings</a>`,
2793
+ ],
2794
+
2795
+ mod: 'gen6',
2796
+ gameType: 'doubles',
2797
+ searchShow: false,
2798
+ ruleset: ['Flat Rules', 'Min Source Gen = 6'],
2799
+ banlist: ['Soul Dew'],
2800
+ },
2807
2801
  {
2808
2802
  name: "[Gen 6] Doubles Custom Game",
2809
2803
 
@@ -2865,8 +2859,8 @@ export const Formats: FormatList = [
2865
2859
 
2866
2860
  mod: 'gen5',
2867
2861
  searchShow: false,
2868
- ruleset: ['Standard', 'Evasion Abilities Clause', 'Baton Pass Clause', 'Swagger Clause', 'Sleep Clause Mod'],
2869
- banlist: ['Uber', 'OU', 'UUBL', 'Arena Trap', 'Drought', 'Sand Stream', 'Snow Warning'],
2862
+ ruleset: ['Standard', 'Evasion Abilities Clause', 'Swagger Clause', 'Sleep Clause Mod'],
2863
+ banlist: ['Uber', 'OU', 'UUBL', 'Arena Trap', 'Drought', 'Sand Stream', 'Snow Warning', 'Prankster + Assist', 'Prankster + Copycat', 'Baton Pass'],
2870
2864
  },
2871
2865
  {
2872
2866
  name: "[Gen 5] RU",
@@ -2877,8 +2871,9 @@ export const Formats: FormatList = [
2877
2871
 
2878
2872
  mod: 'gen5',
2879
2873
  searchShow: false,
2880
- ruleset: ['[Gen 5] UU', '!Sleep Clause Mod', 'Sleep Moves Clause'],
2874
+ ruleset: ['[Gen 5] UU', 'Baton Pass Clause', '!Sleep Clause Mod', 'Sleep Moves Clause'],
2881
2875
  banlist: ['UU', 'RUBL', 'Shadow Tag', 'Shell Smash + Baton Pass'],
2876
+ unbanlist: ['Prankster + Assist', 'Prankster + Copycat', 'Baton Pass'],
2882
2877
  },
2883
2878
  {
2884
2879
  name: "[Gen 5] NU",
@@ -2889,8 +2884,8 @@ export const Formats: FormatList = [
2889
2884
 
2890
2885
  mod: 'gen5',
2891
2886
  searchShow: false,
2892
- ruleset: ['[Gen 5] RU', '!Sleep Moves Clause', 'Sleep Clause Mod', '+Shadow Tag'],
2893
- banlist: ['RU', 'NUBL', 'Prankster + Assist'],
2887
+ ruleset: ['[Gen 5] RU', '!Sleep Moves Clause', 'Sleep Clause Mod'],
2888
+ banlist: ['RU', 'NUBL', 'Assist', 'Copycat'],
2894
2889
  },
2895
2890
  {
2896
2891
  name: "[Gen 5] PU",
@@ -2901,7 +2896,7 @@ export const Formats: FormatList = [
2901
2896
  mod: 'gen5',
2902
2897
  searchShow: false,
2903
2898
  ruleset: ['[Gen 5] NU', 'Sleep Moves Clause'],
2904
- banlist: ['NU', 'Combusken', 'Gothorita', 'Linoone', 'Riolu', 'Rotom-Frost', 'Throh', 'Vigoroth'],
2899
+ banlist: ['NU', 'Combusken', 'Gothorita', 'Linoone', 'Riolu', 'Rotom-Frost', 'Simipour', 'Throh', 'Vigoroth'],
2905
2900
  },
2906
2901
  {
2907
2902
  name: "[Gen 5] LC",
@@ -2986,7 +2981,7 @@ export const Formats: FormatList = [
2986
2981
  banlist: ['DUber', 'Soul Dew', 'Dark Void', 'Gravity'],
2987
2982
  },
2988
2983
  {
2989
- name: "[Gen 5] GBU Doubles",
2984
+ name: "[Gen 5] VGC 2013",
2990
2985
 
2991
2986
  mod: 'gen5',
2992
2987
  gameType: 'doubles',
@@ -3043,17 +3038,15 @@ export const Formats: FormatList = [
3043
3038
  column: 5,
3044
3039
  },
3045
3040
  {
3046
- name: "[Gen 4] UU",
3041
+ name: "[Gen 4] Ubers",
3047
3042
  threads: [
3048
- `&bullet; <a href="https://www.smogon.com/forums/threads/3532624/">DPP UU Metagame Discussion</a>`,
3049
- `&bullet; <a href="https://www.smogon.com/forums/threads/3503638/">DPP UU Viability Rankings</a>`,
3043
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8286279/">DPP Ubers</a>`,
3050
3044
  ],
3051
3045
 
3052
3046
  mod: 'gen4',
3053
3047
  searchShow: false,
3054
- ruleset: ['[Gen 4] OU'],
3055
- banlist: ['OU', 'UUBL'],
3056
- unbanlist: ['Arena Trap'],
3048
+ ruleset: ['Standard'],
3049
+ banlist: ['AG'],
3057
3050
  },
3058
3051
  {
3059
3052
  name: "[Gen 4] NU",
@@ -3113,7 +3106,7 @@ export const Formats: FormatList = [
3113
3106
  'Picked Team Size = 1', 'Max Team Size = 3',
3114
3107
  '[Gen 4] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview',
3115
3108
  ],
3116
- banlist: ['Latias', 'Porygon-Z', 'Snorlax', 'Togekiss', 'Focus Sash', 'Destiny Bond', 'Explosion', 'Perish Song', 'Self-Destruct'],
3109
+ banlist: ['Latias', 'Machamp', 'Porygon-Z', 'Snorlax', 'Togekiss', 'Focus Sash', 'Destiny Bond', 'Explosion', 'Perish Song', 'Self-Destruct'],
3117
3110
  unbanlist: ['Wobbuffet', 'Wynaut', 'Sand Veil'],
3118
3111
  },
3119
3112
  {
@@ -3226,6 +3219,21 @@ export const Formats: FormatList = [
3226
3219
  banlist: ['UU'],
3227
3220
  unbanlist: ['Baton Pass'],
3228
3221
  },
3222
+ {
3223
+ name: "[Gen 3] 1v1",
3224
+ desc: `Bring three Pok&eacute;mon to Team Preview and choose one to battle.`,
3225
+ threads: [
3226
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8031456/">ADV 1v1</a>`,
3227
+ ],
3228
+
3229
+ mod: 'gen3',
3230
+ searchShow: false,
3231
+ ruleset: [
3232
+ 'Picked Team Size = 1', 'Max Team Size = 3',
3233
+ '[Gen 3] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview',
3234
+ ],
3235
+ banlist: ['Clefable', 'Slaking', 'Snorlax', 'Suicune', 'Destiny Bond', 'Explosion', 'Ingrain', 'Perish Song', 'Self-Destruct', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Lax Incense', 'Quick Claw'],
3236
+ },
3229
3237
  {
3230
3238
  name: "[Gen 3] Custom Game",
3231
3239
 
@@ -3282,7 +3290,7 @@ export const Formats: FormatList = [
3282
3290
  'Picked Team Size = 1', 'Max Team Size = 3',
3283
3291
  '[Gen 2] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview',
3284
3292
  ],
3285
- banlist: ['Clefable', 'Snorlax', 'Zapdos', 'Berserk Gene', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Destiny Bond', 'Explosion', 'Present', 'Self-Destruct'],
3293
+ banlist: ['Clefable', 'Snorlax', 'Zapdos', 'Berserk Gene', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Destiny Bond', 'Explosion', 'Perish Song', 'Present', 'Self-Destruct'],
3286
3294
  },
3287
3295
  {
3288
3296
  name: "[Gen 2] Nintendo Cup 2000",
@@ -3352,20 +3360,6 @@ export const Formats: FormatList = [
3352
3360
  ruleset: ['[Gen 1] UU'],
3353
3361
  banlist: ['UU', 'NUBL'],
3354
3362
  },
3355
- {
3356
- name: "[Gen 1] Stadium OU",
3357
- threads: [
3358
- `&bullet; <a href="https://www.smogon.com/forums/threads/3685877/">Stadium OU Viability Rankings</a>`,
3359
- ],
3360
-
3361
- mod: 'gen1stadium',
3362
- searchShow: false,
3363
- ruleset: ['Standard', 'Team Preview'],
3364
- banlist: ['Uber',
3365
- 'Nidoking + Fury Attack + Thrash', 'Exeggutor + Poison Powder + Stomp', 'Exeggutor + Sleep Powder + Stomp',
3366
- 'Exeggutor + Stun Spore + Stomp', 'Jolteon + Focus Energy + Thunder Shock', 'Flareon + Focus Energy + Ember',
3367
- ],
3368
- },
3369
3363
  {
3370
3364
  name: "[Gen 1] Japanese OU",
3371
3365
  desc: `Generation 1 with Japanese battle mechanics.`,
@@ -3389,6 +3383,31 @@ export const Formats: FormatList = [
3389
3383
  ],
3390
3384
  banlist: ['Uber'],
3391
3385
  },
3386
+ {
3387
+ name: "[Gen 1] Stadium OU",
3388
+ threads: [
3389
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3685877/">Stadium OU Viability Rankings</a>`,
3390
+ ],
3391
+
3392
+ mod: 'gen1stadium',
3393
+ searchShow: false,
3394
+ ruleset: ['Standard', 'Team Preview'],
3395
+ banlist: ['Uber',
3396
+ 'Nidoking + Fury Attack + Thrash', 'Exeggutor + Poison Powder + Stomp', 'Exeggutor + Sleep Powder + Stomp',
3397
+ 'Exeggutor + Stun Spore + Stomp', 'Jolteon + Focus Energy + Thunder Shock', 'Flareon + Focus Energy + Ember',
3398
+ ],
3399
+ },
3400
+ {
3401
+ name: "[Gen 1] Tradebacks OU",
3402
+ desc: `RBY OU with movepool additions from the Time Capsule.`,
3403
+ threads: [
3404
+ `&bullet; <a href="https://www.smogon.com/articles/rby-tradebacks-ou">RBY Tradebacks OU</a>`,
3405
+ ],
3406
+
3407
+ mod: 'gen1',
3408
+ searchShow: false,
3409
+ ruleset: ['[Gen 1] OU', 'Allow Tradeback'],
3410
+ },
3392
3411
  {
3393
3412
  name: "[Gen 1] Custom Game",
3394
3413