@pkmn/sim 0.5.7 → 0.5.10

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 (66) hide show
  1. package/build/config/formats.js +442 -247
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/aliases.js +0 -2
  4. package/build/data/aliases.js.map +1 -1
  5. package/build/data/formats-data.js +3 -3
  6. package/build/data/formats-data.js.map +1 -1
  7. package/build/data/items.js +2 -2
  8. package/build/data/items.js.map +1 -1
  9. package/build/data/learnsets.js +5 -6
  10. package/build/data/learnsets.js.map +1 -1
  11. package/build/data/mods/gen2/moves.js +13 -1
  12. package/build/data/mods/gen2/moves.js.map +1 -1
  13. package/build/data/mods/gen3/formats-data.js +2 -2
  14. package/build/data/mods/gen3/formats-data.js.map +1 -1
  15. package/build/data/mods/gen4/formats-data.js +4 -4
  16. package/build/data/mods/gen4/formats-data.js.map +1 -1
  17. package/build/data/mods/gen4/moves.js +7 -5
  18. package/build/data/mods/gen4/moves.js.map +1 -1
  19. package/build/data/mods/gen5/moves.js +6 -4
  20. package/build/data/mods/gen5/moves.js.map +1 -1
  21. package/build/data/mods/gen6/items.js +2 -2
  22. package/build/data/mods/gen6/items.js.map +1 -1
  23. package/build/data/mods/gen7/moves.js +3 -3
  24. package/build/data/mods/gen7/moves.js.map +1 -1
  25. package/build/data/mods/gen7/pokedex.js +5 -0
  26. package/build/data/mods/gen7/pokedex.js.map +1 -1
  27. package/build/data/moves.js +6 -5
  28. package/build/data/moves.js.map +1 -1
  29. package/build/data/pokedex.js +3 -3
  30. package/build/data/pokedex.js.map +1 -1
  31. package/build/data/rulesets.js +23 -139
  32. package/build/data/rulesets.js.map +1 -1
  33. package/build/lib/index.js +5 -1
  34. package/build/lib/index.js.map +1 -1
  35. package/build/lib/streams.js +5 -1
  36. package/build/lib/streams.js.map +1 -1
  37. package/build/sim/dex.js +5 -1
  38. package/build/sim/dex.js.map +1 -1
  39. package/build/sim/index.js +5 -1
  40. package/build/sim/index.js.map +1 -1
  41. package/build/sim/team-validator.js +11 -0
  42. package/build/sim/team-validator.js.map +1 -1
  43. package/build/sim/teams.js +5 -1
  44. package/build/sim/teams.js.map +1 -1
  45. package/build/sim/tools/index.js +5 -1
  46. package/build/sim/tools/index.js.map +1 -1
  47. package/build/sim/tools/runner.js +5 -1
  48. package/build/sim/tools/runner.js.map +1 -1
  49. package/config/formats.ts +424 -243
  50. package/data/aliases.ts +0 -2
  51. package/data/formats-data.ts +3 -3
  52. package/data/items.ts +2 -2
  53. package/data/learnsets.ts +5 -6
  54. package/data/mods/gen2/moves.ts +13 -1
  55. package/data/mods/gen3/formats-data.ts +2 -2
  56. package/data/mods/gen4/formats-data.ts +4 -4
  57. package/data/mods/gen4/moves.ts +6 -4
  58. package/data/mods/gen5/moves.ts +6 -4
  59. package/data/mods/gen6/items.ts +2 -2
  60. package/data/mods/gen7/moves.ts +3 -3
  61. package/data/mods/gen7/pokedex.ts +5 -0
  62. package/data/moves.ts +6 -5
  63. package/data/pokedex.ts +3 -3
  64. package/data/rulesets.ts +21 -125
  65. package/package.json +2 -2
  66. package/sim/team-validator.ts +13 -0
@@ -217,8 +217,8 @@ exports.Formats = [
217
217
  mod: 'gen8',
218
218
  ruleset: ['[Gen 8] PU'],
219
219
  banlist: [
220
- 'PU', 'Aurorus', 'Centiskorch', 'Drampa', 'Exeggutor-Alola', 'Gallade', 'Haunter', 'Magmortar', 'Magneton', 'Omastar', 'Rotom-Frost',
221
- 'Turtonator', 'Vanilluxe', 'Vikavolt', 'Silvally-Dragon', 'Silvally-Ground', 'Sneasel', 'Damp Rock', 'Grassy Seed',
220
+ 'PU', 'Arctovish', 'Aurorus', 'Centiskorch', 'Drampa', 'Exeggutor-Alola', 'Gallade', 'Haunter', 'Magmortar', 'Magneton', 'Omastar',
221
+ 'Rotom-Frost', 'Turtonator', 'Vanilluxe', 'Vikavolt', 'Silvally-Dragon', 'Silvally-Ground', 'Sneasel', 'Damp Rock', 'Grassy Seed',
222
222
  ],
223
223
  },
224
224
  {
@@ -333,6 +333,11 @@ exports.Formats = [
333
333
  },
334
334
  {
335
335
  name: "[Gen 8] VGC 2022",
336
+ threads: [
337
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3677186/">VGC 2022 Metagame Discussion</a>`,
338
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3695848/">VGC 2022 Sample Teams</a>`,
339
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3696395/">VGC 2022 Viability Rankings</a>`,
340
+ ],
336
341
  mod: 'gen8',
337
342
  gameType: 'doubles',
338
343
  ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 8', 'VGC Timer', 'Limit Two Restricted'],
@@ -383,7 +388,7 @@ exports.Formats = [
383
388
  'HP Percentage Mod', 'Cancel Mod',
384
389
  ],
385
390
  banlist: [
386
- 'Pokestar Spirit', 'Shedinja + Sturdy', 'Battle Bond', 'Cheek Pouch', 'Cursed Body', 'Dry Skin', 'Fluffy', 'Fur Coat', 'Gorilla Tactics',
391
+ 'Pokestar Spirit', 'Shedinja + Sturdy', 'Battle Bond', 'Cheek Pouch', 'Cursed Body', 'Dry Skin', 'Fur Coat', 'Gorilla Tactics',
387
392
  'Grassy Surge', 'Huge Power', 'Ice Body', 'Iron Barbs', 'Libero', 'Moody', 'Neutralizing Gas', 'Parental Bond', 'Perish Body', 'Poison Heal',
388
393
  'Power Construct', 'Pressure', 'Protean', 'Pure Power', 'Rain Dish', 'Rough Skin', 'Sand Spit', 'Sand Stream', 'Snow Warning', 'Stamina',
389
394
  'Volt Absorb', 'Water Absorb', 'Wonder Guard', 'Abomasite', 'Aguav Berry', 'Assault Vest', 'Berry', 'Berry Juice', 'Berserk Gene',
@@ -438,11 +443,11 @@ exports.Formats = [
438
443
  ruleset: ['Standard NatDex', 'OHKO Clause', 'Evasion Moves Clause', 'Species Clause', 'Dynamax Clause', 'Sleep Clause Mod'],
439
444
  banlist: [
440
445
  'Alakazam-Mega', 'Arceus', 'Blastoise-Mega', 'Blaziken-Mega', 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Darkrai',
441
- 'Darmanitan-Galar', 'Deoxys-Attack', 'Deoxys-Base', 'Deoxys-Speed', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus',
446
+ 'Darmanitan-Galar', 'Deoxys-Attack', 'Deoxys-Base', 'Deoxys-Speed', 'Dialga', 'Dracovish', 'Eternatus',
442
447
  'Genesect', 'Gengar-Mega', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kangaskhan-Mega', 'Kyogre', 'Kyurem-Black',
443
448
  'Kyurem-White', 'Landorus-Base', 'Lucario-Mega', 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Metagross-Mega', 'Mewtwo',
444
449
  'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Necrozma-Ultra', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram',
445
- 'Salamence-Mega', 'Shaymin-Sky', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian',
450
+ 'Salamence-Mega', 'Shaymin-Sky', 'Solgaleo', 'Spectrier', 'Tornadus-Therian', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian',
446
451
  'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base', 'Zygarde-Complete', 'Arena Trap', 'Moody',
447
452
  'Power Construct', 'Sand Veil', 'Shadow Tag', 'Snow Cloak', 'Bright Powder', 'King\'s Rock', 'Lax Incense', 'Razor Fang',
448
453
  'Quick Claw', 'Baton Pass',
@@ -467,17 +472,16 @@ exports.Formats = [
467
472
  'Drizzle', 'Drought',
468
473
  // Slowbronite is banned so it doesn't validate on Galarian Slowbro
469
474
  'Slowbronite',
470
- // NatDex suspect
471
- 'Tornadus-Therian',
475
+ // NDOU suspect
476
+ 'Dragapult',
472
477
  ],
473
478
  // Used to distinguish UU from below UU in the client
474
479
  restricted: [
475
- 'Aegislash', 'Alakazam-Base', 'Altaria-Mega', 'Amoonguss', 'Beedrill-Mega', 'Blaziken-Base', 'Breloom', 'Celesteela',
476
- 'Chandelure', 'Donphan', 'Dracozolt', 'Dragonite', 'Feraligatr', 'Gastrodon', 'Hatterene', 'Hippowdon', 'Infernape',
477
- 'Keldeo', 'Krookodile', 'Mamoswine', 'Mandibuzz', 'Manectric-Mega', 'Melmetal', 'Mienshao', 'Moltres-Base',
478
- 'Nidoking', 'Nidoqueen', 'Nihilego', 'Quagsire', 'Regieleki', 'Ribombee', 'Rotom-Heat', 'Rotom-Wash', 'Salamence',
479
- 'Scizor', 'Skarmory', 'Slowking-Base', 'Swampert-Base', 'Talonflame', 'Tangrowth', 'Tornadus-Base', 'Umbreon',
480
- 'Urshifu-Rapid-Strike',
480
+ 'Aegislash', 'Alakazam-Base', 'Altaria-Mega', 'Amoonguss', 'Azumarill', 'Beedrill-Mega', 'Blaziken-Base', 'Breloom', 'Celesteela',
481
+ 'Chandelure', 'Donphan', 'Dracozolt', 'Dragonite', 'Feraligatr', 'Gastrodon', 'Hatterene', 'Hippowdon', 'Infernape', 'Keldeo',
482
+ 'Krookodile', 'Mamoswine', 'Mandibuzz', 'Manectric-Mega', 'Melmetal', 'Mienshao', 'Moltres-Base', 'Nidoking', 'Nidoqueen', 'Nihilego',
483
+ 'Quagsire', 'Regieleki', 'Ribombee', 'Rotom-Heat', 'Rotom-Wash', 'Salamence', 'Scizor', 'Skarmory', 'Slowking-Base', 'Swampert-Base',
484
+ 'Talonflame', 'Tangrowth', 'Tornadus-Base', 'Umbreon', 'Urshifu-Rapid-Strike',
481
485
  ],
482
486
  },
483
487
  {
@@ -587,134 +591,212 @@ exports.Formats = [
587
591
  column: 2,
588
592
  },
589
593
  {
590
- name: "[Gen 8] Trademarked",
591
- desc: `Sacrifice your Pok&eacute;mon's ability for a status move that activates on switch-in.`,
594
+ name: "[Gen 8] Shared Power",
595
+ desc: `Once a Pok&eacute;mon switches in, its ability is shared with the rest of the team.`,
592
596
  threads: [
593
- `&bullet; <a href="https://www.smogon.com/forums/threads/3656980/">Trademarked</a>`,
597
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3660877/">Shared Power</a>`,
594
598
  ],
595
- mod: 'gen8',
599
+ mod: 'sharedpower',
596
600
  // searchShow: false,
597
601
  ruleset: ['Standard', 'Dynamax Clause'],
598
602
  banlist: [
599
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Kyurem-Black', 'Kyurem-White',
600
- 'Giratina', 'Giratina-Origin', 'Genesect', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Lugia', 'Lunala', 'Magearna', 'Marowak-Alola',
601
- 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza',
602
- 'Reshiram', 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned',
603
- 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Shadow Tag', 'Baton Pass',
603
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
604
+ 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna',
605
+ 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
606
+ 'Pheromosa', 'Rayquaza', 'Reshiram', 'Shedinja', 'Solgaleo', 'Urshifu-Base', 'Urshifu-Rapid-Strike',
607
+ 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom',
608
+ 'Arena Trap', 'Contrary', 'Drizzle ++ Swift Swim', 'Drought ++ Chlorophyll', 'Electric Surge ++ Surge Surfer',
609
+ 'Fur Coat', 'Guts', 'Harvest', 'Huge Power', 'Imposter', 'Innards Out', 'Libero', 'Magic Bounce', 'Magic Guard',
610
+ 'Magnet Pull', 'Mold Breaker', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Queenly Majesty', 'Quick Draw',
611
+ 'Regenerator', 'Sand Rush', 'Sand Veil', 'Shadow Tag', 'Simple', 'Snow Cloak', 'Snow Warning ++ Slush Rush', 'Speed Boost',
612
+ 'Stakeout', 'Steelworker ++ Steely Spirit', 'Tinted Lens', 'Triage', 'Unaware', 'Unburden', 'Water Bubble',
613
+ 'Baton Pass',
604
614
  ],
605
- restricted: [
606
- 'Baneful Bunker', 'Block', 'Copycat', 'Corrosive Gas', 'Detect', 'Destiny Bond', 'Disable', 'Encore', 'Fairy Lock', 'Hypnosis', 'Ingrain',
607
- 'Instruct', 'Lovely Kiss', 'King\'s Shield', 'Mat Block', 'Mean Look', 'Memento', 'move:Metronome', 'Obstruct', 'Octolock', 'Nature Power',
608
- 'Parting Shot', 'Psycho Shift', 'Protect', 'Roar', 'Sing', 'Skill Swap', 'Sleep Powder', 'Sleep Talk', 'Spiky Shield', 'Spore', 'Substitute',
609
- 'Teleport', 'Whirlwind', 'Wish', 'Yawn',
615
+ getSharedPower(pokemon) {
616
+ const sharedPower = new Set();
617
+ for (const ally of pokemon.side.pokemon) {
618
+ if (ally.previouslySwitchedIn > 0) {
619
+ if (pokemon.battle.dex.currentMod !== 'sharedpower' && ['trace', 'mirrorarmor'].includes(ally.baseAbility)) {
620
+ sharedPower.add('noability');
621
+ continue;
622
+ }
623
+ sharedPower.add(ally.baseAbility);
624
+ }
625
+ }
626
+ sharedPower.delete(pokemon.baseAbility);
627
+ return sharedPower;
628
+ },
629
+ onBeforeSwitchIn(pokemon) {
630
+ let format = this.format;
631
+ if (!format.getSharedPower)
632
+ format = this.dex.formats.get('gen8sharedpower');
633
+ for (const ability of format.getSharedPower(pokemon)) {
634
+ const effect = 'ability:' + ability;
635
+ pokemon.volatiles[effect] = { id: this.toID(effect), target: pokemon };
636
+ if (!pokemon.m.abils)
637
+ pokemon.m.abils = [];
638
+ if (!pokemon.m.abils.includes(effect))
639
+ pokemon.m.abils.push(effect);
640
+ }
641
+ },
642
+ onSwitchInPriority: 2,
643
+ onSwitchIn(pokemon) {
644
+ let format = this.format;
645
+ if (!format.getSharedPower)
646
+ format = this.dex.formats.get('gen8sharedpower');
647
+ for (const ability of format.getSharedPower(pokemon)) {
648
+ if (ability === 'noability') {
649
+ this.hint(`Mirror Armor and Trace break in Shared Power formats that don't use Shared Power as a base, so they get removed from non-base users.`);
650
+ }
651
+ const effect = 'ability:' + ability;
652
+ delete pokemon.volatiles[effect];
653
+ pokemon.addVolatile(effect);
654
+ }
655
+ },
656
+ },
657
+ {
658
+ name: "[Gen 8] Cross Evolution",
659
+ 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.`,
660
+ threads: [
661
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3657562/">Cross Evolution</a>`,
610
662
  ],
611
- onValidateTeam(team, format, teamHas) {
612
- const problems = [];
613
- for (const trademark in teamHas.trademarks) {
614
- if (teamHas.trademarks[trademark] > 1) {
615
- problems.push(`You are limited to 1 of each Trademark.`, `(You have ${teamHas.trademarks[trademark]} Pok\u00e9mon with ${trademark} as a Trademark.)`);
663
+ mod: 'gen8',
664
+ // searchShow: false,
665
+ ruleset: ['Standard', 'Overflow Stat Mod', 'Dynamax Clause'],
666
+ banlist: ['Corsola-Galar', 'Sneasel', 'Type: Null', 'Arena Trap', 'Ice Scales', 'Moody', 'King\'s Rock', 'Baton Pass'],
667
+ restricted: ['Chansey', 'Lunala', 'Shedinja', 'Solgaleo', 'Gorilla Tactics', 'Huge Power', 'Pure Power', 'Shadow Tag'],
668
+ onValidateTeam(team) {
669
+ const names = new Set();
670
+ for (const set of team) {
671
+ const name = set.name;
672
+ if (names.has(this.dex.toID(name))) {
673
+ return [
674
+ `Your Pok\u00e9mon must have different nicknames.`,
675
+ `(You have more than one Pok\u00e9mon named '${name}')`,
676
+ ];
616
677
  }
678
+ names.add(this.dex.toID(name));
617
679
  }
618
- return problems;
680
+ if (!names.size) {
681
+ return [
682
+ `${this.format.name} works using nicknames; your team has 0 nicknamed Pok\u00e9mon.`,
683
+ `(If this was intentional, add a nickname to one Pok\u00e9mon that isn't the name of a Pok\u00e9mon species.)`,
684
+ ];
685
+ }
686
+ },
687
+ checkCanLearn(move, species, lsetData, set) {
688
+ // @ts-ignore
689
+ if (!set.sp?.exists || !set.crossSpecies?.exists) {
690
+ return this.checkCanLearn(move, species, lsetData, set);
691
+ }
692
+ // @ts-ignore
693
+ const problem = this.checkCanLearn(move, set.sp);
694
+ if (!problem)
695
+ return null;
696
+ // @ts-ignore
697
+ if (!set.crossMovesLeft)
698
+ return problem;
699
+ // @ts-ignore
700
+ if (this.checkCanLearn(move, set.crossSpecies))
701
+ return problem;
702
+ // @ts-ignore
703
+ set.crossMovesLeft--;
704
+ return null;
619
705
  },
620
706
  validateSet(set, teamHas) {
621
- const dex = this.dex;
622
- const ability = dex.moves.get(set.ability);
623
- if (!ability.exists) { // Not even a real move
707
+ const crossSpecies = this.dex.species.get(set.name);
708
+ let problems = this.dex.formats.get('Pokemon').onChangeSet?.call(this, set, this.format) || null;
709
+ if (Array.isArray(problems) && problems.length)
710
+ return problems;
711
+ const crossNonstandard = (!this.ruleTable.has('standardnatdex') && crossSpecies.isNonstandard === 'Past') ||
712
+ crossSpecies.isNonstandard === 'Future';
713
+ const crossIsCap = !this.ruleTable.has('+pokemontag:cap') && crossSpecies.isNonstandard === 'CAP';
714
+ if (!crossSpecies.exists || crossNonstandard || crossIsCap)
715
+ return this.validateSet(set, teamHas);
716
+ const species = this.dex.species.get(set.species);
717
+ const check = this.checkSpecies(set, species, species, {});
718
+ if (check)
719
+ return [check];
720
+ const nonstandard = !this.ruleTable.has('standardnatdex') && species.isNonstandard === 'Past';
721
+ const isCap = !this.ruleTable.has('+pokemontag:cap') && species.isNonstandard === 'CAP';
722
+ if (!species.exists || nonstandard || isCap || species === crossSpecies)
624
723
  return this.validateSet(set, teamHas);
724
+ if (!species.nfe)
725
+ return [`${species.name} cannot cross evolve because it doesn't evolve.`];
726
+ const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
727
+ if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo) {
728
+ return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it isn't an evolution.`];
625
729
  }
626
- // Absolute trademark bans
627
- if (ability.category !== 'Status') {
628
- return [`${ability.name} is not a status move, and cannot be used as a trademark.`];
730
+ if (this.ruleTable.isRestrictedSpecies(crossSpecies)) {
731
+ return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it is banned.`];
629
732
  }
630
- if (ability.forceSwitch || ability.selfSwitch) {
733
+ const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
734
+ if (!crossPrevoSpecies.prevo !== !species.prevo) {
631
735
  return [
632
- `Force-switching and self-switching moves are banned from being used as trademarks.`,
633
- `(${ability.name} is a ${ability.forceSwitch ? 'force' : 'self'}-switching move.)`,
736
+ `${species.name} cannot cross evolve into ${crossSpecies.name} because they are not consecutive evolution stages.`,
634
737
  ];
635
738
  }
636
- const irrevokablyRestricted = [
637
- 'Assist', 'Copycat', 'Metronome', 'Mirror Move', 'Sleep Talk',
638
- 'Skill Swap', // Self-propagates indefinitely
639
- ];
640
- if (irrevokablyRestricted.includes(ability.name)) {
641
- return [`${ability.name} cannot safely function as a trademark.`];
739
+ const ability = this.dex.abilities.get(set.ability);
740
+ if (!this.ruleTable.isRestricted(`ability:${ability.id}`) || Object.values(species.abilities).includes(ability.name)) {
741
+ set.species = crossSpecies.name;
642
742
  }
643
- // Contingent trademark bans
644
- if (this.ruleTable.isRestricted(`move:${ability.id}`)) {
645
- return [`${ability.name} is restricted from being used as a trademark.`];
743
+ // @ts-ignore
744
+ set.sp = species;
745
+ // @ts-ignore
746
+ set.crossSpecies = crossSpecies;
747
+ // @ts-ignore
748
+ set.crossMovesLeft = 2;
749
+ problems = this.validateSet(set, teamHas);
750
+ set.name = crossSpecies.name;
751
+ set.species = species.name;
752
+ return problems;
753
+ },
754
+ onModifySpecies(species, target, source, effect) {
755
+ if (!target)
756
+ return; // chat
757
+ if (effect && ['imposter', 'transform'].includes(effect.id))
758
+ return;
759
+ if (target.set.name === target.set.species)
760
+ return;
761
+ const crossSpecies = this.dex.species.get(target.set.name);
762
+ if (!crossSpecies.exists)
763
+ return;
764
+ if (species.battleOnly || !species.nfe)
765
+ return;
766
+ const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
767
+ if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo)
768
+ return;
769
+ const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
770
+ if (!crossPrevoSpecies.prevo !== !species.prevo)
771
+ return;
772
+ const mixedSpecies = this.dex.deepClone(species);
773
+ mixedSpecies.baseSpecies = mixedSpecies.name = `${species.name}-${crossSpecies.name}`;
774
+ mixedSpecies.weightkg =
775
+ Math.max(0.1, +(species.weightkg + crossSpecies.weightkg - crossPrevoSpecies.weightkg)).toFixed(1);
776
+ mixedSpecies.nfe = false;
777
+ mixedSpecies.evos = [];
778
+ mixedSpecies.eggGroups = crossSpecies.eggGroups;
779
+ mixedSpecies.abilities = crossSpecies.abilities;
780
+ mixedSpecies.bst = 0;
781
+ let i;
782
+ for (i in species.baseStats) {
783
+ const statChange = crossSpecies.baseStats[i] - crossPrevoSpecies.baseStats[i];
784
+ mixedSpecies.baseStats[i] = this.clampIntRange(species.baseStats[i] + statChange, 1, 255);
785
+ mixedSpecies.bst += mixedSpecies.baseStats[i];
646
786
  }
647
- if (set.moves.map(this.toID).includes(ability.id)) {
648
- return [`${set.name} may not use ${ability.name} as both a trademark and one of its moves simultaneously.`];
787
+ if (crossSpecies.types[0] !== crossPrevoSpecies.types[0])
788
+ mixedSpecies.types[0] = crossSpecies.types[0];
789
+ if (crossSpecies.types[1] !== crossPrevoSpecies.types[1]) {
790
+ mixedSpecies.types[1] = crossSpecies.types[1] || crossSpecies.types[0];
649
791
  }
650
- const customRules = this.format.customRules || [];
651
- if (!customRules.includes('!obtainableabilities'))
652
- customRules.push('!obtainableabilities');
653
- const TeamValidator = require('../sim/team-validator').TeamValidator;
654
- const validator = new TeamValidator(dex.formats.get(`${this.format.id}@@@${customRules.join(',')}`));
655
- const moves = set.moves;
656
- set.moves = [ability.id];
657
- set.ability = dex.species.get(set.species).abilities['0'];
658
- let problems = validator.validateSet(set, {}) || [];
659
- if (problems.length)
660
- return problems;
661
- set.moves = moves;
662
- set.ability = dex.species.get(set.species).abilities['0'];
663
- problems = problems.concat(validator.validateSet(set, teamHas) || []);
664
- set.ability = ability.id;
665
- if (!teamHas.trademarks)
666
- teamHas.trademarks = {};
667
- teamHas.trademarks[ability.name] = (teamHas.trademarks[ability.name] || 0) + 1;
668
- return problems.length ? problems : null;
792
+ if (mixedSpecies.types[0] === mixedSpecies.types[1])
793
+ mixedSpecies.types = [mixedSpecies.types[0]];
794
+ return mixedSpecies;
669
795
  },
670
- pokemon: {
671
- getAbility() {
672
- const move = this.battle.dex.moves.get(this.battle.toID(this.ability));
673
- if (!move.exists)
674
- return Object.getPrototypeOf(this).getAbility.call(this);
675
- return {
676
- id: move.id,
677
- name: move.name,
678
- onStart(pokemon) {
679
- this.add('-activate', pokemon, 'ability: ' + move.name);
680
- this.actions.useMove(move, pokemon);
681
- },
682
- toString() {
683
- return "";
684
- },
685
- };
686
- },
687
- },
688
- },
689
- {
690
- name: "[Gen 8] Linked",
691
- desc: `The first two moves in a Pok&eacute;mon's moveset are used simultaneously.`,
692
- threads: [
693
- `&bullet; <a href="https://www.smogon.com/forums/threads/3660421/">Linked</a>`,
694
- ],
695
- mod: 'linked',
696
- ruleset: ['Standard', 'Dynamax Clause'],
697
- banlist: [
698
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Cloyster', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
699
- 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala', 'Magearna',
700
- 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Solgaleo',
701
- 'Spectrier', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base',
702
- 'Zygarde-Complete', 'Arena Trap', 'Chlorophyll', 'Moody', 'Power Construct', 'Sand Rush', 'Sand Veil', 'Shadow Tag', 'Slush Rush', 'Snow Cloak',
703
- 'Surge Surfer', 'Swift Swim', 'Unburden', 'Bright Powder', 'King\'s Rock', 'Lax Incense', 'Baton Pass',
704
- ],
705
- restricted: [
706
- 'Baneful Bunker', 'Bounce', 'Protect', 'Detect', 'Dig', 'Dive', 'Fly', 'King\'s Shield', 'Nature\'s Madness', 'Night Shade',
707
- 'Obstruct', 'Phantom Force', 'Seismic Toss', 'Shadow Force', 'Sky Drop', 'Spiky Shield', 'Super Fang', 'Trick Room',
708
- ],
709
- onValidateSet(set) {
710
- const problems = [];
711
- for (const [i, moveid] of set.moves.entries()) {
712
- const move = this.dex.moves.get(moveid);
713
- if ([0, 1].includes(i) && this.ruleTable.isRestricted(`move:${move.id}`)) {
714
- problems.push(`${set.name || set.species}'s move ${move.name} cannot be linked.`);
715
- }
796
+ onBegin() {
797
+ for (const pokemon of this.getAllPokemon()) {
798
+ pokemon.baseSpecies = pokemon.species;
716
799
  }
717
- return problems;
718
800
  },
719
801
  },
720
802
  // Other Metagames
@@ -860,17 +942,17 @@ exports.Formats = [
860
942
  mod: 'gen8',
861
943
  ruleset: ['Standard', 'STABmons Move Legality', 'Dynamax Clause', 'Sleep Moves Clause', '!Sleep Clause Mod'],
862
944
  banlist: [
863
- 'Aegislash', 'Blacephalon', 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Dragonite',
864
- 'Eternatus', 'Genesect', 'Garchomp', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black',
865
- 'Kyurem-White', 'Landorus', 'Landorus-Therian', 'Lugia', 'Lunala', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings',
866
- 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Porygon-Z', 'Rayquaza', 'Reshiram', 'Silvally', 'Solgaleo', 'Spectrier', 'Tapu Bulu',
867
- 'Tapu Koko', 'Thundurus-Base', 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned',
868
- 'Zapdos-Galar', 'Zekrom', 'Zygarde-Base', 'Arena Trap', 'Magnet Pull', 'Moody', 'Power Construct', 'Shadow Tag', 'King\'s Rock',
869
- 'Baton Pass',
945
+ 'Aegislash', 'Blacephalon', 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Dragonite', 'Eternatus',
946
+ 'Genesect', 'Garchomp', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus',
947
+ 'Landorus-Therian', 'Lugia', 'Lunala', 'Magearna', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
948
+ 'Pheromosa', 'Porygon-Z', 'Rayquaza', 'Reshiram', 'Silvally', 'Solgaleo', 'Spectrier', 'Tapu Bulu', 'Tapu Koko', 'Tapu Lele', 'Thundurus-Base',
949
+ 'Urshifu-Base', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zapdos-Galar', 'Zekrom', 'Zygarde-Base',
950
+ 'Arena Trap', 'Magnet Pull', 'Moody', 'Power Construct', 'Shadow Tag', 'King\'s Rock', 'Baton Pass',
870
951
  ],
871
952
  restricted: [
872
953
  'Acupressure', 'Astral Barrage', 'Belly Drum', 'Bolt Beak', 'Clangorous Soul', 'Double Iron Bash', 'Electrify', 'Extreme Speed', 'Fishious Rend',
873
- 'Geomancy', 'Glacial Lance', 'Oblivion Wing', 'Precipice Blades', 'Shell Smash', 'Shift Gear', 'Thousand Arrows', 'V-create', 'Wicked Blow',
954
+ 'Geomancy', 'Glacial Lance', 'Oblivion Wing', 'Precipice Blades', 'Shell Smash', 'Shift Gear', 'Thousand Arrows', 'Thunderous Kick', 'V-create',
955
+ 'Wicked Blow',
874
956
  ],
875
957
  },
876
958
  {
@@ -1023,7 +1105,6 @@ exports.Formats = [
1023
1105
  `&bullet; <a href="https://www.smogon.com/forums/threads/3697080/">BDSP NU</a>`,
1024
1106
  ],
1025
1107
  mod: 'gen8bdsp',
1026
- searchShow: false,
1027
1108
  ruleset: ['[Gen 8 BDSP] RU'],
1028
1109
  banlist: ['RU', 'NUBL'],
1029
1110
  },
@@ -1106,7 +1187,7 @@ exports.Formats = [
1106
1187
  ],
1107
1188
  mod: 'gen8',
1108
1189
  searchShow: false,
1109
- 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'],
1190
+ ruleset: ['Standard', 'Dynamax Clause', 'Camomons Mod'],
1110
1191
  banlist: [
1111
1192
  'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragonite', 'Eternatus', 'Genesect', 'Giratina', 'Giratina-Origin',
1112
1193
  'Groudon', 'Ho-Oh', 'Hydreigon', 'Kartana', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Latias', 'Latios', 'Lugia',
@@ -1114,21 +1195,6 @@ exports.Formats = [
1114
1195
  'Reuniclus', 'Shedinja', 'Slowking-Galar', 'Solgaleo', 'Spectrier', 'Tornadus-Therian', 'Volcarona', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned',
1115
1196
  'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zeraora', 'Zygarde-Base', 'Arena Trap', 'Moody', 'Power Construct', 'Shadow Tag', 'Baton Pass',
1116
1197
  ],
1117
- onModifySpeciesPriority: 2,
1118
- onModifySpecies(species, target, source, effect) {
1119
- if (!target)
1120
- return; // Chat command
1121
- if (effect && ['imposter', 'transform'].includes(effect.id))
1122
- return;
1123
- const types = [...new Set(target.baseMoveSlots.slice(0, 2).map(move => this.dex.moves.get(move.id).type))];
1124
- return { ...species, types: types };
1125
- },
1126
- onSwitchIn(pokemon) {
1127
- this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
1128
- },
1129
- onAfterMega(pokemon) {
1130
- this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
1131
- },
1132
1198
  },
1133
1199
  {
1134
1200
  name: "[Gen 8] Inheritance",
@@ -1318,6 +1384,38 @@ exports.Formats = [
1318
1384
  this.add('-start', pokemon, donorTemplate.name, '[silent]');
1319
1385
  },
1320
1386
  },
1387
+ {
1388
+ name: "[Gen 8] Linked",
1389
+ desc: `The first two moves in a Pok&eacute;mon's moveset are used simultaneously.`,
1390
+ threads: [
1391
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3660421/">Linked</a>`,
1392
+ ],
1393
+ mod: 'linked',
1394
+ searchShow: false,
1395
+ ruleset: ['Standard', 'Dynamax Clause'],
1396
+ banlist: [
1397
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Cloyster', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
1398
+ 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala',
1399
+ 'Magearna', 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram',
1400
+ 'Solgaleo', 'Spectrier', 'Urshifu-Base', 'Volcarona', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned',
1401
+ 'Zekrom', 'Zygarde-Base', 'Zygarde-Complete', 'Arena Trap', 'Chlorophyll', 'Moody', 'Power Construct', 'Sand Rush', 'Sand Veil', 'Shadow Tag',
1402
+ 'Slush Rush', 'Snow Cloak', 'Speed Boost', 'Surge Surfer', 'Swift Swim', 'Unburden', 'Bright Powder', 'King\'s Rock', 'Lax Incense', 'Baton Pass',
1403
+ ],
1404
+ restricted: [
1405
+ 'Baneful Bunker', 'Bounce', 'Protect', 'Detect', 'Dig', 'Dive', 'Fly', 'King\'s Shield', 'Nature\'s Madness', 'Night Shade',
1406
+ 'Obstruct', 'Phantom Force', 'Seismic Toss', 'Shadow Force', 'Sky Drop', 'Spiky Shield', 'Super Fang', 'Trick Room',
1407
+ ],
1408
+ onValidateSet(set) {
1409
+ const problems = [];
1410
+ for (const [i, moveid] of set.moves.entries()) {
1411
+ const move = this.dex.moves.get(moveid);
1412
+ if ([0, 1].includes(i) && this.ruleTable.isRestricted(`move:${move.id}`)) {
1413
+ problems.push(`${set.name || set.species}'s move ${move.name} cannot be linked.`);
1414
+ }
1415
+ }
1416
+ return problems;
1417
+ },
1418
+ },
1321
1419
  {
1322
1420
  name: "[Gen 8] Multibility",
1323
1421
  desc: `Run a second ability at the cost of giving up a Pok&eacute;mon's item slot.`,
@@ -1599,6 +1697,21 @@ exports.Formats = [
1599
1697
  // Shadow Tag/Arena Trap
1600
1698
  'Diglett-Base', 'Dugtrio-Base', 'Gothita', 'Gothitelle', 'Gothorita', 'Trapinch', 'Wobbuffet', 'Wynaut',
1601
1699
  ],
1700
+ onValidateSet(set) {
1701
+ const species = this.dex.species.get(set.species);
1702
+ const unSeenAbilities = Object.keys(species.abilities)
1703
+ .filter(key => key !== 'S' && (key !== 'H' || !species.unreleasedHidden))
1704
+ .map(key => species.abilities[key])
1705
+ .filter(ability => ability !== set.ability);
1706
+ if (unSeenAbilities.length && this.toID(set.ability) !== this.toID(species.abilities['S'])) {
1707
+ for (const abilityName of unSeenAbilities) {
1708
+ const banReason = this.ruleTable.check('ability:' + this.toID(abilityName));
1709
+ if (banReason) {
1710
+ return [`${set.name}'s ability ${abilityName} is ${banReason}.`];
1711
+ }
1712
+ }
1713
+ }
1714
+ },
1602
1715
  onBegin() {
1603
1716
  for (const pokemon of this.getAllPokemon()) {
1604
1717
  if (pokemon.ability === this.toID(pokemon.species.abilities['S'])) {
@@ -1626,67 +1739,113 @@ exports.Formats = [
1626
1739
  },
1627
1740
  },
1628
1741
  {
1629
- name: "[Gen 8] Shared Power",
1630
- desc: `Once a Pok&eacute;mon switches in, its ability is shared with the rest of the team.`,
1742
+ name: "[Gen 8] Trademarked",
1743
+ desc: `Sacrifice your Pok&eacute;mon's ability for a status move that activates on switch-in.`,
1631
1744
  threads: [
1632
- `&bullet; <a href="https://www.smogon.com/forums/threads/3660877/">Shared Power</a>`,
1745
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3656980/">Trademarked</a>`,
1633
1746
  ],
1634
- mod: 'sharedpower',
1747
+ mod: 'gen8',
1748
+ // While bugs are being fixed
1635
1749
  searchShow: false,
1750
+ challengeShow: false,
1751
+ tournamentShow: false,
1636
1752
  ruleset: ['Standard', 'Dynamax Clause'],
1637
1753
  banlist: [
1638
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
1639
- 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna',
1640
- 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
1641
- 'Pheromosa', 'Rayquaza', 'Reshiram', 'Shedinja', 'Solgaleo', 'Urshifu-Base', 'Urshifu-Rapid-Strike',
1642
- 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom',
1643
- 'Arena Trap', 'Contrary', 'Drizzle ++ Swift Swim', 'Drought ++ Chlorophyll', 'Electric Surge ++ Surge Surfer',
1644
- 'Fur Coat', 'Guts', 'Harvest', 'Huge Power', 'Imposter', 'Innards Out', 'Libero', 'Magic Bounce', 'Magic Guard',
1645
- 'Magnet Pull', 'Mold Breaker', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Queenly Majesty', 'Quick Draw',
1646
- 'Regenerator', 'Sand Rush', 'Sand Veil', 'Shadow Tag', 'Simple', 'Snow Cloak', 'Snow Warning ++ Slush Rush', 'Speed Boost',
1647
- 'Stakeout', 'Steelworker ++ Steely Spirit', 'Tinted Lens', 'Triage', 'Unaware', 'Unburden', 'Water Bubble',
1648
- 'Baton Pass',
1754
+ 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Kyurem-Black', 'Kyurem-White', 'Giratina',
1755
+ 'Giratina-Origin', 'Genesect', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Lugia', 'Lunala', 'Magearna', 'Marowak-Alola', 'Marshadow', 'Melmetal',
1756
+ 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Solgaleo', 'Spectrier',
1757
+ 'Urshifu-Base', 'Victini', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base',
1758
+ 'Arena Trap', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Shadow Tag', 'Baton Pass',
1649
1759
  ],
1650
- getSharedPower(pokemon) {
1651
- const sharedPower = new Set();
1652
- for (const ally of pokemon.side.pokemon) {
1653
- if (ally.previouslySwitchedIn > 0) {
1654
- if (pokemon.battle.dex.currentMod !== 'sharedpower' && ['trace', 'mirrorarmor'].includes(ally.baseAbility)) {
1655
- sharedPower.add('noability');
1656
- continue;
1657
- }
1658
- sharedPower.add(ally.baseAbility);
1760
+ restricted: [
1761
+ 'Baneful Bunker', 'Block', 'Copycat', 'Corrosive Gas', 'Detect', 'Destiny Bond', 'Disable', 'Encore', 'Fairy Lock', 'Hypnosis', 'Ingrain',
1762
+ 'Instruct', 'Lovely Kiss', 'King\'s Shield', 'Mat Block', 'Mean Look', 'Memento', 'move:Metronome', 'Obstruct', 'Octolock', 'Nature Power',
1763
+ 'Parting Shot', 'Psycho Shift', 'Protect', 'Roar', 'Sing', 'Skill Swap', 'Sleep Powder', 'Sleep Talk', 'Spiky Shield', 'Spore', 'Substitute',
1764
+ 'Switcheroo', 'Teleport', 'Trick', 'Whirlwind', 'Wish', 'Yawn',
1765
+ ],
1766
+ onValidateTeam(team, format, teamHas) {
1767
+ const problems = [];
1768
+ for (const trademark in teamHas.trademarks) {
1769
+ if (teamHas.trademarks[trademark] > 1) {
1770
+ problems.push(`You are limited to 1 of each Trademark.`, `(You have ${teamHas.trademarks[trademark]} Pok\u00e9mon with ${trademark} as a Trademark.)`);
1659
1771
  }
1660
1772
  }
1661
- sharedPower.delete(pokemon.baseAbility);
1662
- return sharedPower;
1773
+ return problems;
1663
1774
  },
1664
- onBeforeSwitchIn(pokemon) {
1665
- let format = this.format;
1666
- if (!format.getSharedPower)
1667
- format = this.dex.formats.get('gen8sharedpower');
1668
- for (const ability of format.getSharedPower(pokemon)) {
1669
- const effect = 'ability:' + ability;
1670
- pokemon.volatiles[effect] = { id: this.toID(effect), target: pokemon };
1671
- if (!pokemon.m.abils)
1672
- pokemon.m.abils = [];
1673
- if (!pokemon.m.abils.includes(effect))
1674
- pokemon.m.abils.push(effect);
1775
+ validateSet(set, teamHas) {
1776
+ const dex = this.dex;
1777
+ const ability = dex.moves.get(set.ability);
1778
+ if (!ability.exists) { // Not even a real move
1779
+ return this.validateSet(set, teamHas);
1675
1780
  }
1676
- },
1677
- onSwitchInPriority: 2,
1678
- onSwitchIn(pokemon) {
1679
- let format = this.format;
1680
- if (!format.getSharedPower)
1681
- format = this.dex.formats.get('gen8sharedpower');
1682
- for (const ability of format.getSharedPower(pokemon)) {
1683
- if (ability === 'noability') {
1684
- this.hint(`Mirror Armor and Trace break in Shared Power formats that don't use Shared Power as a base, so they get removed from non-base users.`);
1781
+ // Absolute trademark bans
1782
+ if (ability.category !== 'Status') {
1783
+ return [`${ability.name} is not a status move, and cannot be used as a trademark.`];
1784
+ }
1785
+ if (ability.forceSwitch || ability.selfSwitch) {
1786
+ return [
1787
+ `Force-switching and self-switching moves are banned from being used as trademarks.`,
1788
+ `(${ability.name} is a ${ability.forceSwitch ? 'force' : 'self'}-switching move.)`,
1789
+ ];
1790
+ }
1791
+ const irrevokablyRestricted = [
1792
+ 'Assist', 'Copycat', 'Metronome', 'Mirror Move', 'Sleep Talk',
1793
+ 'Recycle', 'Trace',
1794
+ 'Skill Swap', // Self-propagates indefinitely
1795
+ ];
1796
+ for (const m of set.moves) {
1797
+ const move = dex.moves.get(m);
1798
+ if (irrevokablyRestricted.includes(move.name)) {
1799
+ return [`${move.name} is banned from Trademark, irrespective of custom rules, because it can cause endless turns.`];
1685
1800
  }
1686
- const effect = 'ability:' + ability;
1687
- delete pokemon.volatiles[effect];
1688
- pokemon.addVolatile(effect);
1689
1801
  }
1802
+ if (irrevokablyRestricted.includes(ability.name)) {
1803
+ return [`${ability.name} cannot safely function as a trademark.`];
1804
+ }
1805
+ // Contingent trademark bans
1806
+ if (this.ruleTable.isRestricted(`move:${ability.id}`)) {
1807
+ return [`${ability.name} is restricted from being used as a trademark.`];
1808
+ }
1809
+ if (set.moves.map(this.toID).includes(ability.id)) {
1810
+ return [`${set.name} may not use ${ability.name} as both a trademark and one of its moves simultaneously.`];
1811
+ }
1812
+ const customRules = this.format.customRules || [];
1813
+ if (!customRules.includes('!obtainableabilities'))
1814
+ customRules.push('!obtainableabilities');
1815
+ const TeamValidator = require('../sim/team-validator').TeamValidator;
1816
+ const validator = new TeamValidator(dex.formats.get(`${this.format.id}@@@${customRules.join(',')}`));
1817
+ const moves = set.moves;
1818
+ set.moves = [ability.id];
1819
+ set.ability = dex.species.get(set.species).abilities['0'];
1820
+ let problems = validator.validateSet(set, {}) || [];
1821
+ if (problems.length)
1822
+ return problems;
1823
+ set.moves = moves;
1824
+ set.ability = dex.species.get(set.species).abilities['0'];
1825
+ problems = problems.concat(validator.validateSet(set, teamHas) || []);
1826
+ set.ability = ability.id;
1827
+ if (!teamHas.trademarks)
1828
+ teamHas.trademarks = {};
1829
+ teamHas.trademarks[ability.name] = (teamHas.trademarks[ability.name] || 0) + 1;
1830
+ return problems.length ? problems : null;
1831
+ },
1832
+ pokemon: {
1833
+ getAbility() {
1834
+ const move = this.battle.dex.moves.get(this.battle.toID(this.ability));
1835
+ if (!move.exists)
1836
+ return Object.getPrototypeOf(this).getAbility.call(this);
1837
+ return {
1838
+ id: move.id,
1839
+ name: move.name,
1840
+ onStart(pokemon) {
1841
+ this.add('-activate', pokemon, 'ability: ' + move.name);
1842
+ this.actions.useMove(move, pokemon);
1843
+ },
1844
+ toString() {
1845
+ return "";
1846
+ },
1847
+ };
1848
+ },
1690
1849
  },
1691
1850
  },
1692
1851
  {
@@ -1830,6 +1989,41 @@ exports.Formats = [
1830
1989
  searchShow: false,
1831
1990
  ruleset: ['[Gen 8] Random Battle', 'Dynamax Clause'],
1832
1991
  },
1992
+ {
1993
+ name: "[Gen 8] Random Battle Mayhem",
1994
+ desc: `[Gen 8] Random Battle (No Dmax) with Team Preview and elements of Camomons, Inverse, Scalemons, and Shared Power.`,
1995
+ mod: 'sharedpower',
1996
+ team: 'random',
1997
+ searchShow: false,
1998
+ ruleset: ['[Gen 8] Random Battle', 'Team Preview', 'Dynamax Clause', 'Camomons Mod', 'Inverse Mod', 'Scalemons Mod'],
1999
+ onBeforeSwitchIn(pokemon) {
2000
+ let format = this.format;
2001
+ if (!format.getSharedPower)
2002
+ format = this.dex.formats.get('gen8sharedpower');
2003
+ for (const ability of format.getSharedPower(pokemon)) {
2004
+ const effect = 'ability:' + ability;
2005
+ pokemon.volatiles[effect] = { id: this.toID(effect), target: pokemon };
2006
+ if (!pokemon.m.abils)
2007
+ pokemon.m.abils = [];
2008
+ if (!pokemon.m.abils.includes(effect))
2009
+ pokemon.m.abils.push(effect);
2010
+ }
2011
+ },
2012
+ onSwitchInPriority: 2,
2013
+ onSwitchIn(pokemon) {
2014
+ let format = this.format;
2015
+ if (!format.getSharedPower)
2016
+ format = this.dex.formats.get('gen8sharedpower');
2017
+ for (const ability of format.getSharedPower(pokemon)) {
2018
+ if (ability === 'noability') {
2019
+ this.hint(`Mirror Armor and Trace break in Shared Power formats that don't use Shared Power as a base, so they get removed from non-base users.`);
2020
+ }
2021
+ const effect = 'ability:' + ability;
2022
+ delete pokemon.volatiles[effect];
2023
+ pokemon.addVolatile(effect);
2024
+ }
2025
+ },
2026
+ },
1833
2027
  {
1834
2028
  name: "[Gen 8] BSS Factory",
1835
2029
  desc: `Randomized 3v3 Singles featuring Pok&eacute;mon and movesets popular in Battle Stadium Singles.`,
@@ -2086,36 +2280,42 @@ exports.Formats = [
2086
2280
  column: 3,
2087
2281
  },
2088
2282
  {
2089
- name: "[Gen 3] UU",
2283
+ name: "[Gen 4] UU",
2090
2284
  threads: [
2091
- `&bullet; <a href="https://www.smogon.com/forums/threads/3585923/">ADV UU Metagame Discussion</a>`,
2092
- `&bullet; <a href="https://www.smogon.com/forums/threads/3548578/">ADV UU Viability Rankings</a>`,
2285
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3532624/">DPP UU Metagame Discussion</a>`,
2286
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3503638/">DPP UU Viability Rankings</a>`,
2093
2287
  ],
2094
- mod: 'gen3',
2288
+ mod: 'gen4',
2095
2289
  // searchShow: false,
2096
- ruleset: ['Standard', 'NFE Clause'],
2097
- banlist: ['Uber', 'OU', 'UUBL', 'Smeargle + Ingrain', 'Baton Pass'],
2098
- unbanlist: ['Scyther', 'Sand Veil'],
2290
+ ruleset: ['[Gen 4] OU'],
2291
+ banlist: ['OU', 'UUBL'],
2292
+ unbanlist: ['Arena Trap', 'Swagger'],
2099
2293
  },
2100
2294
  {
2101
- name: "[Gen 1] NU",
2295
+ name: "[Gen 7] LC",
2102
2296
  threads: [
2103
- `&bullet; <a href="https://www.smogon.com/forums/threads/3668913/">RBY NU Viability Rankings</a>`,
2297
+ `&bullet; <a href="https://www.smogon.com/dex/sm/formats/lc/">USM LC Banlist</a>`,
2298
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3639319/">USM LC Sample Teams</a>`,
2299
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3621440/">USM LC Viability Rankings</a>`,
2104
2300
  ],
2105
- mod: 'gen1',
2301
+ mod: 'gen7',
2106
2302
  // searchShow: false,
2107
- ruleset: ['[Gen 1] UU'],
2108
- banlist: ['UU', 'NUBL'],
2303
+ ruleset: ['Little Cup', 'Standard', 'Swagger Clause'],
2304
+ banlist: [
2305
+ 'Aipom', 'Cutiefly', 'Drifloon', 'Gligar', 'Gothita', 'Meditite', 'Misdreavus', 'Murkrow', 'Porygon',
2306
+ 'Scyther', 'Sneasel', 'Swirlix', 'Tangela', 'Trapinch', 'Vulpix-Base', 'Wingull', 'Yanma',
2307
+ 'Eevium Z', 'Baton Pass', 'Dragon Rage', 'Sonic Boom', 'Sticky Web',
2308
+ ],
2109
2309
  },
2110
2310
  {
2111
- name: "[Gen 4] Ubers",
2311
+ name: "[Gen 5] PU",
2112
2312
  threads: [
2113
- `&bullet; <a href="https://www.smogon.com/forums/posts/8286279/">DPP Ubers</a>`,
2313
+ `&bullet; <a href="https://www.smogon.com/forums/posts/7326932/">BW2 PU</a>`,
2114
2314
  ],
2115
- mod: 'gen4',
2315
+ mod: 'gen5',
2116
2316
  // searchShow: false,
2117
- ruleset: ['Standard'],
2118
- banlist: ['AG'],
2317
+ ruleset: ['[Gen 5] NU', 'Sleep Moves Clause'],
2318
+ banlist: ['NU', 'PUBL'],
2119
2319
  },
2120
2320
  // Past Gens OU
2121
2321
  ///////////////////////////////////////////////////////////////////
@@ -2388,22 +2588,6 @@ exports.Formats = [
2388
2588
  ruleset: ['[Gen 7] NU'],
2389
2589
  banlist: ['NU', 'PUBL'],
2390
2590
  },
2391
- {
2392
- name: "[Gen 7] LC",
2393
- threads: [
2394
- `&bullet; <a href="https://www.smogon.com/dex/sm/formats/lc/">USM LC Banlist</a>`,
2395
- `&bullet; <a href="https://www.smogon.com/forums/threads/3639319/">USM LC Sample Teams</a>`,
2396
- `&bullet; <a href="https://www.smogon.com/forums/threads/3621440/">USM LC Viability Rankings</a>`,
2397
- ],
2398
- mod: 'gen7',
2399
- searchShow: false,
2400
- ruleset: ['Little Cup', 'Standard', 'Swagger Clause'],
2401
- banlist: [
2402
- 'Aipom', 'Cutiefly', 'Drifloon', 'Gligar', 'Gothita', 'Meditite', 'Misdreavus', 'Murkrow', 'Porygon',
2403
- 'Scyther', 'Sneasel', 'Swirlix', 'Tangela', 'Trapinch', 'Vulpix-Base', 'Wingull', 'Yanma',
2404
- 'Eevium Z', 'Baton Pass', 'Dragon Rage', 'Sonic Boom', 'Sticky Web',
2405
- ],
2406
- },
2407
2591
  {
2408
2592
  name: "[Gen 7] Monotype",
2409
2593
  desc: `All the Pok&eacute;mon on a team must share a type.`,
@@ -2720,14 +2904,15 @@ exports.Formats = [
2720
2904
  mod: 'gen6',
2721
2905
  searchShow: false,
2722
2906
  ruleset: [
2723
- 'Max Team Size = 3', 'Picked Team Size = 1',
2724
- 'Obtainable', 'Nickname Clause', 'Moody Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Accuracy Moves Clause', 'Swagger Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod', 'Team Preview',
2907
+ 'Max Team Size = 3', 'Picked Team Size = 1', 'Obtainable', 'Nickname Clause', 'Moody Clause', 'OHKO Clause',
2908
+ 'Evasion Moves Clause', 'Accuracy Moves Clause', 'Swagger Clause', 'Endless Battle Clause', 'HP Percentage Mod',
2909
+ 'Cancel Mod', 'Team Preview',
2725
2910
  ],
2726
2911
  banlist: [
2727
2912
  'Arceus', 'Blaziken', 'Darkrai', 'Deoxys-Base', 'Deoxys-Attack', 'Deoxys-Defense', 'Dialga', 'Giratina',
2728
2913
  'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kangaskhan-Mega', 'Kyogre', 'Kyurem-White', 'Lugia', 'Mewtwo',
2729
2914
  'Palkia', 'Rayquaza', 'Reshiram', 'Salamence-Mega', 'Shaymin-Sky', 'Xerneas', 'Yveltal', 'Zekrom',
2730
- 'Focus Sash', 'Soul Dew', 'Perish Song',
2915
+ 'Focus Sash', 'Soul Dew', 'Grass Whistle', 'Hypnosis', 'Perish Song', 'Sing', 'Yawn',
2731
2916
  ],
2732
2917
  },
2733
2918
  {
@@ -2920,16 +3105,6 @@ exports.Formats = [
2920
3105
  ruleset: ['[Gen 5] RU', '!Sleep Moves Clause', 'Sleep Clause Mod'],
2921
3106
  banlist: ['RU', 'NUBL', 'Assist', 'Copycat'],
2922
3107
  },
2923
- {
2924
- name: "[Gen 5] PU",
2925
- threads: [
2926
- `&bullet; <a href="https://www.smogon.com/forums/posts/7326932/">BW2 PU</a>`,
2927
- ],
2928
- mod: 'gen5',
2929
- searchShow: false,
2930
- ruleset: ['[Gen 5] NU', 'Sleep Moves Clause'],
2931
- banlist: ['NU', 'PUBL'],
2932
- },
2933
3108
  {
2934
3109
  name: "[Gen 5] LC",
2935
3110
  threads: [
@@ -2966,7 +3141,7 @@ exports.Formats = [
2966
3141
  'Picked Team Size = 1', 'Max Team Size = 3',
2967
3142
  'Standard', 'Baton Pass Clause', 'Swagger Clause', 'Accuracy Moves Clause',
2968
3143
  ],
2969
- banlist: ['Uber', 'Cottonee', 'Dragonite', 'Kyurem-Black', 'Mew', 'Togekiss', 'Whimsicott', 'Victini', 'Bright Powder', 'Focus Band', 'Focus Sash', 'Lax Incense', 'Quick Claw', 'Soul Dew', 'Perish Song'],
3144
+ banlist: ['Uber', 'Cottonee', 'Dragonite', 'Jirachi', 'Kyurem-Black', 'Mew', 'Togekiss', 'Whimsicott', 'Victini', 'Bright Powder', 'Focus Band', 'Focus Sash', 'Lax Incense', 'Quick Claw', 'Soul Dew', 'Perish Song'],
2970
3145
  unbanlist: ['Genesect', 'Landorus', 'Manaphy', 'Thundurus', 'Tornadus-Therian'],
2971
3146
  },
2972
3147
  {
@@ -3055,16 +3230,14 @@ exports.Formats = [
3055
3230
  column: 5,
3056
3231
  },
3057
3232
  {
3058
- name: "[Gen 4] UU",
3233
+ name: "[Gen 4] Ubers",
3059
3234
  threads: [
3060
- `&bullet; <a href="https://www.smogon.com/forums/threads/3532624/">DPP UU Metagame Discussion</a>`,
3061
- `&bullet; <a href="https://www.smogon.com/forums/threads/3503638/">DPP UU Viability Rankings</a>`,
3235
+ `&bullet; <a href="https://www.smogon.com/forums/posts/8286279/">DPP Ubers</a>`,
3062
3236
  ],
3063
3237
  mod: 'gen4',
3064
3238
  searchShow: false,
3065
- ruleset: ['[Gen 4] OU'],
3066
- banlist: ['OU', 'UUBL'],
3067
- unbanlist: ['Arena Trap', 'Swagger'],
3239
+ ruleset: ['Standard'],
3240
+ banlist: ['AG'],
3068
3241
  },
3069
3242
  {
3070
3243
  name: "[Gen 4] NU",
@@ -3197,6 +3370,18 @@ exports.Formats = [
3197
3370
  ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
3198
3371
  banlist: ['Wobbuffet + Leftovers'],
3199
3372
  },
3373
+ {
3374
+ name: "[Gen 3] UU",
3375
+ threads: [
3376
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3585923/">ADV UU Metagame Discussion</a>`,
3377
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3548578/">ADV UU Viability Rankings</a>`,
3378
+ ],
3379
+ mod: 'gen3',
3380
+ searchShow: false,
3381
+ ruleset: ['Standard', 'NFE Clause'],
3382
+ banlist: ['Uber', 'OU', 'UUBL', 'Smeargle + Ingrain', 'Baton Pass'],
3383
+ unbanlist: ['Scyther', 'Sand Veil'],
3384
+ },
3200
3385
  {
3201
3386
  name: "[Gen 3] NU",
3202
3387
  threads: [
@@ -3286,7 +3471,7 @@ exports.Formats = [
3286
3471
  '[Gen 2] OU', 'Accuracy Moves Clause', 'Sleep Moves Clause', 'Team Preview',
3287
3472
  ],
3288
3473
  banlist: [
3289
- 'Clefable', 'Snorlax', 'Zapdos', 'Berserk Gene', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Quick Claw',
3474
+ 'Alakazam', 'Clefable', 'Snorlax', 'Zapdos', 'Berserk Gene', 'Bright Powder', 'Focus Band', 'King\'s Rock', 'Quick Claw',
3290
3475
  'Attract', 'Destiny Bond', 'Explosion', 'Perish Song', 'Present', 'Self-Destruct', 'Swagger',
3291
3476
  ],
3292
3477
  },
@@ -3342,6 +3527,16 @@ exports.Formats = [
3342
3527
  ruleset: ['[Gen 1] OU'],
3343
3528
  banlist: ['OU', 'UUBL'],
3344
3529
  },
3530
+ {
3531
+ name: "[Gen 1] NU",
3532
+ threads: [
3533
+ `&bullet; <a href="https://www.smogon.com/forums/threads/3668913/">RBY NU Viability Rankings</a>`,
3534
+ ],
3535
+ mod: 'gen1',
3536
+ searchShow: false,
3537
+ ruleset: ['[Gen 1] UU'],
3538
+ banlist: ['UU', 'NUBL'],
3539
+ },
3345
3540
  {
3346
3541
  name: "[Gen 1] Japanese OU",
3347
3542
  desc: `Generation 1 with Japanese battle mechanics.`,