// ==UserScript==
// @name [Pokechill] 调试模式(队伍编辑 + 物品管理器)
// @namespace https://play-pokechill.github.io/
// @version 1.2
// @description 队伍编辑(可修改等级、特性、技能) + 物品管理器(查看/修改所有物品),统一UI风格
// @author 人民当家做主
// @license MIT
// @icon https://play-pokechill.github.io/img/icons/icon.png
// @match https://play-pokechill.github.io/*
// @match https://g1tyx.github.io/play-pokechill/*
// @require https://cdn.jsdelivr.net/npm/fuse.js@7.1.0
// @grant none
// ==/UserScript==
(function() {
'use strict';
// ---------- 工具函数:获取中文名称 ----------
function getChineseName(id) {
if (!id) return '';
const engName = typeof format === 'function' ? format(id) : id;
if (window.EN_CN_DICT && window.EN_CN_DICT[engName]) {
return window.EN_CN_DICT[engName];
}
return engName;
}
// ---------- 等待游戏核心加载 ----------
function waitForGame() {
if (typeof saved === 'undefined' || typeof pkmn === 'undefined' || typeof move === 'undefined' || typeof ability === 'undefined' || typeof item === 'undefined') {
setTimeout(waitForGame, 300);
return;
}
if (!window.EN_CN_DICT) {
setTimeout(waitForGame, 300);
return;
}
initTeamEditor();
initItemManager();
}
// ========== 队伍编辑模块 ==========
function initTeamEditor() {
addTeamEditorButton();
createTeamEditorPanel();
bindTeamEditorEvents();
}
function addTeamEditorButton() {
const menuItems = document.getElementById('menu-items');
if (!menuItems) return;
if (document.getElementById('team-editor-menu-btn')) return;
const btn = document.createElement('div');
btn.id = 'team-editor-menu-btn';
btn.className = 'menu-item';
btn.innerHTML = `
队伍编辑
`;
btn.addEventListener('click', (e) => {
e.stopPropagation();
openTeamEditor();
});
menuItems.appendChild(btn);
}
function createTeamEditorPanel() {
if (document.getElementById('team-editor-panel')) return;
const panel = document.createElement('div');
panel.id = 'team-editor-panel';
panel.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.85);
z-index: 10000;
display: none;
justify-content: center;
align-items: center;
backdrop-filter: blur(5px);
`;
panel.innerHTML = `
✎ 队伍编辑 (当前队伍: 队伍1)
`;
document.body.appendChild(panel);
}
function openTeamEditor() {
const panel = document.getElementById('team-editor-panel');
if (!panel) return;
if (typeof closeTooltip === 'function') closeTooltip();
populateTeamSlots();
panel.style.display = 'flex';
}
function closeTeamEditor() {
const panel = document.getElementById('team-editor-panel');
if (panel) panel.style.display = 'none';
}
function populateTeamSlots() {
const container = document.getElementById('team-editor-slots');
if (!container) return;
const teamName = saved.currentPreviewTeam || 'preview1';
const team = saved.previewTeams[teamName];
if (!team) {
container.innerHTML = '无法读取队伍数据
';
return;
}
document.getElementById('editor-current-team-name').innerText = teamName.replace('preview', '队伍');
let html = '';
for (let i = 1; i <= 6; i++) {
const slot = team[`slot${i}`];
const pokeId = slot?.pkmn;
const pokeData = pokeId ? pkmn[pokeId] : null;
html += `
${pokeData ? `

` : '❌'}
${pokeData ? getChineseName(pokeId) : '空'} ${pokeId || ''}
${pokeData ? `
等级
` : ''}
${pokeData ? `
特性
${[1,2,3,4].map(m => {
const moveId = pokeData.moves?.[`slot${m}`];
return `
${moveId ? getChineseName(moveId) : '--'}
`;
}).join('')}
` : '
空位,无法编辑
'}
`;
}
container.innerHTML = html;
container.querySelectorAll('.editor-ability-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const slot = btn.dataset.slot;
showAbilitySearch(slot);
});
});
container.querySelectorAll('.editor-move-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const slot = btn.dataset.slot;
const moveSlot = btn.dataset.moveSlot;
showMoveSearch(slot, moveSlot);
});
});
container.querySelectorAll('.editor-level').forEach(input => {
input.addEventListener('change', function() {
const slot = this.dataset.slot;
const val = parseInt(this.value, 10);
updatePokemonLevel(slot, val);
});
});
container.querySelectorAll('.editor-ability-input').forEach(inp => {
inp.addEventListener('click', (e) => {
e.stopPropagation();
const slot = inp.dataset.slot;
showAbilitySearch(slot);
});
});
}
function updatePokemonLevel(slot, newLevel) {
const teamName = saved.currentPreviewTeam || 'preview1';
const team = saved.previewTeams[teamName];
const slotKey = `slot${slot}`;
const pokeId = team[slotKey]?.pkmn;
if (!pokeId) return;
const poke = pkmn[pokeId];
if (!poke) return;
poke.level = Math.min(100, Math.max(1, newLevel));
}
function getMemoryAbilities() {
const memorySet = new Set();
for (let itemId in item) {
const it = item[itemId];
if (it.type === 'memory' && it.ability) {
memorySet.add(it.ability);
}
}
return memorySet;
}
function showAbilitySearch(slot) {
const teamName = saved.currentPreviewTeam || 'preview1';
const team = saved.previewTeams[teamName];
const slotKey = `slot${slot}`;
const pokeId = team[slotKey]?.pkmn;
if (!pokeId) return;
const poke = pkmn[pokeId];
if (!poke) return;
const memoryAbilities = getMemoryAbilities();
const abilityList = [];
for (let abId in ability) {
const ab = ability[abId];
if (ab.type || memoryAbilities.has(abId)) {
abilityList.push({
id: abId,
name: getChineseName(abId),
data: ab
});
}
}
const fuse = new Fuse(abilityList, {
keys: ['name', 'id'],
threshold: 0.3,
includeScore: true
});
showSearchPopup('选择特性', abilityList, fuse, (selectedId) => {
poke.ability = selectedId;
if (poke.hiddenAbility && poke.hiddenAbility.id === selectedId) {
poke.hiddenAbilityUnlocked = true;
}
const input = document.querySelector(`.editor-ability-input[data-slot="${slot}"]`);
if (input) input.value = getChineseName(selectedId);
});
}
function showMoveSearch(slot, moveSlot) {
const teamName = saved.currentPreviewTeam || 'preview1';
const team = saved.previewTeams[teamName];
const slotKey = `slot${slot}`;
const pokeId = team[slotKey]?.pkmn;
if (!pokeId) return;
const poke = pkmn[pokeId];
if (!poke) return;
const moveList = [];
for (let moveId in move) {
const mv = move[moveId];
if (!mv.moveset) continue;
moveList.push({
id: moveId,
name: getChineseName(moveId),
data: mv
});
}
const fuse = new Fuse(moveList, {
keys: ['name', 'id'],
threshold: 0.3,
includeScore: true
});
showSearchPopup(`选择技能 (槽位${moveSlot})`, moveList, fuse, (selectedId) => {
if (!poke.movepool.includes(selectedId)) {
poke.movepool.push(selectedId);
}
poke.moves[`slot${moveSlot}`] = selectedId;
const container = document.querySelector(`.team-editor-slot[data-slot-index="${slot}"] .editor-moves`);
if (container) {
const moveDivs = container.querySelectorAll('.pkmn-movebox');
if (moveDivs[moveSlot-1]) {
moveDivs[moveSlot-1].querySelector('span').textContent = getChineseName(selectedId);
const img = moveDivs[moveSlot-1].querySelector('img');
img.src = `img/icons/${move[selectedId].type}.svg`;
img.style.backgroundColor = `var(--type-${move[selectedId].type})`;
}
}
});
}
function bindTeamEditorEvents() {
document.addEventListener('click', (e) => {
const closeBtn = e.target.closest('#team-editor-close');
if (closeBtn) closeTeamEditor();
const refreshBtn = e.target.closest('#team-editor-refresh');
if (refreshBtn) populateTeamSlots();
const saveBtn = e.target.closest('#team-editor-save');
if (saveBtn) {
if (typeof updatePreviewTeam === 'function') updatePreviewTeam();
closeTeamEditor();
}
});
}
// ========== 物品管理器模块 ==========
function initItemManager() {
addItemManagerButton();
createItemManagerPanel();
bindItemManagerEvents();
}
function addItemManagerButton() {
const menuItems = document.getElementById('menu-items');
if (!menuItems) return;
if (document.getElementById('item-manager-menu-btn')) return;
const btn = document.createElement('div');
btn.id = 'item-manager-menu-btn';
btn.className = 'menu-item';
btn.innerHTML = `
物品管理器
`;
btn.addEventListener('click', (e) => {
e.stopPropagation();
openItemManager();
});
menuItems.appendChild(btn);
}
function createItemManagerPanel() {
if (document.getElementById('item-manager-panel')) return;
const panel = document.createElement('div');
panel.id = 'item-manager-panel';
panel.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.85);
z-index: 10000;
display: none;
justify-content: center;
align-items: center;
backdrop-filter: blur(5px);
`;
panel.innerHTML = `
📦 物品管理器
`;
document.body.appendChild(panel);
}
function openItemManager() {
const panel = document.getElementById('item-manager-panel');
if (!panel) return;
if (typeof closeTooltip === 'function') closeTooltip();
populateItemList();
panel.style.display = 'flex';
}
function closeItemManager() {
const panel = document.getElementById('item-manager-panel');
if (panel) panel.style.display = 'none';
}
function getItemCategory(itemId, itemData) {
if (itemData.type === 'held') {
if (itemData.sort === 'gem') return 'gem';
if (itemData.sort === 'berry') return 'berry';
return 'held';
}
if (itemData.type === 'tm') return 'tm';
if (itemData.type === 'memory') return 'memory';
if (itemData.type === 'decor') return 'decor';
if (itemData.evo) return 'evo';
if (itemData.type === 'key') return 'key';
return 'key';
}
function populateItemList() {
const container = document.getElementById('item-list');
if (!container) return;
const searchTerm = document.getElementById('item-search')?.value.toLowerCase() || '';
const category = document.getElementById('item-category-filter')?.value || 'all';
const allItems = [];
for (let id in item) {
const it = item[id];
if (it.hidden) continue;
const cat = getItemCategory(id, it);
if (category !== 'all' && cat !== category) continue;
const chineseName = getChineseName(id);
if (searchTerm) {
const lowerId = id.toLowerCase();
const lowerName = chineseName.toLowerCase();
if (!lowerId.includes(searchTerm) && !lowerName.includes(searchTerm)) {
continue;
}
}
allItems.push({
id: id,
name: chineseName,
got: it.got || 0,
category: cat,
data: it
});
}
allItems.sort((a, b) => a.id.localeCompare(b.id));
container.innerHTML = '';
if (allItems.length === 0) {
container.innerHTML = '没有找到物品
';
return;
}
allItems.forEach(itemInfo => {
const row = document.createElement('div');
row.style.cssText = `
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.3rem 0.5rem;
background: var(--dark2);
border-radius: 0.5rem;
border: 1px solid var(--light1);
`;
let iconHtml = '';
if (itemInfo.data.type === 'tm') {
const moveId = itemInfo.data.move;
const moveType = move[moveId]?.type || 'normal';
iconHtml = `
`;
} else if (itemInfo.data.type === 'memory') {
const imgColor = itemInfo.data.image || 'dark';
iconHtml = `
`;
} else if (itemInfo.data.type === 'decor') {
iconHtml = `
`;
} else {
iconHtml = `
`;
}
const nameHtml = `
${itemInfo.name}
${itemInfo.id}
`;
const countHtml = `
${itemInfo.got}
`;
const controlsHtml = `
`;
row.innerHTML = iconHtml + nameHtml + countHtml + controlsHtml;
container.appendChild(row);
});
bindItemEvents();
}
function bindItemEvents() {
document.querySelectorAll('.item-dec').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const id = btn.dataset.id;
if (!id || !item[id]) return;
const newVal = Math.max(0, (item[id].got || 0) - 1);
item[id].got = newVal;
const input = document.querySelector(`.item-count[data-id="${id}"]`);
if (input) input.value = newVal;
});
});
document.querySelectorAll('.item-inc').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const id = btn.dataset.id;
if (!id || !item[id]) return;
const newVal = (item[id].got || 0) + 1;
item[id].got = newVal;
const input = document.querySelector(`.item-count[data-id="${id}"]`);
if (input) input.value = newVal;
});
});
document.querySelectorAll('.item-count').forEach(input => {
input.addEventListener('change', (e) => {
e.stopPropagation();
const id = input.dataset.id;
if (!id || !item[id]) return;
let val = parseInt(input.value, 10);
if (isNaN(val) || val < 0) val = 0;
item[id].got = val;
input.value = val;
});
});
}
function bindItemManagerEvents() {
document.addEventListener('click', (e) => {
const closeBtn = e.target.closest('#item-manager-close');
if (closeBtn) closeItemManager();
const refreshBtn = e.target.closest('#item-refresh');
if (refreshBtn) populateItemList();
});
document.getElementById('item-search')?.addEventListener('input', populateItemList);
document.getElementById('item-category-filter')?.addEventListener('change', populateItemList);
}
// ========== 通用搜索弹窗 ==========
function showSearchPopup(title, items, fuseInstance, onSelect) {
const existing = document.getElementById('team-editor-search-popup');
if (existing) existing.remove();
const popup = document.createElement('div');
popup.id = 'team-editor-search-popup';
popup.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
max-width: 90%;
max-height: 80%;
background: var(--dark1);
border: 2px solid var(--light1);
border-radius: 1rem;
padding: 1rem;
z-index: 20000;
display: flex;
flex-direction: column;
gap: 0.8rem;
color: white;
box-shadow: 0 0 30px black;
`;
popup.innerHTML = `
${title}
`;
document.body.appendChild(popup);
const input = document.getElementById('search-popup-input');
const resultsDiv = document.getElementById('search-popup-results');
const closeBtn = document.getElementById('search-popup-close');
function renderResults(list) {
resultsDiv.innerHTML = '';
if (!list.length) {
resultsDiv.innerHTML = '无结果
';
return;
}
list.slice(0, 50).forEach(item => {
const div = document.createElement('div');
div.style.cssText = `
padding: 0.5rem;
background: var(--dark2);
border-radius: 0.3rem;
cursor: pointer;
display: flex;
justify-content: space-between;
`;
div.innerHTML = `${item.name}${item.id}`;
div.addEventListener('click', () => {
onSelect(item.id);
popup.remove();
});
resultsDiv.appendChild(div);
});
}
renderResults(items);
input.addEventListener('input', () => {
const query = input.value.trim();
if (!query) {
renderResults(items);
return;
}
const results = fuseInstance.search(query).map(r => r.item);
renderResults(results);
});
closeBtn.addEventListener('click', () => popup.remove());
const onKeyDown = (e) => {
if (e.key === 'Escape') popup.remove();
};
window.addEventListener('keydown', onKeyDown, { once: true });
}
// 启动
waitForGame();
})();