pokemon-dev-utils
Version:
Pokemon utils for developers
189 lines • 6.73 kB
JavaScript
const NATURE_MODIFIERS = {
Hardy: {},
Lonely: { plus: "attack", minus: "defense" },
Brave: { plus: "attack", minus: "speed" },
Adamant: { plus: "attack", minus: "specialAttack" },
Naughty: { plus: "attack", minus: "specialDefense" },
Bold: { plus: "defense", minus: "attack" },
Docile: {},
Relaxed: { plus: "defense", minus: "speed" },
Impish: { plus: "defense", minus: "specialAttack" },
Lax: { plus: "defense", minus: "specialDefense" },
Timid: { plus: "speed", minus: "attack" },
Hasty: { plus: "speed", minus: "defense" },
Serious: {},
Jolly: { plus: "speed", minus: "specialAttack" },
Naive: { plus: "speed", minus: "specialDefense" },
Modest: { plus: "specialAttack", minus: "attack" },
Mild: { plus: "specialAttack", minus: "defense" },
Quiet: { plus: "specialAttack", minus: "speed" },
Bashful: {},
Rash: { plus: "specialAttack", minus: "specialDefense" },
Calm: { plus: "specialDefense", minus: "attack" },
Gentle: { plus: "specialDefense", minus: "defense" },
Sassy: { plus: "specialDefense", minus: "speed" },
Careful: { plus: "specialDefense", minus: "specialAttack" },
Quirky: {},
};
export async function parsePokepasteUrl(url) {
try {
const jsonUrl = url.endsWith('/json') ? url : `${url}/json`;
const response = await fetch(jsonUrl);
if (!response.ok) {
return {
success: false,
error: `HTTP ${response.status}: ${response.statusText}`
};
}
const data = await response.json();
return parsePokepasteText(data.paste, {
title: data.title,
author: data.author,
format: data.notes,
originalUrl: url
});
}
catch (error) {
return {
success: false,
error: `解析 URL 失敗: ${error instanceof Error ? error.message : String(error)}`
};
}
}
export function parsePokepasteText(pasteText, metadata) {
try {
const pokemonBlocks = pasteText
.split(/\r?\n\r?\n/)
.filter(block => block.trim().length > 0);
const pokemon = [];
for (const block of pokemonBlocks) {
const parsed = parsePokemonBlock(block);
if (parsed) {
pokemon.push(parsed);
}
}
if (pokemon.length === 0) {
return {
success: false,
error: '未找到有效的寶可夢資料'
};
}
const team = {
title: metadata?.title,
author: metadata?.author,
format: metadata?.format?.replace('Format: ', '') ?? '',
pokemon,
metadata: {
source: 'pokepaste',
parsedAt: new Date().toISOString(),
originalUrl: metadata?.originalUrl
}
};
return {
success: true,
data: team
};
}
catch (error) {
return {
success: false,
error: `解析文字失敗: ${error instanceof Error ? error.message : String(error)}`
};
}
}
function parsePokemonBlock(block) {
const lines = block.split(/\r?\n/).filter(line => line.trim().length > 0);
if (lines.length === 0)
return null;
// 檢查是否包含寶可夢名稱
const firstLine = lines[0];
if (!firstLine || (!firstLine.includes('@') && !firstLine.match(/^[A-Za-z\-\s\(\)]+$/))) {
return null;
}
const pokemon = {
level: 50,
evs: { hp: 0, attack: 0, defense: 0, specialAttack: 0, specialDefense: 0, speed: 0 },
ivs: { hp: 31, attack: 31, defense: 31, specialAttack: 31, specialDefense: 31, speed: 31 },
stats: { hp: 0, attack: 0, defense: 0, specialAttack: 0, specialDefense: 0, speed: 0 },
moves: []
};
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (i === 0) {
// 第一行:名稱和道具
const [nameWithGender, item] = line.split(' @ ');
if (nameWithGender) {
let name = nameWithGender.trim();
if (name.includes('(M)')) {
pokemon.gender = 'Male';
name = name.replace(/ \(M\)/, '');
}
else if (name.includes('(F)')) {
pokemon.gender = 'Female';
name = name.replace(/ \(F\)/, '');
}
pokemon.name = name;
}
if (item) {
pokemon.item = item.trim();
}
}
else if (line.startsWith('Ability: ')) {
pokemon.ability = line.replace('Ability: ', '').trim();
}
else if (line.startsWith('Level: ')) {
pokemon.level = parseInt(line.replace('Level: ', '').trim()) || 50;
}
else if (line.startsWith('Tera Type: ')) {
pokemon.teraType = line.replace('Tera Type: ', '').trim();
}
else if (line.startsWith('EVs: ')) {
const evString = line.replace('EVs: ', '').trim();
const parsedEvs = parseStats(evString);
Object.assign(pokemon.evs, parsedEvs);
}
else if (line.startsWith('IVs: ')) {
const ivString = line.replace('IVs: ', '').trim();
const parsedIvs = parseStats(ivString);
Object.assign(pokemon.ivs, parsedIvs);
}
else if (line.includes(' Nature')) {
const natureName = line.replace(' Nature', '').trim();
pokemon.nature = natureName;
}
else if (line.startsWith('- ')) {
const move = line.replace('- ', '').trim();
pokemon.moves?.push(move);
}
}
if (!pokemon.name)
return null;
return pokemon;
}
function parseStats(statString) {
const stats = {};
const statPairs = statString.split(' / ');
for (const pair of statPairs) {
const [value, statName] = pair.trim().split(' ');
const numValue = parseInt(value);
if (!isNaN(numValue) && statName) {
const key = getStatKey(statName.trim());
if (key) {
stats[key] = numValue;
}
}
}
return stats;
}
function getStatKey(statName) {
switch (statName.toLowerCase()) {
case 'hp': return 'hp';
case 'atk': return 'attack';
case 'def': return 'defense';
case 'spa': return 'specialAttack';
case 'spd': return 'specialDefense';
case 'spe': return 'speed';
default: return null;
}
}
//# sourceMappingURL=pokepaste-parser.js.map