您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add an export as trainertext button to pokepastes
// ==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') } }); }); })();