text: // Note: These are the rules that formats use
  // The list of formats is stored in config/formats.js
  
  'use strict';
  
  /**@type {{[k: string]: FormatsData}} */
  let BattleFormats = {
  
  	// Rulesets
  	///////////////////////////////////////////////////////////////////
  
  	standard: {
  		effectType: 'ValidatorRule',
  		name: 'Standard',
  		desc: "The standard ruleset for all offical Smogon singles tiers (Ubers, OU, etc.)",
  		ruleset: ['Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Moody Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
  	},
  	standardnext: {
  		effectType: 'ValidatorRule',
  		name: 'Standard NEXT',
  		desc: "The standard ruleset for the NEXT mod",
  		ruleset: ['+Unreleased', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'HP Percentage Mod', 'Cancel Mod'],
  		banlist: ['Soul Dew'],
  	},
  	standardubers: {
  		effectType: 'ValidatorRule',
  		name: 'Standard Ubers',
  		desc: "The standard ruleset for [Gen 5] Ubers",
  		ruleset: ['Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'Moody Clause', 'OHKO Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
  	},
  	standardgbu: {
  		effectType: 'ValidatorRule',
  		name: 'Standard GBU',
  		desc: "The standard ruleset for all official in-game Pok&eacute;mon tournaments and Battle Spot",
  		ruleset: ['Species Clause', 'Nickname Clause', 'Item Clause', 'Team Preview', 'Cancel Mod'],
  		banlist: ['Battle Bond',
  			'Mewtwo', 'Mew',
  			'Lugia', 'Ho-Oh', 'Celebi',
  			'Kyogre', 'Groudon', 'Rayquaza', 'Jirachi', 'Deoxys',
  			'Dialga', 'Palkia', 'Giratina', 'Phione', 'Manaphy', 'Darkrai', 'Shaymin', 'Arceus',
  			'Victini', 'Reshiram', 'Zekrom', 'Kyurem', 'Keldeo', 'Meloetta', 'Genesect',
  			'Xerneas', 'Yveltal', 'Zygarde', 'Diancie', 'Hoopa', 'Volcanion',
  			'Cosmog', 'Cosmoem', 'Solgaleo', 'Lunala', 'Necrozma', 'Magearna', 'Marshadow', 'Zeraora',
  		],
  		onValidateSet(set, format) {
  			if (this.gen < 7 && toID(set.item) === 'souldew') {
  				return [`${set.name || set.species} has Soul Dew, which is banned in ${format.name}.`];
  			}
  		},
  	},
  	minimalgbu: {
  		effectType: 'ValidatorRule',
  		name: 'Minimal GBU',
  		desc: "The standard ruleset for official tournaments, but without Restricted Legendary bans",
  		ruleset: ['Species Clause', 'Nickname Clause', 'Item Clause', 'Team Preview', 'Cancel Mod'],
  		banlist: ['Battle Bond',
  			'Mew',
  			'Celebi',
  			'Jirachi', 'Deoxys',
  			'Phione', 'Manaphy', 'Darkrai', 'Shaymin', 'Arceus',
  			'Victini', 'Keldeo', 'Meloetta', 'Genesect',
  			'Diancie', 'Hoopa', 'Volcanion',
  			'Magearna', 'Marshadow', 'Zeraora',
  		],
  		onValidateSet(set, format) {
  			if (this.gen < 7 && toID(set.item) === 'souldew') {
  				return [`${set.name || set.species} has Soul Dew, which is banned in ${format.name}.`];
  			}
  		},
  	},
  	standarddoubles: {
  		effectType: 'ValidatorRule',
  		name: 'Standard Doubles',
  		desc: "The standard ruleset for all official Smogon doubles tiers",
  		ruleset: ['Species Clause', 'Nickname Clause', 'OHKO Clause', 'Moody Clause', 'Evasion Abilities Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
  	},
  	obtainable: {
  		effectType: 'ValidatorRule',
  		name: 'Obtainable',
  		desc: "Makes sure the team is possible to obtain in-game.",
  		ruleset: ['Obtainable Moves', 'Obtainable Abilities', 'Obtainable Formes', 'Obtainable Misc'],
  		banlist: ['Unreleased', 'Nonexistent'],
  	},
  	obtainablemoves: {
  		effectType: 'ValidatorRule',
  		name: 'Obtainable Moves',
  		desc: "Makes sure moves are learnable by the species.",
  		banlist: [
  			// Leaf Blade: Gen 6+ Nuzleaf level-up
  			// Sucker Punch: Gen 4 Shiftry tutor
  			'Shiftry + Leaf Blade + Sucker Punch',
  		],
  		// Mostly hardcoded in team-validator.ts
  	},
  	obtainableabilities: {
  		effectType: 'ValidatorRule',
  		name: 'Obtainable Abilities',
  		desc: "Makes sure abilities match the species.",
  		// Hardcoded in team-validator.ts
  	},
  	obtainableformes: {
  		effectType: 'ValidatorRule',
  		name: 'Obtainable Formes',
  		desc: "Makes sure in-battle formes only appear in-battle.",
  		// Mostly hardcoded in team-validator.ts
  		onValidateTeam(team) {
  			let kyuremCount = 0;
  			let necrozmaDMCount = 0;
  			let necrozmaDWCount = 0;
  			for (const set of team) {
  				if (set.species === 'Kyurem-White' || set.species === 'Kyurem-Black') {
  					if (kyuremCount > 0) {
  						return ['You cannot have more than one Kyurem-Black/Kyurem-White.'];
  					}
  					kyuremCount++;
  				}
  				if (set.species === 'Necrozma-Dusk-Mane') {
  					if (necrozmaDMCount > 0) {
  						return ['You cannot have more than one Necrozma-Dusk-Mane.'];
  					}
  					necrozmaDMCount++;
  				}
  				if (set.species === 'Necrozma-Dawn-Wings') {
  					if (necrozmaDWCount > 0) {
  						return ['You cannot have more than one Necrozma-Dawn-Wings.'];
  					}
  					necrozmaDWCount++;
  				}
  			}
  			return [];
  		},
  	},
  	obtainablemisc: {
  		effectType: 'ValidatorRule',
  		name: 'Obtainable Misc',
  		desc: "Validate all obtainability things that aren't moves/abilities (Hidden Power type, gender, stats, etc).",
  		// Mostly hardcoded in team-validator.ts
  		onChangeSet(set) {
  			let template = this.dex.getTemplate(set.species);
  
  			if (template.gender) {
  				if (set.gender !== template.gender) {
  					set.gender = template.gender;
  				}
  			} else {
  				if (set.gender !== 'M' && set.gender !== 'F') {
  					set.gender = '';
  				}
  			}
  
  			// limit one of each move
  			let moves = [];
  			if (set.moves) {
  				/**@type {{[k: string]: true}} */
  				let hasMove = {};
  				for (const moveId of set.moves) {
  					let move = this.dex.getMove(moveId);
  					let moveid = move.id;
  					if (hasMove[moveid]) continue;
  					hasMove[moveid] = true;
  					moves.push(moveId);
  				}
  			}
  			set.moves = moves;
  		},
  	},
  	hoennpokedex: {
  		effectType: 'ValidatorRule',
  		name: 'Hoenn Pokedex',
  		desc: "Only allows Pok&eacute;mon native to the Hoenn region (OR/AS)",
  		onValidateSet(set, format) {
  			let hoennDex = [
  				"Abra", "Absol", "Aggron", "Alakazam", "Altaria", "Anorith", "Armaldo", "Aron", "Azumarill", "Azurill", "Bagon", "Baltoy", "Banette", "Barboach", "Beautifly", "Beldum", "Bellossom", "Blaziken", "Breloom", "Budew", "Cacnea", "Cacturne", "Camerupt", "Carvanha", "Cascoon", "Castform", "Chimecho", "Chinchou", "Chingling", "Clamperl", "Claydol", "Combusken", "Corphish", "Corsola", "Cradily", "Crawdaunt", "Crobat", "Delcatty", "Dodrio", "Doduo", "Donphan", "Dusclops", "Dusknoir", "Duskull", "Dustox", "Electrike", "Electrode", "Exploud", "Feebas", "Flygon", "Froslass", "Gallade", "Gardevoir", "Geodude", "Girafarig", "Glalie", "Gloom", "Golbat", "Goldeen", "Golduck", "Golem", "Gorebyss", "Graveler", "Grimer", "Grovyle", "Grumpig", "Gulpin", "Gyarados", "Hariyama", "Heracross", "Horsea", "Huntail", "Igglybuff", "Illumise", "Jigglypuff", "Kadabra", "Kecleon", "Kingdra", "Kirlia", "Koffing", "Lairon", "Lanturn", "Latias", "Latios", "Lileep", "Linoone", "Lombre", "Lotad", "Loudred", "Ludicolo", "Lunatone", "Luvdisc", "Machamp", "Machoke", "Machop", "Magcargo", "Magikarp", "Magnemite", "Magneton", "Magnezone", "Makuhita", "Manectric", "Marill", "Marshtomp", "Masquerain", "Mawile", "Medicham", "Meditite", "Metagross", "Metang", "Mightyena", "Milotic", "Minun", "Mudkip", "Muk", "Natu", "Nincada", "Ninetales", "Ninjask", "Nosepass", "Numel", "Nuzleaf", "Oddish", "Pelipper", "Phanpy", "Pichu", "Pikachu", "Pinsir", "Plusle", "Poochyena", "Probopass", "Psyduck", "Raichu", "Ralts", "Regice", "Regirock", "Registeel", "Relicanth", "Rhydon", "Rhyhorn", "Rhyperior", "Roselia", "Roserade", "Sableye", "Salamence", "Sandshrew", "Sandslash", "Sceptile", "Seadra", "Seaking", "Sealeo", "Seedot", "Seviper", "Sharpedo", "Shedinja", "Shelgon", "Shiftry", "Shroomish", "Shuppet", "Silcoon", "Skarmory", "Skitty", "Slaking", "Slakoth", "Slugma", "Snorunt", "Solrock", "Spheal", "Spinda", "Spoink", "Starmie", "Staryu", "Surskit", "Swablu", "Swalot", "Swampert", "Swellow", "Taillow", "Tentacool", "Tentacruel", "Torchic", "Torkoal", "Trapinch", "Treecko", "Tropius", "Vibrava", "Vigoroth", "Vileplume", "Volbeat", "Voltorb", "Vulpix", "Wailmer", "Wailord", "Walrein", "Weezing", "Whiscash", "Whismur", "Wigglytuff", "Wingull", "Wobbuffet", "Wurmple", "Wynaut", "Xatu", "Zangoose", "Zigzagoon", "Zubat",
  			];
  			let template = this.dex.getTemplate(set.species || set.name);
  			if (!hoennDex.includes(template.baseSpecies) && !this.ruleTable.has('+' + template.speciesid)) {
  				return [template.baseSpecies + " is not in the Hoenn Pokédex."];
  			}
  		},
  	},
  	sinnohpokedex: {
  		effectType: 'ValidatorRule',
  		name: 'Sinnoh Pokedex',
  		desc: "Only allows Pok&eacute;mon native to the Sinnoh region (Platinum)",
  		onValidateSet(set, format) {
  			let sinnohDex = [
  				"Turtwig", "Grotle", "Torterra", "Chimchar", "Monferno", "Infernape", "Piplup", "Prinplup", "Empoleon", "Starly", "Staravia", "Staraptor", "Bidoof", "Bibarel", "Kricketot", "Kricketune", "Shinx", "Luxio", "Luxray", "Abra", "Kadabra", "Alakazam", "Magikarp", "Gyarados", "Budew", "Roselia", "Roserade", "Zubat", "Golbat", "Crobat", "Geodude", "Graveler", "Golem", "Onix", "Steelix", "Cranidos", "Rampardos", "Shieldon", "Bastiodon", "Machop", "Machoke", "Machamp", "Psyduck", "Golduck", "Burmy", "Wormadam", "Mothim", "Wurmple", "Silcoon", "Beautifly", "Cascoon", "Dustox", "Combee", "Vespiquen", "Pachirisu", "Buizel", "Floatzel", "Cherubi", "Cherrim", "Shellos", "Gastrodon", "Heracross", "Aipom", "Ambipom", "Drifloon", "Drifblim", "Buneary", "Lopunny", "Gastly", "Haunter", "Gengar", "Misdreavus", "Mismagius", "Murkrow", "Honchkrow", "Glameow", "Purugly", "Goldeen", "Seaking", "Barboach", "Whiscash", "Chingling", "Chimecho", "Stunky", "Skuntank", "Meditite", "Medicham", "Bronzor", "Bronzong", "Ponyta", "Rapidash", "Bonsly", "Sudowoodo", "Mime Jr.", "Mr. Mime", "Happiny", "Chansey", "Blissey", "Cleffa", "Clefairy", "Clefable", "Chatot", "Pichu", "Pikachu", "Raichu", "Hoothoot", "Noctowl", "Spiritomb", "Gible", "Gabite", "Garchomp", "Munchlax", "Snorlax", "Unown", "Riolu", "Lucario", "Wooper", "Quagsire", "Wingull", "Pelipper", "Girafarig", "Hippopotas", "Hippowdon", "Azurill", "Marill", "Azumarill", "Skorupi", "Drapion", "Croagunk", "Toxicroak", "Carnivine", "Remoraid", "Octillery", "Finneon", "Lumineon", "Tentacool", "Tentacruel", "Feebas", "Milotic", "Mantyke", "Mantine", "Snover", "Abomasnow", "Sneasel", "Weavile", "Uxie", "Mesprit", "Azelf", "Dialga", "Palkia", "Manaphy", "Rotom", "Gligar", "Gliscor", "Nosepass", "Probopass", "Ralts", "Kirlia", "Gardevoir", "Gallade", "Lickitung", "Lickilicky", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon", "Swablu", "Altaria", "Togepi", "Togetic", "Togekiss", "Houndour", "Houndoom", "Magnemite", "Magneton", "Magnezone", "Tangela", "Tangrowth", "Yanma", "Yanmega", "Tropius", "Rhyhorn", "Rhydon", "Rhyperior", "Duskull", "Dusclops", "Dusknoir", "Porygon", "Porygon2", "Porygon-Z", "Scyther", "Scizor", "Elekid", "Electabuzz", "Electivire", "Magby", "Magmar", "Magmortar", "Swinub", "Piloswine", "Mamoswine", "Snorunt", "Glalie", "Froslass", "Absol", "Giratina",
  			];
  			let template = this.dex.getTemplate(set.species || set.name);
  			if ((!sinnohDex.includes(template.baseSpecies) || template.gen > 4) && !this.ruleTable.has('+' + template.speciesid)) {
  				return [`${template.species} is not in the Sinnoh Pokédex.`];
  			}
  		},
  	},
  	kalospokedex: {
  		effectType: 'ValidatorRule',
  		name: 'Kalos Pokedex',
  		desc: "Only allows Pok&eacute;mon native to the Kalos region (XY)",
  		onValidateSet(set, format) {
  			let kalosDex = [
  				"Chespin", "Quilladin", "Chesnaught", "Fennekin", "Braixen", "Delphox", "Froakie", "Frogadier", "Greninja", "Bunnelby", "Diggersby", "Zigzagoon", "Linoone", "Fletchling", "Fletchinder", "Talonflame", "Pidgey", "Pidgeotto", "Pidgeot", "Scatterbug", "Spewpa", "Vivillon", "Caterpie", "Metapod", "Butterfree", "Weedle", "Kakuna", "Beedrill", "Pansage", "Simisage", "Pansear", "Simisear", "Panpour", "Simipour", "Pichu", "Pikachu", "Raichu", "Bidoof", "Bibarel", "Dunsparce", "Azurill", "Marill", "Azumarill", "Burmy", "Wormadam", "Mothim", "Surskit", "Masquerain", "Magikarp", "Gyarados", "Corphish", "Crawdaunt", "Goldeen", "Seaking", "Carvanha", "Sharpedo", "Litleo", "Pyroar", "Psyduck", "Golduck", "Farfetch'd", "Riolu", "Lucario", "Ralts", "Kirlia", "Gardevoir", "Gallade", "Flabe\u0301be\u0301", "Floette", "Florges", "Budew", "Roselia", "Roserade", "Ledyba", "Ledian", "Combee", "Vespiquen", "Skitty", "Delcatty", "Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard", "Squirtle", "Wartortle", "Blastoise", "Skiddo", "Gogoat", "Pancham", "Pangoro", "Furfrou", "Doduo", "Dodrio", "Plusle", "Minun", "Gulpin", "Swalot", "Scraggy", "Scrafty", "Abra", "Kadabra", "Alakazam", "Oddish", "Gloom", "Vileplume", "Bellossom", "Sentret", "Furret", "Nincada", "Ninjask", "Shedinja", "Espurr", "Meowstic", "Kecleon", "Honedge", "Doublade", "Aegislash", "Venipede", "Whirlipede", "Scolipede", "Audino", "Smeargle", "Croagunk", "Toxicroak", "Ducklett", "Swanna", "Spritzee", "Aromatisse", "Swirlix", "Slurpuff", "Volbeat", "Illumise", "Hoppip", "Skiploom", "Jumpluff", "Munchlax", "Snorlax", "Whismur", "Loudred", "Exploud", "Meditite", "Medicham", "Zubat", "Golbat", "Crobat", "Axew", "Fraxure", "Haxorus", "Diancie", "Hoopa", "Volcanion",
  				"Drifloon", "Drifblim", "Mienfoo", "Mienshao", "Zangoose", "Seviper", "Spoink", "Grumpig", "Absol", "Inkay", "Malamar", "Lunatone", "Solrock", "Bagon", "Shelgon", "Salamence", "Wingull", "Pelipper", "Taillow", "Swellow", "Binacle", "Barbaracle", "Dwebble", "Crustle", "Tentacool", "Tentacruel", "Wailmer", "Wailord", "Luvdisc", "Skrelp", "Dragalge", "Clauncher", "Clawitzer", "Staryu", "Starmie", "Shellder", "Cloyster", "Qwilfish", "Horsea", "Seadra", "Kingdra", "Relicanth", "Sandile", "Krokorok", "Krookodile", "Helioptile", "Heliolisk", "Hippopotas", "Hippowdon", "Rhyhorn", "Rhydon", "Rhyperior", "Onix", "Steelix", "Woobat", "Swoobat", "Machop", "Machoke", "Machamp", "Cubone", "Marowak", "Kangaskhan", "Mawile", "Tyrunt", "Tyrantrum", "Amaura", "Aurorus", "Aerodactyl", "Ferroseed", "Ferrothorn", "Snubbull", "Granbull", "Electrike", "Manectric", "Houndour", "Houndoom", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon", "Sylveon", "Emolga", "Yanma", "Yanmega", "Hawlucha", "Sigilyph", "Golett", "Golurk", "Nosepass", "Probopass", "Makuhita", "Hariyama", "Throh", "Sawk", "Starly", "Staravia", "Staraptor", "Stunky", "Skuntank", "Nidoran-F", "Nidorina", "Nidoqueen", "Nidoran-M", "Nidorino", "Nidoking", "Dedenne", "Chingling", "Chimecho", "Mime Jr.", "Mr. Mime", "Solosis", "Duosion", "Reuniclus", "Wynaut", "Wobbuffet", "Roggenrola", "Boldore", "Gigalith", "Sableye", "Carbink", "Tauros", "Miltank", "Mareep", "Flaaffy", "Ampharos", "Pinsir", "Heracross", "Pachirisu", "Slowpoke", "Slowbro", "Slowking", "Exeggcute", "Exeggutor", "Chatot", "Mantyke", "Mantine", "Clamperl", "Huntail", "Gorebyss", "Remoraid", "Octillery", "Corsola", "Chinchou", "Lanturn", "Alomomola", "Lapras", "Articuno", "Zapdos", "Moltres",
  				"Diglett", "Dugtrio", "Trapinch", "Vibrava", "Flygon", "Gible", "Gabite", "Garchomp", "Geodude", "Graveler", "Golem", "Slugma", "Magcargo", "Shuckle", "Skorupi", "Drapion", "Wooper", "Quagsire", "Goomy", "Sliggoo", "Goodra", "Karrablast", "Escavalier", "Shelmet", "Accelgor", "Bellsprout", "Weepinbell", "Victreebel", "Carnivine", "Gastly", "Haunter", "Gengar", "Poliwag", "Poliwhirl", "Poliwrath", "Politoed", "Ekans", "Arbok", "Stunfisk", "Barboach", "Whiscash", "Purrloin", "Liepard", "Poochyena", "Mightyena", "Patrat", "Watchog", "Pawniard", "Bisharp", "Klefki", "Murkrow", "Honchkrow", "Foongus", "Amoonguss", "Lotad", "Lombre", "Ludicolo", "Buizel", "Floatzel", "Basculin", "Phantump", "Trevenant", "Pumpkaboo", "Gourgeist", "Litwick", "Lampent", "Chandelure", "Rotom", "Magnemite", "Magneton", "Magnezone", "Voltorb", "Electrode", "Trubbish", "Garbodor", "Swinub", "Piloswine", "Mamoswine", "Bergmite", "Avalugg", "Cubchoo", "Beartic", "Smoochum", "Jynx", "Vanillite", "Vanillish", "Vanilluxe", "Snover", "Abomasnow", "Delibird", "Sneasel", "Weavile", "Timburr", "Gurdurr", "Conkeldurr", "Torkoal", "Sandshrew", "Sandslash", "Aron", "Lairon", "Aggron", "Larvitar", "Pupitar", "Tyranitar", "Heatmor", "Durant", "Spinarak", "Ariados", "Spearow", "Fearow", "Cryogonal", "Skarmory", "Noibat", "Noivern", "Gligar", "Gliscor", "Hoothoot", "Noctowl", "Igglybuff", "Jigglypuff", "Wigglytuff", "Shuppet", "Banette", "Zorua", "Zoroark", "Gothita", "Gothorita", "Gothitelle", "Bonsly", "Sudowoodo", "Spinda", "Teddiursa", "Ursaring", "Lickitung", "Lickilicky", "Scyther", "Scizor", "Ditto", "Swablu", "Altaria", "Druddigon", "Deino", "Zweilous", "Hydreigon", "Dratini", "Dragonair", "Dragonite", "Xerneas", "Yveltal", "Zygarde", "Mewtwo",
  			];
  			let template = this.dex.getTemplate(set.species || set.name);
  			if ((!kalosDex.includes(template.baseSpecies) || template.gen > 6) && !this.ruleTable.has('+' + template.speciesid)) {
  				return [`${template.species} is not in the Kalos Pokédex.`];
  			}
  		},
  	},
  	alolapokedex: {
  		effectType: 'ValidatorRule',
  		name: 'Alola Pokedex',
  		desc: "Only allows Pok&eacute;mon native to the Alola region (US/UM)",
  		onValidateSet(set, format) {
  			let alolaDex = [
  				"Rowlet", "Dartrix", "Decidueye", "Litten", "Torracat", "Incineroar", "Popplio", "Brionne", "Primarina", "Pikipek", "Trumbeak", "Toucannon", "Yungoos", "Gumshoos", "Rattata-Alola", "Raticate-Alola", "Caterpie", "Metapod", "Butterfree", "Ledyba", "Ledian", "Spinarak", "Ariados", "Buneary", "Lopunny", "Inkay", "Malamar", "Zorua", "Zoroark", "Furfrou", "Pichu", "Pikachu", "Raichu-Alola", "Grubbin", "Charjabug", "Vikavolt", "Bonsly", "Sudowoodo", "Happiny", "Chansey", "Blissey", "Munchlax", "Snorlax", "Slowpoke", "Slowbro", "Slowking", "Wingull", "Pelipper", "Abra", "Kadabra", "Alakazam", "Meowth-Alola", "Persian-Alola", "Magnemite", "Magneton", "Magnezone", "Grimer-Alola", "Muk-Alola", "Mime Jr.", "Mr. Mime", "Ekans", "Arbok", "Dunsparce", "Growlithe", "Arcanine", "Drowzee", "Hypno", "Makuhita", "Hariyama", "Smeargle", "Crabrawler", "Crabominable", "Gastly", "Haunter", "Gengar", "Drifloon", "Drifblim", "Murkrow", "Honchkrow", "Zubat", "Golbat", "Crobat", "Noibat", "Noivern", "Diglett-Alola", "Dugtrio-Alola", "Spearow", "Fearow", "Rufflet", "Braviary", "Vullaby", "Mandibuzz", "Mankey", "Primeape", "Delibird", "Hawlucha", "Oricorio", "Cutiefly", "Ribombee", "Flabe\u0301be\u0301", "Floette", "Florges", "Petilil", "Lilligant", "Cottonee", "Whimsicott", "Psyduck", "Golduck", "Smoochum", "Jynx", "Magikarp", "Gyarados", "Barboach", "Whiscash", "Seal", "Dewgong", "Machop", "Machoke", "Machamp", "Roggenrola", "Boldore", "Gigalith", "Carbink", "Sableye", "Mawile", "Rockruff", "Lycanroc", "Spinda", "Tentacool", "Tentacruel", "Finneon", "Lumineon", "Wishiwashi", "Luvdisc", "Corsola", "Mareanie", "Toxapex", "Shellder", "Cloyster", "Clamperl", "Huntail", "Gorebyss", "Remoraid", "Octillery", "Mantyke", "Mantine", "Bagon", "Shelgon", "Salamence", "Lillipup", "Herdier", "Stoutland", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon", "Sylveon", "Mareep", "Flaaffy", "Ampharos", "Mudbray", "Mudsdale", "Igglybuff", "Jigglypuff", "Wigglytuff", "Tauros", "Miltank", "Surskit", "Masquerain", "Dewpider", "Araquanid", "Fomantis", "Lurantis", "Morelull", "Shiinotic", "Paras", "Parasect", "Poliwag", "Poliwhirl", "Poliwrath", "Politoed", "Goldeen", "Seaking", "Basculin", "Feebas", "Milotic", "Alomomola", "Fletchling", "Fletchinder", "Talonflame", "Salandit", "Salazzle", "Cubone", "Marowak-Alola", "Kangaskhan", "Magby", "Magmar", "Magmortar", "Larvesta", "Volcarona", "Stufful", "Bewear", "Bounsweet", "Steenee", "Tsareena", "Comfey", "Pinsir", "Hoothoot", "Noctowl", "Kecleon", "Oranguru", "Passimian", "Goomy", "Sliggoo", "Goodra", "Castform", "Wimpod", "Golisopod", "Staryu", "Starmie", "Sandygast", "Palossand", "Omanyte", "Omastar", "Kabuto", "Kabutops", "Lileep", "Cradily", "Anorith", "Armaldo", "Cranidos", "Rampardos", "Shieldon", "Bastiodon", "Tirtouga", "Carracosta", "Archen", "Archeops", "Tyrunt", "Tyrantrum", "Amaura", "Aurorus", "Pupitar", "Larvitar", "Tyranitar", "Phantump", "Trevenant", "Natu", "Xatu", "Nosepass", "Probopass", "Pyukumuku", "Chinchou", "Lanturn", "Type: Null", "Silvally", "Poipole", "Naganadel", "Zygarde", "Trubbish", "Garbodor", "Minccino", "Cinccino", "Pineco", "Forretress", "Skarmory", "Ditto", "Cleffa", "Clefairy", "Clefable", "Elgyem", "Beheeyem", "Minior", "Beldum", "Metang", "Metagross", "Porygon", "Porygon2", "Porygon-Z", "Pancham", "Pangoro", "Komala", "Torkoal", "Turtonator", "Houndour", "Houndoom", "Dedenne", "Togedemaru", "Electrike", "Manectric", "Elekid", "Electabuzz", "Electivire", "Geodude-Alola", "Graveler-Alola", "Golem-Alola", "Sandile", "Krokorok", "Krookodile", "Trapinch", "Vibrava", "Flygon", "Gible", "Gabite", "Garchomp", "Baltoy", "Claydol", "Golett", "Golurk", "Klefki", "Mimikyu", "Shuppet", "Banette", "Frillish", "Jellicent", "Bruxish", "Drampa", "Absol", "Snorunt", "Glalie", "Froslass", "Sneasel", "Weavile", "Sandshrew-Alola", "Sandslash-Alola", "Vulpix-Alola", "Ninetales-Alola", "Vanillite", "Vanillish", "Vanilluxe", "Scraggy", "Scrafty", "Pawniard", "Bisharp", "Snubbull", "Granbull", "Shellos", "Gastrodon", "Relicanth", "Dhelmise", "Carvanha", "Sharpedo", "Skrelp", "Dragalge", "Clauncher", "Clawitzer", "Wailmer", "Wailord", "Lapras", "Tropius", "Exeggcute", "Exeggutor-Alola", "Corphish", "Crawdaunt", "Mienfoo", "Mienshao", "Jangmo-o", "Hakamo-o", "Kommo-o", "Emolga", "Scyther", "Scizor", "Heracross", "Aipom", "Ampibom", "Litleo", "Pyroar", "Misdreavus", "Mismagius", "Druddigon", "Lickitung", "Lickilicky", "Riolu", "Lucario", "Dratini", "Dragonair", "Dragonite", "Aerodactyl", "Tapu Koko", "Tapu Lele", "Tapu Bulu", "Tapu Fini", "Cosmog", "Cosmoem", "Solgaleo", "Lunala", "Nihilego", "Stakataka", "Blacephalon", "Buzzwole", "Pheromosa", "Xurkitree", "Celesteela", "Kartana", "Guzzlord", "Necrozma", "Magearna", "Marshadow", "Zeraora",
  			];
  			let template = this.dex.getTemplate(set.species || set.name);
  			if (!alolaDex.includes(template.baseSpecies) && !alolaDex.includes(template.species) && !this.ruleTable.has('+' + template.speciesid)) {
  				return [`${template.baseSpecies} is not in the Alola Pokédex.`];
  			}
  		},
  	},
  	potd: {
  		effectType: 'Rule',
  		name: 'PotD',
  		onBegin() {
  			if (global.Config && global.Config.potd) {
  				this.add('rule', "Pokemon of the Day: " + this.dex.getTemplate(Config.potd).name);
  			}
  		},
  	},
  	teampreview: {
  		effectType: 'Rule',
  		name: 'Team Preview',
  		desc: "Allows each player to see the Pok&eacute;mon on their opponent's team before they choose their lead Pok&eacute;mon",
  		onBegin() {
  			this.add('clearpoke');
  			for (const pokemon of this.getAllPokemon()) {
  				let details = pokemon.details.replace(/(Arceus|Gourgeist|Genesect|Pumpkaboo|Silvally)(-[a-zA-Z?]+)?/g, '$1-*').replace(', shiny', '');
  				this.add('poke', pokemon.side.id, details, pokemon.item ? 'item' : '');
  			}
  		},
  		onTeamPreview() {
  			this.makeRequest('teampreview');
  		},
  	},
  	littlecup: {
  		effectType: 'ValidatorRule',
  		name: 'Little Cup',
  		desc: "Only allows Pok&eacute;mon that can evolve and don't have any prior evolutions",
  		onValidateSet(set) {
  			let template = this.dex.getTemplate(set.species || set.name);
  			if (template.prevo && this.dex.getTemplate(template.prevo).gen <= this.gen) {
  				return [set.species + " isn't the first in its evolution family."];
  			}
  			let futureGenEvo = template.evos && this.dex.getTemplate(template.evos[0]).gen > this.gen;
  			if (!template.nfe || futureGenEvo) {
  				return [set.species + " doesn't have an evolution family."];
  			}
  		},
  	},
  	blitz: {
  		effectType: 'Rule',
  		name: 'Blitz',
  		// THIS 100% INTENTIONALLY SAYS TEN SECONDS PER TURN
  		// IGNORE maxPerTurn. addPerTurn IS 5, TRANSLATING TO AN INCREMENT OF 10.
  		desc: "Super-fast 'Blitz' timer giving 30 second Team Preview and 10 seconds per turn.",
  		onBegin() {
  			this.add('rule', 'Blitz: Super-fast timer');
  		},
  		timer: {starting: 15, addPerTurn: 5, maxPerTurn: 15, maxFirstTurn: 30, grace: 30},
  	},
  	vgctimer: {
  		effectType: 'Rule',
  		name: 'VGC Timer',
  		desc: "VGC's timer: 90 second Team Preview, 7 minutes Your Time, 1 minute per turn",
  		timer: {starting: 7 * 60, addPerTurn: 0, maxPerTurn: 55, maxFirstTurn: 90, grace: 90, timeoutAutoChoose: true, dcTimerBank: false},
  	},
  	speciesclause: {
  		effectType: 'ValidatorRule',
  		name: 'Species Clause',
  		desc: "Prevents teams from having more than one Pok&eacute;mon from the same species",
  		onBegin() {
  			this.add('rule', 'Species Clause: Limit one of each Pokémon');
  		},
  		onValidateTeam(team, format) {
  			/**@type {{[k: string]: true}} */
  			let speciesTable = {};
  			for (const set of team) {
  				let template = this.dex.getTemplate(set.species);
  				if (speciesTable[template.num]) {
  					return ["You are limited to one of each Pokémon by Species Clause.", "(You have more than one " + template.baseSpecies + ")"];
  				}
  				speciesTable[template.num] = true;
  			}
  		},
  	},
  	nicknameclause: {
  		effectType: 'ValidatorRule',
  		name: 'Nickname Clause',
  		desc: "Prevents teams from having more than one Pok&eacute;mon with the same nickname",
  		onValidateTeam(team, format) {
  			/**@type {{[k: string]: true}} */
  			let nameTable = {};
  			for (const set of team) {
  				let name = set.name;
  				if (name) {
  					if (name === this.dex.getTemplate(set.species).baseSpecies) continue;
  					if (nameTable[name]) {
  						return ["Your Pokémon must have different nicknames.", "(You have more than one " + name + ")"];
  					}
  					nameTable[name] = true;
  				}
  			}
  			// Illegality of impersonation of other species is
  			// hardcoded in team-validator.js, so we are done.
  		},
  	},
  	itemclause: {
  		effectType: 'ValidatorRule',
  		name: 'Item Clause',
  		desc: "Prevents teams from having more than one Pok&eacute;mon with the same item",
  		onBegin() {
  			this.add('rule', 'Item Clause: Limit one of each item');
  		},
  		onValidateTeam(team, format) {
  			/**@type {{[k: string]: true}} */
  			let itemTable = {};
  			for (const set of team) {
  				let item = toID(set.item);
  				if (!item) continue;
  				if (itemTable[item]) {
  					return ["You are limited to one of each item by Item Clause.", "(You have more than one " + this.dex.getItem(item).name + ")"];
  				}
  				itemTable[item] = true;
  			}
  		},
  	},
  	abilityclause: {
  		effectType: 'ValidatorRule',
  		name: 'Ability Clause',
  		desc: "Prevents teams from having more than two Pok&eacute;mon with the same ability",
  		onBegin() {
  			this.add('rule', 'Ability Clause: Limit two of each ability');
  		},
  		onValidateTeam(team, format) {
  			/**@type {{[k: string]: number}} */
  			let abilityTable = {};
  			/**@type {{[k: string]: string}} */
  			let base = {
  				airlock: 'cloudnine',
  				battlearmor: 'shellarmor',
  				clearbody: 'whitesmoke',
  				dazzling: 'queenlymajesty',
  				emergencyexit: 'wimpout',
  				filter: 'solidrock',
  				gooey: 'tanglinghair',
  				insomnia: 'vitalspirit',
  				ironbarbs: 'roughskin',
  				minus: 'plus',
  				powerofalchemy: 'receiver',
  				teravolt: 'moldbreaker',
  				turboblaze: 'moldbreaker',
  			};
  			for (const set of team) {
  				let ability = toID(set.ability);
  				if (!ability) continue;
  				if (ability in base) ability = /** @type {ID} */(base[ability]);
  				if (ability in abilityTable) {
  					if (abilityTable[ability] >= 2) {
  						return ["You are limited to two of each ability by the Ability Clause.", `(You have more than two ${this.dex.getAbility(ability).name} variants)`];
  					}
  					abilityTable[ability]++;
  				} else {
  					abilityTable[ability] = 1;
  				}
  			}
  		},
  	},
  	ohkoclause: {
  		effectType: 'ValidatorRule',
  		name: 'OHKO Clause',
  		desc: "Bans all OHKO moves, such as Fissure",
  		onBegin() {
  			this.add('rule', 'OHKO Clause: OHKO moves are banned');
  		},
  		onValidateSet(set) {
  			let problems = [];
  			if (set.moves) {
  				for (const moveId of set.moves) {
  					let move = this.dex.getMove(moveId);
  					if (move.ohko) problems.push(move.name + ' is banned by OHKO Clause.');
  				}
  			}
  			return problems;
  		},
  	},
  	evasionabilitiesclause: {
  		effectType: 'ValidatorRule',
  		name: 'Evasion Abilities Clause',
  		desc: "Bans abilities that boost Evasion under certain weather conditions",
  		banlist: ['Sand Veil', 'Snow Cloak'],
  		onBegin() {
  			this.add('rule', 'Evasion Abilities Clause: Evasion abilities are banned');
  		},
  	},
  	evasionmovesclause: {
  		effectType: 'ValidatorRule',
  		name: 'Evasion Moves Clause',
  		desc: "Bans moves that consistently raise the user's evasion when used",
  		banlist: ['Minimize', 'Double Team'],
  		onBegin() {
  			this.add('rule', 'Evasion Moves Clause: Evasion moves are banned');
  		},
  	},
  	accuracymovesclause: {
  		effectType: 'ValidatorRule',
  		name: 'Accuracy Moves Clause',
  		desc: "Bans moves that have a chance to lower the target's accuracy when used",
  		banlist: ['Flash', 'Kinesis', 'Leaf Tornado', 'Mirror Shot', 'Mud Bomb', 'Mud-Slap', 'Muddy Water', 'Night Daze', 'Octazooka', 'Sand Attack', 'Smokescreen'],
  		onBegin() {
  			this.add('rule', 'Accuracy Moves Clause: Accuracy-lowering moves are banned');
  		},
  	},
  	endlessbattleclause: {
  		effectType: 'Rule',
  		name: 'Endless Battle Clause',
  		desc: "Prevents players from forcing a battle which their opponent cannot end except by forfeit",
  		// implemented in sim/battle.js, see https://dex.pokemonshowdown.com/articles/battlerules#endlessbattleclause for the specification.
  		onBegin() {
  			this.add('rule', 'Endless Battle Clause: Forcing endless battles is banned');
  		},
  	},
  	moodyclause: {
  		effectType: 'ValidatorRule',
  		name: 'Moody Clause',
  		desc: "Bans the ability Moody",
  		banlist: ['Moody'],
  		onBegin() {
  			this.add('rule', 'Moody Clause: Moody is banned');
  		},
  	},
  	swaggerclause: {
  		effectType: 'ValidatorRule',
  		name: 'Swagger Clause',
  		desc: "Bans the move Swagger",
  		banlist: ['Swagger'],
  		onBegin() {
  			this.add('rule', 'Swagger Clause: Swagger is banned');
  		},
  	},
  	batonpassclause: {
  		effectType: 'ValidatorRule',
  		name: 'Baton Pass Clause',
  		desc: "Stops teams from having more than one Pok&eacute;mon with Baton Pass, and no Pok&eacute;mon may be capable of passing boosts to both Speed and another stat",
  		banlist: ["Baton Pass > 1"],
  		onBegin() {
  			this.add('rule', 'Baton Pass Clause: Limit one Baton Passer, can\'t pass Spe and other stats simultaneously');
  		},
  		onValidateSet(set, format, setHas) {
  			if (!('move:batonpass' in setHas)) return;
  
  			let item = this.dex.getItem(set.item);
  			let ability = toID(set.ability);
  			/**@type {boolean | string} */
  			let speedBoosted = false;
  			/**@type {boolean | string} */
  			let nonSpeedBoosted = false;
  
  			for (const moveId of set.moves) {
  				let move = this.dex.getMove(moveId);
  				if (move.id === 'flamecharge' || (move.boosts && move.boosts.spe && move.boosts.spe > 0)) {
  					speedBoosted = true;
  				}
  				if (['acupressure', 'bellydrum', 'chargebeam', 'curse', 'diamondstorm', 'fellstinger', 'fierydance', 'flowershield', 'poweruppunch', 'rage', 'rototiller', 'skullbash', 'stockpile'].includes(move.id) ||
  					move.boosts && ((move.boosts.atk && move.boosts.atk > 0) || (move.boosts.def && move.boosts.def > 0) || (move.boosts.spa && move.boosts.spa > 0) || (move.boosts.spd && move.boosts.spd > 0))) {
  					nonSpeedBoosted = true;
  				}
  				if (item.zMove && move.type === item.zMoveType) {
  					if (move.zMoveBoost && move.zMoveBoost.spe && move.zMoveBoost.spe > 0) {
  						if (!speedBoosted) speedBoosted = move.name;
  					}
  					if (move.zMoveBoost && ((move.zMoveBoost.atk && move.zMoveBoost.atk > 0) || (move.zMoveBoost.def && move.zMoveBoost.def > 0) ||
  						(move.zMoveBoost.spa && move.zMoveBoost.spa > 0) || (move.zMoveBoost.spd && move.zMoveBoost.spd > 0))) {
  						if (!nonSpeedBoosted || move.name === speedBoosted) nonSpeedBoosted = move.name;
  					}
  				}
  			}
  
  			if (['motordrive', 'rattled', 'speedboost', 'steadfast', 'weakarmor'].includes(ability) || ['blazikenite', 'eeviumz', 'kommoniumz', 'salacberry'].includes(item.id)) {
  				speedBoosted = true;
  			}
  			if (!speedBoosted) return;
  
  			if (['angerpoint', 'competitive', 'defiant', 'download', 'justified', 'lightningrod', 'moxie', 'sapsipper', 'stormdrain'].includes(ability) || ['absorbbulb', 'apicotberry', 'cellbattery', 'eeviumz', 'ganlonberry', 'keeberry', 'kommoniumz', 'liechiberry', 'luminousmoss', 'marangaberry', 'petayaberry', 'snowball', 'starfberry', 'weaknesspolicy'].includes(item.id)) {
  				nonSpeedBoosted = true;
  			}
  			if (!nonSpeedBoosted) return;
  
  			// if both boost sources are Z-moves, and they're distinct
  			if (speedBoosted !== nonSpeedBoosted && typeof speedBoosted === 'string' && typeof nonSpeedBoosted === 'string') return;
  
  			return [(set.name || set.species) + " can Baton Pass both Speed and a different stat, which is banned by Baton Pass Clause."];
  		},
  	},
  	"3batonpassclause": {
  		effectType: 'ValidatorRule',
  		name: '3 Baton Pass Clause',
  		desc: "Stops teams from having more than three Pok&eacute;mon with Baton Pass",
  		banlist: ["Baton Pass > 3"],
  		onBegin() {
  			this.add('rule', '3 Baton Pass Clause: Limit three Baton Passers');
  		},
  	},
  	cfzclause: {
  		effectType: 'ValidatorRule',
  		name: 'CFZ Clause',
  		desc: "Bans the use of crystal-free Z-Moves",
  		banlist: ['10,000,000 Volt Thunderbolt', 'Acid Downpour', 'All-Out Pummeling', 'Black Hole Eclipse', 'Bloom Doom', 'Breakneck Blitz', 'Catastropika', 'Clangorous Soulblaze', 'Continental Crush', 'Corkscrew Crash', 'Devastating Drake', 'Extreme Evoboost', 'Genesis Supernova', 'Gigavolt Havoc', 'Guardian of Alola', 'Hydro Vortex', 'Inferno Overdrive', 'Let\'s Snuggle Forever', 'Light That Burns the Sky', 'Malicious Moonsault', 'Menacing Moonraze Maelstrom', 'Never-Ending Nightmare', 'Oceanic Operetta', 'Pulverizing Pancake', 'Savage Spin-Out', 'Searing Sunraze Smash', 'Shattered Psyche', 'Sinister Arrow Raid', 'Soul-Stealing 7-Star Strike', 'Splintered Stormshards', 'Stoked Sparksurfer', 'Subzero Slammer', 'Supersonic Skystrike', 'Tectonic Rage', 'Twinkle Tackle'],
  		onBegin() {
  			this.add('rule', 'CFZ Clause: Crystal-free Z-Moves are banned');
  		},
  	},
  	zmoveclause: {
  		effectType: 'ValidatorRule',
  		name: 'Z-Move Clause',
  		desc: "Bans Pok&eacute;mon from holding Z-Crystals",
  		onValidateSet(set) {
  			const item = this.dex.getItem(set.item);
  			if (item.zMove) return [`${set.name || set.species}'s item ${item.name} is banned by Z-Move Clause.`];
  		},
  		onBegin() {
  			this.add('rule', 'Z-Move Clause: Z-Moves are banned');
  		},
  	},
  	nfeclause: {
  		effectType: 'ValidatorRule',
  		name: 'NFE Clause',
  		desc: "Bans Pok&eacute;mon that are fully evolved or can't evolve",
  		onValidateSet(set) {
  			const template = this.dex.getTemplate(set.species || set.name);
  			if (!template.nfe) {
  				return [set.species + " cannot evolve."];
  			}
  		},
  		onBegin() {
  			this.add('rule', 'NFE Clause: Fully Evolved Pok&eacute;mon are banned');
  		},
  	},
  	hppercentagemod: {
  		effectType: 'Rule',
  		name: 'HP Percentage Mod',
  		desc: "Shows the HP of Pok&eacute;mon in percentages",
  		onBegin() {
  			this.add('rule', 'HP Percentage Mod: HP is shown in percentages');
  			this.reportPercentages = true;
  		},
  	},
  	exacthpmod: {
  		effectType: 'Rule',
  		name: 'Exact HP Mod',
  		desc: "Shows the exact HP of all Pok&eacute;mon",
  		onBegin() {
  			this.add('rule', 'Exact HP Mod: Exact HP is shown');
  			this.reportExactHP = true;
  		},
  	},
  	cancelmod: {
  		effectType: 'Rule',
  		name: 'Cancel Mod',
  		desc: "Allows players to change their own choices before their opponents make one",
  		onBegin() {
  			this.supportCancel = true;
  		},
  	},
  	sleepclausemod: {
  		effectType: 'Rule',
  		name: 'Sleep Clause Mod',
  		desc: "Prevents players from putting more than one of their opponent's Pok&eacute;mon to sleep at a time, and bans Mega Gengar from using Hypnosis",
  		banlist: ['Hypnosis + Gengarite'],
  		onBegin() {
  			this.add('rule', 'Sleep Clause Mod: Limit one foe put to sleep');
  		},
  		onSetStatus(status, target, source) {
  			if (source && source.side === target.side) {
  				return;
  			}
  			if (status.id === 'slp') {
  				for (const pokemon of target.side.pokemon) {
  					if (pokemon.hp && pokemon.status === 'slp') {
  						if (!pokemon.statusData.source || pokemon.statusData.source.side !== pokemon.side) {
  							this.add('-message', 'Sleep Clause Mod activated.');
  							return false;
  						}
  					}
  				}
  			}
  		},
  	},
  	switchpriorityclausemod: {
  		effectType: 'Rule',
  		name: 'Switch Priority Clause Mod',
  		desc: "Makes a faster Pokémon switch first when double-switching, unlike in Emerald link battles, where player 1's Pokémon would switch first",
  		onBegin() {
  			this.add('rule', 'Switch Priority Clause Mod: Faster Pokémon switch first');
  		},
  	},
  	freezeclausemod: {
  		effectType: 'Rule',
  		name: 'Freeze Clause Mod',
  		desc: "Prevents players from freezing more than one of their opponent's Pok&eacute;mon at a time",
  		onBegin() {
  			this.add('rule', 'Freeze Clause Mod: Limit one foe frozen');
  		},
  		onSetStatus(status, target, source) {
  			if (source && source.side === target.side) {
  				return;
  			}
  			if (status.id === 'frz') {
  				for (const pokemon of target.side.pokemon) {
  					if (pokemon.status === 'frz') {
  						this.add('-message', 'Freeze Clause activated.');
  						return false;
  					}
  				}
  			}
  		},
  	},
  	sametypeclause: {
  		effectType: 'ValidatorRule',
  		name: 'Same Type Clause',
  		desc: "Forces all Pok&eacute;mon on a team to share a type with each other",
  		onBegin() {
  			this.add('rule', 'Same Type Clause: Pokémon in a team must share a type');
  		},
  		onValidateTeam(team) {
  			/**@type {string[]} */
  			let typeTable;
  			for (const [i, set] of team.entries()) {
  				let template = this.dex.getTemplate(set.species);
  				if (!template.types) return [`Invalid pokemon ${set.name || set.species}`];
  				if (i === 0) {
  					typeTable = template.types;
  				} else {
  					// @ts-ignore
  					typeTable = typeTable.filter(type => template.types.includes(type));
  				}
  				if (this.gen >= 7) {
  					let item = this.dex.getItem(set.item);
  					if (item.megaStone && template.species === item.megaEvolves) {
  						template = this.dex.getTemplate(item.megaStone);
  						typeTable = typeTable.filter(type => template.types.includes(type));
  					}
  					if (item.id === "ultranecroziumz" && template.baseSpecies === "Necrozma") {
  						template = this.dex.getTemplate("Necrozma-Ultra");
  						typeTable = typeTable.filter(type => template.types.includes(type));
  					}
  				}
  				if (!typeTable.length) return [`Your team must share a type.`];
  			}
  		},
  	},
  	megarayquazaclause: {
  		effectType: 'Rule',
  		name: 'Mega Rayquaza Clause',
  		desc: "Prevents Rayquaza from mega evolving",
  		onBegin() {
  			this.add('rule', 'Mega Rayquaza Clause: You cannot mega evolve Rayquaza');
  			for (const pokemon of this.getAllPokemon()) {
  				if (pokemon.speciesid === 'rayquaza') pokemon.canMegaEvo = null;
  			}
  		},
  	},
  	arceusevclause: {
  		effectType: 'ValidatorRule',
  		name: 'Arceus EV Clause',
  		desc: "Restricts Arceus to a maximum of 100 EVs in any one stat",
  		onValidateSet(set, format) {
  			let template = this.dex.getTemplate(set.species);
  			if (template.num === 493 && set.evs) {
  				for (let stat in set.evs) {
  					// @ts-ignore
  					if (set.evs[stat] > 100) return ["Arceus may not have more than 100 of any EVs."];
  				}
  			}
  		},
  	},
  	inversemod: {
  		effectType: 'Rule',
  		name: 'Inverse Mod',
  		desc: "The mod for Inverse Battle which inverts the type effectiveness chart; weaknesses become resistances, while resistances and immunities become weaknesses",
  		onNegateImmunity: false,
  		onBegin() {
  			this.add('rule', 'Inverse Mod: Weaknesses become resistances, while resistances and immunities become weaknesses.');
  		},
  		onEffectiveness(typeMod, target, type, move) {
  			// The effectiveness of Freeze Dry on Water isn't reverted
  			if (move && move.id === 'freezedry' && type === 'Water') return;
  			if (move && !this.dex.getImmunity(move, type)) return 1;
  			return -typeMod;
  		},
  	},
  	ignoreillegalabilities: {
  		effectType: 'ValidatorRule',
  		name: 'Ignore Illegal Abilities',
  		desc: "Allows Pok&eacute;mon to use any ability",
  		// Implemented in the 'pokemon' ruleset and in team-validator.js
  	},
  	stabmonsmovelegality: {
  		effectType: 'ValidatorRule',
  		name: 'STABmons Move Legality',
  		desc: "Allows Pok&eacute;mon to use any move that they or a previous evolution/out-of-battle forme share a type with",
  		checkLearnset(move, template, setSources, set) {
  			const restrictedMoves = this.format.restrictedMoves || [];
  			if (!move.isUnreleased && !move.isZ && !restrictedMoves.includes(move.name)) {
  				let dex = this.dex;
  				let types = template.types;
  				let baseTemplate = dex.getTemplate(template.baseSpecies);
  				if (template.prevo) types = types.concat(dex.getTemplate(dex.getTemplate(template.prevo).prevo || template.prevo).types);
  				if (baseTemplate.otherFormes) {
  					for (const formeid of baseTemplate.otherFormes) {
  						let forme = dex.getTemplate(formeid);
  						if (!forme.battleOnly) {
  							if (forme.forme !== 'Alola' && forme.forme !== 'Alola-Totem' && forme.baseSpecies !== 'Wormadam') {
  								types = types.concat(forme.types).concat(baseTemplate.types);
  							}
  						}
  					}
  				}
  				if (types.includes(move.type)) return null;
  			}
  			return this.checkLearnset(move, template, setSources, set);
  		},
  		unbanlist: ['Shiftry + Leaf Blade + Sucker Punch'],
  	},
  	allowtradeback: {
  		effectType: 'ValidatorRule',
  		name: 'Allow Tradeback',
  		desc: "Allows Gen 1 pokemon to have moves from their Gen 2 learnsets",
  		// Implemented in team-validator.js
  	},
  	allowavs: {
  		effectType: 'ValidatorRule',
  		name: 'Allow AVs',
  		desc: "Tells formats with the 'letsgo' mod to take Awakening Values into consideration when calculating stats",
  		// Implemented in mods/letsgo/rulesets.js
  	},
  };
  
  exports.BattleFormats = BattleFormats;
  