Export as Trainertext

Add an export as trainertext button to pokepastes

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==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')
            }
        });
    });
})();