@pkmn/sim 0.5.8 → 0.5.9

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.
@@ -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
  {
@@ -591,141 +591,212 @@ exports.Formats = [
591
591
  column: 2,
592
592
  },
593
593
  {
594
- name: "[Gen 8] Trademarked",
595
- desc: `Sacrifice your Pokémon's ability for a status move that activates on switch-in.`,
594
+ name: "[Gen 8] Shared Power",
595
+ desc: `Once a Pokémon switches in, its ability is shared with the rest of the team.`,
596
596
  threads: [
597
- `&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>`,
598
598
  ],
599
- mod: 'gen8',
599
+ mod: 'sharedpower',
600
600
  // searchShow: false,
601
601
  ruleset: ['Standard', 'Dynamax Clause'],
602
602
  banlist: [
603
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Dragapult', 'Eternatus', 'Kyurem-Black', 'Kyurem-White', 'Giratina',
604
- 'Giratina-Origin', 'Genesect', 'Groudon', 'Ho-Oh', 'Kartana', 'Kyogre', 'Lugia', 'Lunala', 'Magearna', 'Marowak-Alola', 'Marshadow', 'Melmetal',
605
- 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Solgaleo', 'Spectrier',
606
- 'Urshifu-Base', 'Victini', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom', 'Zygarde-Base',
607
- 'Arena Trap', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Shadow Tag', 'Baton Pass',
608
- ],
609
- restricted: [
610
- 'Baneful Bunker', 'Block', 'Copycat', 'Corrosive Gas', 'Detect', 'Destiny Bond', 'Disable', 'Encore', 'Fairy Lock', 'Hypnosis', 'Ingrain',
611
- 'Instruct', 'Lovely Kiss', 'King\'s Shield', 'Mat Block', 'Mean Look', 'Memento', 'move:Metronome', 'Obstruct', 'Octolock', 'Nature Power',
612
- 'Parting Shot', 'Psycho Shift', 'Protect', 'Roar', 'Sing', 'Skill Swap', 'Sleep Powder', 'Sleep Talk', 'Spiky Shield', 'Spore', 'Substitute',
613
- 'Switcheroo', 'Teleport', 'Trick', 'Whirlwind', 'Wish', 'Yawn',
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',
614
614
  ],
615
- onValidateTeam(team, format, teamHas) {
616
- const problems = [];
617
- for (const trademark in teamHas.trademarks) {
618
- if (teamHas.trademarks[trademark] > 1) {
619
- problems.push(`You are limited to 1 of each Trademark.`, `(You have ${teamHas.trademarks[trademark]} Pok\u00e9mon with ${trademark} as a Trademark.)`);
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);
620
624
  }
621
625
  }
622
- return problems;
626
+ sharedPower.delete(pokemon.baseAbility);
627
+ return sharedPower;
623
628
  },
624
- validateSet(set, teamHas) {
625
- const dex = this.dex;
626
- const ability = dex.moves.get(set.ability);
627
- if (!ability.exists) { // Not even a real move
628
- return this.validateSet(set, teamHas);
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);
629
640
  }
630
- // Absolute trademark bans
631
- if (ability.category !== 'Status') {
632
- return [`${ability.name} is not a status move, and cannot be used as a trademark.`];
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);
633
654
  }
634
- if (ability.forceSwitch || ability.selfSwitch) {
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>`,
662
+ ],
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
+ ];
677
+ }
678
+ names.add(this.dex.toID(name));
679
+ }
680
+ if (!names.size) {
635
681
  return [
636
- `Force-switching and self-switching moves are banned from being used as trademarks.`,
637
- `(${ability.name} is a ${ability.forceSwitch ? 'force' : 'self'}-switching move.)`,
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.)`,
638
684
  ];
639
685
  }
640
- const irrevokablyRestricted = [
641
- 'Assist', 'Copycat', 'Metronome', 'Mirror Move', 'Sleep Talk',
642
- 'Recycle', 'Trace',
643
- 'Skill Swap', // Self-propagates indefinitely
644
- ];
645
- for (const m of set.moves) {
646
- const move = dex.moves.get(m);
647
- if (irrevokablyRestricted.includes(move.name)) {
648
- return [`${move.name} is banned from Trademark, irrespective of custom rules, because it can cause endless turns.`];
649
- }
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);
650
691
  }
651
- if (irrevokablyRestricted.includes(ability.name)) {
652
- return [`${ability.name} cannot safely function as a trademark.`];
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;
705
+ },
706
+ validateSet(set, teamHas) {
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)
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.`];
653
729
  }
654
- // Contingent trademark bans
655
- if (this.ruleTable.isRestricted(`move:${ability.id}`)) {
656
- return [`${ability.name} is restricted from being used as a trademark.`];
730
+ if (this.ruleTable.isRestrictedSpecies(crossSpecies)) {
731
+ return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it is banned.`];
657
732
  }
658
- if (set.moves.map(this.toID).includes(ability.id)) {
659
- return [`${set.name} may not use ${ability.name} as both a trademark and one of its moves simultaneously.`];
733
+ const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
734
+ if (!crossPrevoSpecies.prevo !== !species.prevo) {
735
+ return [
736
+ `${species.name} cannot cross evolve into ${crossSpecies.name} because they are not consecutive evolution stages.`,
737
+ ];
660
738
  }
661
- const customRules = this.format.customRules || [];
662
- if (!customRules.includes('!obtainableabilities'))
663
- customRules.push('!obtainableabilities');
664
- const TeamValidator = require('../sim/team-validator').TeamValidator;
665
- const validator = new TeamValidator(dex.formats.get(`${this.format.id}@@@${customRules.join(',')}`));
666
- const moves = set.moves;
667
- set.moves = [ability.id];
668
- set.ability = dex.species.get(set.species).abilities['0'];
669
- let problems = validator.validateSet(set, {}) || [];
670
- if (problems.length)
671
- return problems;
672
- set.moves = moves;
673
- set.ability = dex.species.get(set.species).abilities['0'];
674
- problems = problems.concat(validator.validateSet(set, teamHas) || []);
675
- set.ability = ability.id;
676
- if (!teamHas.trademarks)
677
- teamHas.trademarks = {};
678
- teamHas.trademarks[ability.name] = (teamHas.trademarks[ability.name] || 0) + 1;
679
- return problems.length ? problems : null;
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;
742
+ }
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;
680
753
  },
681
- pokemon: {
682
- getAbility() {
683
- const move = this.battle.dex.moves.get(this.battle.toID(this.ability));
684
- if (!move.exists)
685
- return Object.getPrototypeOf(this).getAbility.call(this);
686
- return {
687
- id: move.id,
688
- name: move.name,
689
- onStart(pokemon) {
690
- this.add('-activate', pokemon, 'ability: ' + move.name);
691
- this.actions.useMove(move, pokemon);
692
- },
693
- toString() {
694
- return "";
695
- },
696
- };
697
- },
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];
786
+ }
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];
791
+ }
792
+ if (mixedSpecies.types[0] === mixedSpecies.types[1])
793
+ mixedSpecies.types = [mixedSpecies.types[0]];
794
+ return mixedSpecies;
698
795
  },
699
- },
700
- {
701
- name: "[Gen 8] Linked",
702
- desc: `The first two moves in a Pok&eacute;mon's moveset are used simultaneously.`,
703
- threads: [
704
- `&bullet; <a href="https://www.smogon.com/forums/threads/3660421/">Linked</a>`,
705
- ],
706
- mod: 'linked',
707
- ruleset: ['Standard', 'Dynamax Clause'],
708
- banlist: [
709
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Cinderace', 'Cloyster', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
710
- 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala', 'Magearna',
711
- 'Marshadow', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia', 'Pheromosa', 'Rayquaza', 'Reshiram', 'Solgaleo',
712
- 'Spectrier', 'Urshifu-Base', 'Volcarona', 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom',
713
- 'Zygarde-Base', 'Zygarde-Complete', 'Arena Trap', 'Chlorophyll', 'Moody', 'Power Construct', 'Sand Rush', 'Sand Veil', 'Shadow Tag', 'Slush Rush',
714
- 'Snow Cloak', 'Speed Boost', 'Surge Surfer', 'Swift Swim', 'Unburden', 'Bright Powder', 'King\'s Rock', 'Lax Incense', 'Baton Pass',
715
- ],
716
- restricted: [
717
- 'Baneful Bunker', 'Bounce', 'Protect', 'Detect', 'Dig', 'Dive', 'Fly', 'King\'s Shield', 'Nature\'s Madness', 'Night Shade',
718
- 'Obstruct', 'Phantom Force', 'Seismic Toss', 'Shadow Force', 'Sky Drop', 'Spiky Shield', 'Super Fang', 'Trick Room',
719
- ],
720
- onValidateSet(set) {
721
- const problems = [];
722
- for (const [i, moveid] of set.moves.entries()) {
723
- const move = this.dex.moves.get(moveid);
724
- if ([0, 1].includes(i) && this.ruleTable.isRestricted(`move:${move.id}`)) {
725
- problems.push(`${set.name || set.species}'s move ${move.name} cannot be linked.`);
726
- }
796
+ onBegin() {
797
+ for (const pokemon of this.getAllPokemon()) {
798
+ pokemon.baseSpecies = pokemon.species;
727
799
  }
728
- return problems;
729
800
  },
730
801
  },
731
802
  // Other Metagames
@@ -1034,7 +1105,6 @@ exports.Formats = [
1034
1105
  `&bullet; <a href="https://www.smogon.com/forums/threads/3697080/">BDSP NU</a>`,
1035
1106
  ],
1036
1107
  mod: 'gen8bdsp',
1037
- searchShow: false,
1038
1108
  ruleset: ['[Gen 8 BDSP] RU'],
1039
1109
  banlist: ['RU', 'NUBL'],
1040
1110
  },
@@ -1314,6 +1384,38 @@ exports.Formats = [
1314
1384
  this.add('-start', pokemon, donorTemplate.name, '[silent]');
1315
1385
  },
1316
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
+ },
1317
1419
  {
1318
1420
  name: "[Gen 8] Multibility",
1319
1421
  desc: `Run a second ability at the cost of giving up a Pok&eacute;mon's item slot.`,
@@ -1637,67 +1739,113 @@ exports.Formats = [
1637
1739
  },
1638
1740
  },
1639
1741
  {
1640
- name: "[Gen 8] Shared Power",
1641
- 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.`,
1642
1744
  threads: [
1643
- `&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>`,
1644
1746
  ],
1645
- mod: 'sharedpower',
1747
+ mod: 'gen8',
1748
+ // While bugs are being fixed
1646
1749
  searchShow: false,
1750
+ challengeShow: false,
1751
+ tournamentShow: false,
1647
1752
  ruleset: ['Standard', 'Dynamax Clause'],
1648
1753
  banlist: [
1649
- 'Calyrex-Ice', 'Calyrex-Shadow', 'Darmanitan-Galar', 'Dialga', 'Dracovish', 'Eternatus', 'Genesect', 'Giratina',
1650
- 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna',
1651
- 'Marshadow', 'Melmetal', 'Mewtwo', 'Naganadel', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
1652
- 'Pheromosa', 'Rayquaza', 'Reshiram', 'Shedinja', 'Solgaleo', 'Urshifu-Base', 'Urshifu-Rapid-Strike',
1653
- 'Xerneas', 'Yveltal', 'Zacian', 'Zacian-Crowned', 'Zamazenta', 'Zamazenta-Crowned', 'Zekrom',
1654
- 'Arena Trap', 'Contrary', 'Drizzle ++ Swift Swim', 'Drought ++ Chlorophyll', 'Electric Surge ++ Surge Surfer',
1655
- 'Fur Coat', 'Guts', 'Harvest', 'Huge Power', 'Imposter', 'Innards Out', 'Libero', 'Magic Bounce', 'Magic Guard',
1656
- 'Magnet Pull', 'Mold Breaker', 'Moody', 'Neutralizing Gas', 'Power Construct', 'Queenly Majesty', 'Quick Draw',
1657
- 'Regenerator', 'Sand Rush', 'Sand Veil', 'Shadow Tag', 'Simple', 'Snow Cloak', 'Snow Warning ++ Slush Rush', 'Speed Boost',
1658
- 'Stakeout', 'Steelworker ++ Steely Spirit', 'Tinted Lens', 'Triage', 'Unaware', 'Unburden', 'Water Bubble',
1659
- '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',
1660
1759
  ],
1661
- getSharedPower(pokemon) {
1662
- const sharedPower = new Set();
1663
- for (const ally of pokemon.side.pokemon) {
1664
- if (ally.previouslySwitchedIn > 0) {
1665
- if (pokemon.battle.dex.currentMod !== 'sharedpower' && ['trace', 'mirrorarmor'].includes(ally.baseAbility)) {
1666
- sharedPower.add('noability');
1667
- continue;
1668
- }
1669
- 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.)`);
1670
1771
  }
1671
1772
  }
1672
- sharedPower.delete(pokemon.baseAbility);
1673
- return sharedPower;
1773
+ return problems;
1674
1774
  },
1675
- onBeforeSwitchIn(pokemon) {
1676
- let format = this.format;
1677
- if (!format.getSharedPower)
1678
- format = this.dex.formats.get('gen8sharedpower');
1679
- for (const ability of format.getSharedPower(pokemon)) {
1680
- const effect = 'ability:' + ability;
1681
- pokemon.volatiles[effect] = { id: this.toID(effect), target: pokemon };
1682
- if (!pokemon.m.abils)
1683
- pokemon.m.abils = [];
1684
- if (!pokemon.m.abils.includes(effect))
1685
- 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);
1686
1780
  }
1687
- },
1688
- onSwitchInPriority: 2,
1689
- onSwitchIn(pokemon) {
1690
- let format = this.format;
1691
- if (!format.getSharedPower)
1692
- format = this.dex.formats.get('gen8sharedpower');
1693
- for (const ability of format.getSharedPower(pokemon)) {
1694
- if (ability === 'noability') {
1695
- 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.`];
1696
1800
  }
1697
- const effect = 'ability:' + ability;
1698
- delete pokemon.volatiles[effect];
1699
- pokemon.addVolatile(effect);
1700
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
+ },
1701
1849
  },
1702
1850
  },
1703
1851
  {
@@ -2132,36 +2280,42 @@ exports.Formats = [
2132
2280
  column: 3,
2133
2281
  },
2134
2282
  {
2135
- name: "[Gen 3] UU",
2283
+ name: "[Gen 4] UU",
2136
2284
  threads: [
2137
- `&bullet; <a href="https://www.smogon.com/forums/threads/3585923/">ADV UU Metagame Discussion</a>`,
2138
- `&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>`,
2139
2287
  ],
2140
- mod: 'gen3',
2288
+ mod: 'gen4',
2141
2289
  // searchShow: false,
2142
- ruleset: ['Standard', 'NFE Clause'],
2143
- banlist: ['Uber', 'OU', 'UUBL', 'Smeargle + Ingrain', 'Baton Pass'],
2144
- unbanlist: ['Scyther', 'Sand Veil'],
2290
+ ruleset: ['[Gen 4] OU'],
2291
+ banlist: ['OU', 'UUBL'],
2292
+ unbanlist: ['Arena Trap', 'Swagger'],
2145
2293
  },
2146
2294
  {
2147
- name: "[Gen 1] NU",
2295
+ name: "[Gen 7] LC",
2148
2296
  threads: [
2149
- `&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>`,
2150
2300
  ],
2151
- mod: 'gen1',
2301
+ mod: 'gen7',
2152
2302
  // searchShow: false,
2153
- ruleset: ['[Gen 1] UU'],
2154
- 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
+ ],
2155
2309
  },
2156
2310
  {
2157
- name: "[Gen 4] Ubers",
2311
+ name: "[Gen 5] PU",
2158
2312
  threads: [
2159
- `&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>`,
2160
2314
  ],
2161
- mod: 'gen4',
2315
+ mod: 'gen5',
2162
2316
  // searchShow: false,
2163
- ruleset: ['Standard'],
2164
- banlist: ['AG'],
2317
+ ruleset: ['[Gen 5] NU', 'Sleep Moves Clause'],
2318
+ banlist: ['NU', 'PUBL'],
2165
2319
  },
2166
2320
  // Past Gens OU
2167
2321
  ///////////////////////////////////////////////////////////////////
@@ -2434,22 +2588,6 @@ exports.Formats = [
2434
2588
  ruleset: ['[Gen 7] NU'],
2435
2589
  banlist: ['NU', 'PUBL'],
2436
2590
  },
2437
- {
2438
- name: "[Gen 7] LC",
2439
- threads: [
2440
- `&bullet; <a href="https://www.smogon.com/dex/sm/formats/lc/">USM LC Banlist</a>`,
2441
- `&bullet; <a href="https://www.smogon.com/forums/threads/3639319/">USM LC Sample Teams</a>`,
2442
- `&bullet; <a href="https://www.smogon.com/forums/threads/3621440/">USM LC Viability Rankings</a>`,
2443
- ],
2444
- mod: 'gen7',
2445
- searchShow: false,
2446
- ruleset: ['Little Cup', 'Standard', 'Swagger Clause'],
2447
- banlist: [
2448
- 'Aipom', 'Cutiefly', 'Drifloon', 'Gligar', 'Gothita', 'Meditite', 'Misdreavus', 'Murkrow', 'Porygon',
2449
- 'Scyther', 'Sneasel', 'Swirlix', 'Tangela', 'Trapinch', 'Vulpix-Base', 'Wingull', 'Yanma',
2450
- 'Eevium Z', 'Baton Pass', 'Dragon Rage', 'Sonic Boom', 'Sticky Web',
2451
- ],
2452
- },
2453
2591
  {
2454
2592
  name: "[Gen 7] Monotype",
2455
2593
  desc: `All the Pok&eacute;mon on a team must share a type.`,
@@ -2766,14 +2904,15 @@ exports.Formats = [
2766
2904
  mod: 'gen6',
2767
2905
  searchShow: false,
2768
2906
  ruleset: [
2769
- 'Max Team Size = 3', 'Picked Team Size = 1',
2770
- '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',
2771
2910
  ],
2772
2911
  banlist: [
2773
2912
  'Arceus', 'Blaziken', 'Darkrai', 'Deoxys-Base', 'Deoxys-Attack', 'Deoxys-Defense', 'Dialga', 'Giratina',
2774
2913
  'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Kangaskhan-Mega', 'Kyogre', 'Kyurem-White', 'Lugia', 'Mewtwo',
2775
2914
  'Palkia', 'Rayquaza', 'Reshiram', 'Salamence-Mega', 'Shaymin-Sky', 'Xerneas', 'Yveltal', 'Zekrom',
2776
- 'Focus Sash', 'Soul Dew', 'Perish Song',
2915
+ 'Focus Sash', 'Soul Dew', 'Grass Whistle', 'Hypnosis', 'Perish Song', 'Sing', 'Yawn',
2777
2916
  ],
2778
2917
  },
2779
2918
  {
@@ -2966,16 +3105,6 @@ exports.Formats = [
2966
3105
  ruleset: ['[Gen 5] RU', '!Sleep Moves Clause', 'Sleep Clause Mod'],
2967
3106
  banlist: ['RU', 'NUBL', 'Assist', 'Copycat'],
2968
3107
  },
2969
- {
2970
- name: "[Gen 5] PU",
2971
- threads: [
2972
- `&bullet; <a href="https://www.smogon.com/forums/posts/7326932/">BW2 PU</a>`,
2973
- ],
2974
- mod: 'gen5',
2975
- searchShow: false,
2976
- ruleset: ['[Gen 5] NU', 'Sleep Moves Clause'],
2977
- banlist: ['NU', 'PUBL'],
2978
- },
2979
3108
  {
2980
3109
  name: "[Gen 5] LC",
2981
3110
  threads: [
@@ -3012,7 +3141,7 @@ exports.Formats = [
3012
3141
  'Picked Team Size = 1', 'Max Team Size = 3',
3013
3142
  'Standard', 'Baton Pass Clause', 'Swagger Clause', 'Accuracy Moves Clause',
3014
3143
  ],
3015
- 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'],
3016
3145
  unbanlist: ['Genesect', 'Landorus', 'Manaphy', 'Thundurus', 'Tornadus-Therian'],
3017
3146
  },
3018
3147
  {
@@ -3101,16 +3230,14 @@ exports.Formats = [
3101
3230
  column: 5,
3102
3231
  },
3103
3232
  {
3104
- name: "[Gen 4] UU",
3233
+ name: "[Gen 4] Ubers",
3105
3234
  threads: [
3106
- `&bullet; <a href="https://www.smogon.com/forums/threads/3532624/">DPP UU Metagame Discussion</a>`,
3107
- `&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>`,
3108
3236
  ],
3109
3237
  mod: 'gen4',
3110
3238
  searchShow: false,
3111
- ruleset: ['[Gen 4] OU'],
3112
- banlist: ['OU', 'UUBL'],
3113
- unbanlist: ['Arena Trap', 'Swagger'],
3239
+ ruleset: ['Standard'],
3240
+ banlist: ['AG'],
3114
3241
  },
3115
3242
  {
3116
3243
  name: "[Gen 4] NU",
@@ -3243,6 +3370,18 @@ exports.Formats = [
3243
3370
  ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
3244
3371
  banlist: ['Wobbuffet + Leftovers'],
3245
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
+ },
3246
3385
  {
3247
3386
  name: "[Gen 3] NU",
3248
3387
  threads: [
@@ -3388,6 +3527,16 @@ exports.Formats = [
3388
3527
  ruleset: ['[Gen 1] OU'],
3389
3528
  banlist: ['OU', 'UUBL'],
3390
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
+ },
3391
3540
  {
3392
3541
  name: "[Gen 1] Japanese OU",
3393
3542
  desc: `Generation 1 with Japanese battle mechanics.`,