Export as Trainertext

Add an export as trainertext button to pokepastes

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Export as Trainertext
// @namespace    https://pokepast.es/
// @version      2025-08-28
// @license      MIT
// @description  Add an export as trainertext button to pokepastes
// @author       wiresegal
// @match        https://pokepast.es/*
// @grant        GM_addElement
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// ==/UserScript==



(function() {
    'use strict';
    // THIS IS https://unpkg.com/[email protected]/dist/index.mjs, without the export message!
    // CSP issues meant this didn't work on chrome with a dynamic import, so here we are!

    // src/Pokemon.ts
    var POKEMON_STAT_NAMES = ["HP", "Atk", "Def", "SpA", "SpD", "Spe"];
    var Pokemon = class {
        constructor() {
            this.moves = [];
        }
        static fromObject(obj) {
            const p = new Pokemon();
            p.name = obj.name;
            p.nickname = obj.nickname;
            p.gender = obj.gender;
            p.item = obj.item;
            p.ability = obj.ability;
            p.level = obj.level;
            p.shiny = obj.shiny;
            p.happiness = obj.happiness;
            p.nature = obj.nature;
            p.evs = obj.evs;
            p.ivs = obj.ivs;
            p.teraType = obj.teraType;
            p.dynamaxLevel = obj.dynamaxLevel;
            p.gigantamax = obj.gigantamax;
            p.pokeball = obj.pokeball;
            p.moves = Array.isArray(obj.moves) ? obj.moves : [];
            return p;
        }
        toJson(indentation = 2) {
            return JSON.stringify(this, null, indentation);
        }
        toShowdown() {
            let str = "";
            if (this.nickname) {
                str += `${this.nickname} (${this.name})`;
            } else {
                str += `${this.name}`;
            }
            if (this.gender && this.gender.match(/^[MF]$/i)) {
                str += ` (${this.gender.toUpperCase()})`;
            }
            if (this.item) {
                str += ` @ ${this.item}`;
            }
            str += "\n";
            if (this.ability) {
                str += `Ability: ${this.ability}
`;
            }
            if (!Number.isNaN(this.level)) {
                str += `Level: ${this.level}
`;
            }
            if (this.shiny === true) {
                str += `Shiny: Yes
`;
            }
            if (!Number.isNaN(this.happiness)) {
                str += `Happiness: ${this.happiness}
`;
            }
            if (this.pokeball) {
                str += `Pokeball: ${this.pokeball}
`;
            }
            if (!Number.isNaN(this.dynamaxLevel)) {
                str += `Dynamax Level: ${this.dynamaxLevel}
`;
            }
            if (this.gigantamax === true) {
                str += `Gigantamax: Yes
`;
            }
            if (this.teraType) {
                str += `Tera Type: ${this.teraType}
`;
            }
            if (this.evs) {
                const evs = this.evs;
                str += `EVs: ` + POKEMON_STAT_NAMES.filter(function(prop) {
                    return !isNaN(evs[prop.toLowerCase()]);
                }).map(function(prop) {
                    const val = evs[prop.toLowerCase()];
                    return `${val} ${prop}`;
                }).join(" / ") + "\n";
            }
            if (this.nature) {
                str += `${this.nature} Nature
`;
            }
            if (this.ivs) {
                const ivs = this.ivs;
                str += `IVs: ` + POKEMON_STAT_NAMES.filter(function(prop) {
                    return !isNaN(ivs[prop.toLowerCase()]);
                }).map(function(prop) {
                    const val = ivs[prop.toLowerCase()];
                    return `${val} ${prop}`;
                }).join(" / ") + "\n";
            }
            if (this.moves) {
                str += this.moves.map(function(move) {
                    return `- ${move}`;
                }).join("\n") + "\n";
            }
            return str.trim();
        }
        toString() {
            return this.toShowdown();
        }
    };

    // src/PokemonTeam.ts
    var PokemonTeam = class {
        constructor(format = "gen9", name = "Untitled", folder = void 0) {
            this.pokemon = [];
            this.name = name;
            this.format = format;
            this.folder = folder;
        }
        static fromObject(obj) {
            const team = new PokemonTeam();
            team.name = obj.name;
            team.format = obj.format;
            team.folder = obj.folder;
            team.pokemon = obj.pokemon ? obj.pokemon.map(function(pokemon) {
                return Pokemon.fromObject(pokemon);
            }) : [];
            return team;
        }
        toJson(indentation = 2) {
            return JSON.stringify(this, null, indentation);
        }
        toShowdown() {
            const name = this.folder ? `${this.folder}/${this.name}` : this.name;
            let str = `=== [${this.format}] ${name} ===

`;
            str += this.pokemon.map(function(p) {
                return p.toString();
            }).join("\n\n");
            return str.trim();
        }
        toString() {
            return this.toShowdown();
        }
    };

    // src/PokemonTeamSet.ts
    var PokemonTeamSet = class {
        constructor(teams = []) {
            this.teams = teams;
        }
        static fromObject(obj) {
            const teamSet = new PokemonTeamSet();
            teamSet.teams = obj.teams ? obj.teams.map(function(team) {
                return PokemonTeam.fromObject(team);
            }) : [];
            return teamSet;
        }
        toJson(indentation = 2) {
            return JSON.stringify(this, null, indentation);
        }
        toShowdown() {
            return this.teams.map(function(p) {
                return p.toString();
            }).join("\n\n").trim();
        }
        toString() {
            return this.toShowdown();
        }
    };

    // src/ShowdownParser.ts
    var clamp = (num, min, max) => {
        if (Number.isNaN(num)) {
            return min;
        }
        return Math.min(Math.max(num, min), max);
    };
    var _ShowdownParser = class {
        constructor(code) {
            this.code = code.toString().trim();
        }
        parse() {
            const regexes = _ShowdownParser.regexes;
            const teams = [];
            const current = {
                team: null,
                pokemon: null
            };
            const lines = this.code.trim().split("\n").map(function(line) {
                return line.trim();
            });
            lines.forEach((line) => {
                if (line.match(regexes.team)) {
                    current.team = new PokemonTeam();
                    this._parseTeam(line, current.team);
                    teams.push(current.team);
                    return;
                }
                if (line === "" || line.match(/^[- ]+$/)) {
                    this._saveCurrent(teams, current);
                    return;
                }
                if (!current.pokemon) {
                    current.pokemon = new Pokemon();
                    this._parseNameLine(line, current.pokemon);
                    return;
                }
                if (this._parseKeyValuePairs(line, current.pokemon)) {
                    return;
                }
                if (this._parseEvsIvs(line, current.pokemon)) {
                    return;
                }
                if (current.pokemon.moves.length < 4 && line.match(regexes.move)) {
                    const moveMatches = regexes.move.exec(line);
                    if (moveMatches !== null) {
                        current.pokemon.moves.push(moveMatches[1].trim());
                    }
                }
            });
            this._saveCurrent(teams, current);
            return new PokemonTeamSet(teams);
        }
        _parseTeam(line, team) {
            const rg = _ShowdownParser.regexes;
            const teamDataMatches = rg.team.exec(line);
            if (teamDataMatches && teamDataMatches.length >= 2) {
                const teamNames = teamDataMatches[2].split("/");
                let teamName, teamFolder;
                if (teamNames.length > 1) {
                    teamFolder = teamNames.shift();
                    teamName = teamNames.join("/");
                } else {
                    teamName = teamDataMatches[2];
                }
                team.format = teamDataMatches[1].trim();
                team.name = teamName.trim();
                team.folder = teamFolder ? teamFolder.trim() : void 0;
            }
        }
        _parseNameLine(line, pokemon) {
            const rg = _ShowdownParser.regexes;
            if (line.match(rg.nickname_name)) {
                const nameMatches = rg.nickname_name.exec(line);
                if (nameMatches) {
                    pokemon.nickname = nameMatches[1].trim();
                    pokemon.name = nameMatches[2].trim();
                }
            } else if (line.match(rg.name)) {
                const nameMatches = rg.name.exec(line);
                if (nameMatches) {
                    pokemon.name = nameMatches[1].trim();
                }
            }
            if (line.match(rg.gender)) {
                const genderMatches = rg.gender.exec(line);
                if (genderMatches) {
                    pokemon.gender = genderMatches[1].toUpperCase().trim();
                }
            }
            if (line.match(rg.item)) {
                const itemMatches = rg.item.exec(line);
                if (itemMatches) {
                    pokemon.item = itemMatches[1].trim();
                }
            }
        }
        _parseEvsIvs(line, pokemon) {
            const rg = _ShowdownParser.regexes;
            if (line.match(rg.eivs)) {
                const data = rg.eivs.exec(line);
                if (data === null) {
                    return false;
                }
                const prop = data[1].toLowerCase();
                const values = data[2].split("/");
                const limit = prop === "evs" ? 255 : 31;
                values.forEach(function(stat) {
                    const statData = rg.eivs_value.exec(stat.trim().toLowerCase());
                    if (!statData) {
                        console.error("Invalid syntax for " + prop + ": " + stat);
                        return;
                    }
                    if (!pokemon[prop]) {
                        pokemon[prop] = {};
                    }
                    pokemon[prop][statData[2]] = clamp(parseInt(statData[1]), 0, limit);
                });
                return true;
            }
            return false;
        }
        _parseKeyValuePairs(line, pokemon) {
            const propNames = [
                "nature",
                "ability",
                "level",
                "shiny",
                "happiness",
                "pokeball",
                "dynamaxLevel",
                "gigantamax",
                "teraType"
            ];
            return propNames.some(function(key) {
                const matches = _ShowdownParser.regexes[key].exec(line);
                if (matches === null) {
                    return false;
                }
                let value = matches[1].trim();
                if (key === "happiness") {
                    value = clamp(parseInt(value), 0, 255);
                } else if (key === "level") {
                    value = clamp(parseInt(value), 1, 100);
                } else if (key === "dynamaxLevel") {
                    value = clamp(parseInt(value), 0, 10);
                } else if (key.match(/^(shiny|gigantamax)$/i)) {
                    value = value.match(/yes/i) !== null ? true : void 0;
                }
                pokemon[key] = value;
                return true;
            });
        }
        _saveCurrent(teams, current) {
            if (!current.team) {
                current.team = new PokemonTeam();
                teams.push(current.team);
            }
            if (current.pokemon) {
                current.team.pokemon.push(current.pokemon);
                current.pokemon = null;
            }
            return this;
        }
        format() {
            this.code = this.parse().toString();
            return this;
        }
        toString() {
            return this.code;
        }
    };
    var ShowdownParser = _ShowdownParser;
    ShowdownParser.regexes = {
        team: /^===\s+\[(.*)\]\s+(.*)\s+===$/,
        nickname_name: /^([^()=@]*)\s+\(([^()=@]{2,})\)/i,
        name: /^([^()=@]{2,})/i,
        gender: /\((F|M)\)/i,
        item: /@\s?(.*)$/i,
        eivs: /^([EI]Vs):\s?(.*)$/i,
        eivs_value: /^([0-9]+)\s+(hp|atk|def|spa|spd|spe)$/i,
        move: /^[-~]\s?(.*)$/i,
        nature: /^(.*)\s+Nature$/,
        ability: /^(?:Ability|Trait):\s?(.*)$/i,
        level: /^Level:\s?([0-9]{1,3})$/i,
        shiny: /^Shiny:\s?(Yes|No)$/i,
        happiness: /^(?:Happiness|Friendship):\s?([0-9]{1,3})$/i,
        pokeball: /^(?:Pokeball|Ball):\s?(.*)$/i,
        dynamaxLevel: /^Dynamax Level:\s?([0-9]{1,2})$/i,
        gigantamax: /^Gigantamax:\s?(Yes|No)$/i,
        teraType: /^Tera Type:\s?(.*)$/i
    };

    // src/Koffing.ts
    var Koffing = class {
        static parse(data) {
            if (data instanceof PokemonTeamSet || data instanceof PokemonTeam || data instanceof Pokemon) {
                return data;
            }
            if (data instanceof ShowdownParser) {
                return data.parse();
            }
            return new ShowdownParser(data).parse();
        }
        static format(data) {
            return this.parse(data).toShowdown();
        }
        static toJson(data) {
            return this.parse(data).toJson();
        }
        static toShowdown(data) {
            if (data instanceof PokemonTeamSet || data instanceof PokemonTeam || data instanceof Pokemon) {
                return data.toShowdown();
            }
            if (data instanceof ShowdownParser) {
                return data.parse().toShowdown();
            }
            if (typeof data === "string") {
                data = JSON.parse(data);
            }
            return PokemonTeamSet.fromObject(data).toShowdown();
        }
    };

    // Begin actual plugin code

    GM_addElement(GM_addElement(document.getElementsByTagName('aside')[0], 'p'), 'button', {
        textContent: "Export to Trainertext"
    }).addEventListener("click", function (ev) {
        GM_xmlhttpRequest({
            url: window.location + '/raw',
            onload: async res => {
                const koff = Koffing.parse(res.responseText);
                const teams = [];
                koff.teams.forEach(teamraw => {
                    let ttx = '{\n' +
                        ':teamid => ["Dummy",:TCLASS,id],\n' +
                        ':defeat => "Dummy text",\n' +
                        ':mons => [';
                    const mons = [];
                    teamraw.pokemon.forEach(monraw => {
                        let form = 0;
                        let formmatch = monraw.name.match(/(?<species>.*)-(Aevium|Alola|Paldea|Galar|Hisui)$/);
                        if (formmatch) {
                            form = 1;
                            monraw.name = formmatch.groups.species;
                        }
                        let mtx = '{\n' +
                            '    :species => :' + monraw.name.replaceAll(/\W/g, '').toUpperCase() + ',\n';
                        if (monraw.nickname) {
                            '    :name => ' + JSON.stringify(monraw.nickname) + ',\n';
                        }
                        mtx += '    :level => ' + monraw.level + ',\n';
                        if (monraw.item) {
                            mtx += '    :item => :' + monraw.item.replaceAll(/\W/g, '').toUpperCase() + ',\n';
                        }
                        let moves = []
                        monraw.moves.forEach(moveraw => {
                            moves.push(':' + moveraw.replaceAll(/\W/g, '').toUpperCase());
                        });
                        mtx += '    :moves => [' + moves.join(',') + '],\n';
                        mtx += '    :ability => :' + monraw.ability.replaceAll(/\W/g, '').toUpperCase() + ',\n';
                        if (monraw.gender) {
                            mtx += '    :gender => "' + monraw.gender + '",\n';
                        }
                        if (monraw.shiny) {
                            mtx += '    :shiny => true,\n';
                        }
                        if (form > 0) {
                            mtx += '    :form => ' + form + ',\n';
                        }
                        mtx += '    :nature => :' + monraw.nature.toUpperCase() + ',\n';
                        if (monraw.ivs && monraw.ivs.spe === 0) {
                            mtx += '    :iv => 32,\n';
                        } else {
                            mtx += '    :iv => 31,\n';
                        }
                        let evs = ['hp', 'atk', 'def', 'spa', 'spd', 'spe'].map(key => {
                            if (monraw.evs && monraw.evs[key]) {
                                return monraw.evs[key]
                            } else {
                                return 0
                            }
                        });
                        mtx += '    :ev => [' + evs.join(', ') + ']}';
                        mons.push(mtx);
                    });
                    ttx += mons.join(',\n') + ']},\n';
                    teams.push(ttx);
                });
                GM_setClipboard(teams.join(''), 'text')
            }
        });
    });
})();