Resource Other Metagames Code Megathread

Kris

joe mama
is a Top Social Media Contributoris a Programmeris a Forum Moderatoris a Community Contributoris a Live Chat Contributor Alumnusis a Contributor Alumnusis a Top Smogon Media Contributor Alumnusis a Battle Simulator Driver Alumnus
Moderator
approved by The Immortal; taken over from Spandan
Previous threads: ORAS | USUM


Hi, there!
This thread intends to collect the code required to play the approved Other Metagamess.

How to contribute?

You may provide a Github Gist, Pastebin (or a similar site), or a post containing either the code itself required to implement the OM or the diffs involved in its implementation (so a link to a dedicated commit or pull request would be cool). This is the way to go for OMs that dynamically change (e.g. Theorymon, OM Mashup, Pokémon Throwback, etc.) Past versions of periodical OMs can be published though.

For small, simple OMs (in the way of coding, at least), you may just post it fully, using the format showcased below.

If you want to request to have an OM coded, simply post to ask for the request; this includes past-gen OMs.

Gen 8 OMs
config/formats.js
JavaScript:
    {
        name: "[Gen 8] Inheritance",
        desc: `Pokémon may use the ability and moves of another, as long as they forfeit their own learnset.`,
        threads: [
            `&bullet; <a href="https://www.smogon.com/forums/threads/3656811/">Inheritance</a>`,
        ],

        mod: 'gen8',
        ruleset: ['[Gen 8] OU'],
        banlist: ['Shedinja', 'Assist', 'Shell Smash', 'Arena Trap', 'Huge Power', 'Imposter', 'Innards Out', 'Pure Power', 'Water Bubble'],
        restricted: ['Dracovish', 'Dracozolt'],
        // @ts-ignore
        getEvoFamily(speciesid) {
            let species = Dex.getSpecies(speciesid);
            while (species.prevo) {
                species = Dex.getSpecies(species.prevo);
            }
            return species.id;
        },
        validateSet(set, teamHas) {
            const bannedDonors = this.format.restricted || [];
            if (!teamHas.abilityMap) {
                teamHas.abilityMap = Object.create(null);
                for (const id in Dex.data.Pokedex) {
                    let pokemon = Dex.getSpecies(id);
                    if (pokemon.isNonstandard || pokemon.isUnreleased) continue;
                    if (pokemon.requiredAbility || pokemon.requiredItem || pokemon.requiredMove) continue;
                    if (pokemon.isGigantamax || bannedDonors.includes(pokemon.name)) continue;

                    for (const key of Object.values(pokemon.abilities)) {
                        let abilityId = toID(key);
                        if (abilityId in teamHas.abilityMap) {
                            teamHas.abilityMap[abilityId][pokemon.evos ? 'push' : 'unshift'](id);
                        } else {
                            teamHas.abilityMap[abilityId] = [id];
                        }
                    }
                }
            }

            const problem = this.validateForme(set);
            if (problem.length) return problem;

            let species = Dex.getSpecies(set.species);
            if (!species.exists || species.num < 1) return [`The Pok\u00e9mon "${set.species}" does not exist.`];
            if (species.isNonstandard || species.isUnreleased) return [`${species.name} is not obtainable in gen 8.`];
            if (toID(species.tier) === 'uber' || this.format.banlist.includes(species.name)) {
                return [`${species.name} is banned.`];
            }

            const name = set.name;

            let ability = Dex.getAbility(set.ability);
            if (!ability.exists || ability.isNonstandard) return [`${name} needs to have a valid ability.`];
            let pokemonWithAbility = teamHas.abilityMap[ability.id];
            if (!pokemonWithAbility) return [`"${set.ability}" is not available on a legal Pok\u00e9mon.`];

            // @ts-ignore
            this.format.debug = true;

            if (!teamHas.abilitySources) teamHas.abilitySources = Object.create(null);
            /** @type {string[]} */
            let validSources = teamHas.abilitySources[toID(set.species)] = []; // Evolution families

            let canonicalSource = ''; // Specific for the basic implementation of Donor Clause (see onValidateTeam).

            for (const donor of pokemonWithAbility) {
                let donorSpecies = Dex.getSpecies(donor);
                // @ts-ignore
                let evoFamily = this.format.getEvoFamily(donorSpecies);
                if (validSources.includes(evoFamily)) continue;

                set.species = donorSpecies.name;
                const problems = this.validateSet(set, teamHas) || [];
                if (!problems.length) {
                    validSources.push(evoFamily);
                    canonicalSource = donorSpecies.name;
                }
                // Specific for the basic implementation of Donor Clause (see onValidateTeam).
                if (validSources.length > 1) break;
            }
            // @ts-ignore
            this.format.debug = false;

            set.name = name;
            set.species = species.name;
            if (!validSources.length) {
                if (pokemonWithAbility.length > 1) return [`${name}'s set is illegal.`];
                return [`${name} has an illegal set with an ability from ${Dex.getSpecies(pokemonWithAbility[0]).name}.`];
            }

            // Protocol: Include the data of the donor species in the `ability` data slot.
            // Afterwards, we are going to reset the name to what the user intended.
            set.ability = `${set.ability}0${canonicalSource}`;
            return null;
        },
        onValidateTeam(team, format, teamHas) {
            // Donor Clause
            let evoFamilyLists = [];
            for (const set of team) {
                let abilitySources = (teamHas.abilitySources && teamHas.abilitySources[toID(set.species)]);
                if (!abilitySources) continue;
                // @ts-ignore
                evoFamilyLists.push(abilitySources.map(this.format.getEvoFamily));
            }

            // Checking actual full incompatibility would require expensive algebra.
            // Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
            let requiredFamilies = Object.create(null);
            for (const evoFamilies of evoFamilyLists) {
                if (evoFamilies.length !== 1) continue;
                let [familyId] = evoFamilies;
                if (!(familyId in requiredFamilies)) requiredFamilies[familyId] = 1;
                requiredFamilies[familyId]++;
                if (requiredFamilies[familyId] > 2) {
                    return [
                        `You are limited to up to two inheritances from each evolution family by the Donor Clause.`,
                        `(You inherit more than twice from ${this.dex.getSpecies(familyId).name}).`,
                    ];
                }
            }
        },
        onBegin() {
            for (const pokemon of this.getAllPokemon()) {
                if (pokemon.baseAbility.includes('0')) {
                    let donor = pokemon.baseAbility.split('0')[1];
                    pokemon.m.donor = toID(donor);
                    pokemon.baseAbility = toID(pokemon.baseAbility.split('0')[0]);
                    pokemon.ability = pokemon.baseAbility;
                }
            }
        },
        onSwitchIn(pokemon) {
            if (!pokemon.m.donor) return;
            let donorSpecies = this.dex.getSpecies(pokemon.m.donor);
            if (!donorSpecies.exists) return;
            // Place volatiles on the Pokémon to show the donor details.
            this.add('-start', pokemon, donorSpecies.name, '[silent]');
        },
    },
config/formats.js
JavaScript:
    {
        name: "[Gen 8] Pacifistmons",
        desc: `Pok&eacute;mon can only use status moves. Recovery moves are banned.`,
        threads: [
            `&bullet; <a href="https://www.smogon.com/forums/threads/3658719/">Pacifistmons</a>`,
        ],

        mod: 'gen8',
        ruleset: ['[Gen 8] Ubers'],
        banlist: [
            'Magic Bounce', 'Magic Guard', 'Neutralizing Gas', 'Regenerator', 'Assault Vest',
            'Ingrain', 'Life Dew', 'move:Metronome', 'Moonlight', 'Morning Sun', 'Nature Power', 'Purify', 'Recover',
            'Rest', 'Roost', 'Slack Off', 'Soft-Boiled', 'Strength Sap', 'Swallow', 'Synthesis', 'Taunt', 'Wish',
        ],
        onValidateSet(set) {
            if (set.moves) {
                for (const moveid of set.moves) {
                    const move = this.dex.getMove(moveid);
                    if (move.category !== "Status") {
                        return [`${set.species}'s move ${move.name} is banned.`, `(Non-Status moves are banned.)`];
                    }
                }
            }
            if (set.level !== 100) return [`${set.species} must be Level 100.`];
        },
    },
config/formats.js
JavaScript:
    {
        name: "[Gen 8] Trademarked",
        desc: `Sacrifice your Pok&eacute;mon's ability for a status move that activates on switch-in.`,
        threads: [
            `&bullet; <a href="https://www.smogon.com/forums/threads/3656980/">Trademarked</a>`,
        ],

        mod: 'gen8',
        ruleset: ['[Gen 8] OU'],
        banlist: [],
        restricted: [
            'Baneful Bunker', 'Block', 'Copycat', 'Detect', 'Destiny Bond', 'Ingrain', 'King\'s Shield', 'Mean Look', 'Metronome', 'Obstruct',
            'Octolock', 'Nature Power', 'Parting Shot', 'Protect', 'Roar', 'Skill Swap', 'Sleep Talk', 'Spiky Shield', 'Teleport', 'Whirlwind', 'Wish',
        ],
        onValidateTeam(team, format, teamHas) {
            for (const trademark in teamHas.trademarks) {
                if (teamHas.trademarks[trademark] > 1) return [`You are limited to 1 of each Trademark.`, `(You have ${teamHas.trademarks[trademark]} of ${trademark}).`];
            }
        },
        validateSet(set, teamHas) {
            const restrictedMoves = (this.format.restricted || []).concat('Yawn');
            const dex = this.dex;
            let ability = dex.getMove(set.ability);
            if (ability.category !== 'Status' || ability.status === 'slp' || restrictedMoves.includes(ability.name) || set.moves.map(toID).includes(ability.id)) return this.validateSet(set, teamHas);
            let customRules = this.format.customRules || [];
            if (!customRules.includes('!obtainableabilities')) customRules.push('!obtainableabilities');
            const TeamValidator = /** @type {new(format: string | Format) => TeamValidator} */ (this.constructor);
            const validator = new TeamValidator(dex.getFormat(`${this.format.id}@@@${customRules.join(',')}`));
            const moves = set.moves;
            set.moves = [ability.id];
            set.ability = dex.getTemplate(set.species).abilities['0'];
            let problems = validator.validateSet(set, {}) || [];
            if (problems.length) return problems;
            set.moves = moves;
            set.ability = dex.getTemplate(set.species).abilities['0'];
            problems = problems.concat(validator.validateSet(set, teamHas) || []);
            set.ability = ability.id;
            if (!teamHas.trademarks) teamHas.trademarks = {};
            teamHas.trademarks[ability.name] = (teamHas.trademarks[ability.name] || 0) + 1;
            return problems.length ? problems : null;
        },
        pokemon: {
            getAbility() {
                const move = this.battle.dex.getMove(toID(this.ability));
                if (!move.exists) return Object.getPrototypeOf(this).getAbility.call(this);
                return {
                    id: move.id,
                    name: move.name,
                    onStart(pokemon) {
                        this.add('-activate', pokemon, 'ability: ' + move.name);
                        this.useMove(move, pokemon);
                    },
                    toString() {
                        return "";
                    },
                };
            },
        },
    },
config/formats.js
JavaScript:
    {
        name: "[Gen 8] Scalemons",
        desc: `Every Pok&eacute;mon's stats, barring HP, are scaled to give them a BST as close to 600 as possible.`,
        threads: [
            `&bullet; <a href="https://www.smogon.com/forums/threads/3658482/">Scalemons</a>`,
        ],

        mod: 'gen8',
        ruleset: ['[Gen 8] Ubers', 'Dynamax Clause', 'Scalemons Mod'],
        banlist: ['Darmanitan-Galar', 'Gastly', 'Arena Trap', 'Drizzle', 'Drought', 'Huge Power', 'Shadow Tag', 'Baton Pass', 'Eviolite', 'Light Ball'],
    },

OMs that are available on Pokemon Showdown! via a ladder or challenge mode will not have their code displayed on this thread.

Also, useful references:

The code provided in this thread is written to work with the main Pokemon Showdown repository. If your code does not work, it is your responsibility to either adjust the code to work on your server. An alternative is just updating your server's code.
 
Last edited:

Users Who Are Viewing This Thread (Users: 1, Guests: 0)

Top