// ==UserScript== // @name [Pokechill] 自定义木桩测试 // @namespace https://play-pokechill.github.io/ // @version 2.0 // @description 木桩技能池基于所选属性动态过滤,包含所有可学技能。重置按钮同时清空已选技能,修复卡片图片显示。 // @author 人民当家做主 // @icon https://play-pokechill.github.io/img/icons/icon.png // @match https://play-pokechill.github.io/* // @match https://g1tyx.github.io/play-pokechill/* // @grant none // ==/UserScript== (function() { 'use strict'; const dummyAreaId = 'dummyCustom'; const dummyPkmnId = 'dummy_custom'; // 自定义木桩图片(如果图片失效,请替换为有效链接) const DUMMY_SPRITE_URL = 'https://picui.ogmua.cn/s1/2026/03/10/69afa253d4763.webp'; function waitForGame() { if (typeof areas === 'undefined' || typeof pkmn === 'undefined' || typeof move === 'undefined' || typeof ability === 'undefined') { setTimeout(waitForGame, 200); return; } console.log('[DummyCustom] 游戏核心已加载,开始注入...'); initDummyPokemon(); injectDummyTarget(); createConfigPanel(); setupImageErrorHandler(); } waitForGame(); // 全局图片错误处理:将木桩相关的图片请求替换为自定义图片 function setupImageErrorHandler() { document.addEventListener('error', function(e) { const img = e.target; if (img.tagName !== 'IMG') return; if (img.src.includes(`/sprite/${dummyPkmnId}.png`) || img.src.includes(`/sprite/${dummyPkmnId}.gif`) || img.src.includes(`/trainers/.png`)) { if (img.src.includes('/trainers/.png')) { img.style.display = 'none'; e.preventDefault(); return; } img.src = DUMMY_SPRITE_URL; img.onerror = null; console.log('[DummyCustom] 替换图片为自定义木桩图片'); } }, true); } function initDummyPokemon() { if (!pkmn[dummyPkmnId]) { if (!ability.none) { ability.none = { id: 'none', rename: '无', rarity: 1, type: ['all'], info: function() { return '没有任何效果。'; } }; } pkmn[dummyPkmnId] = { id: dummyPkmnId, rename: '木桩-林雷', type: ['normal'], bst: { hp: 6, atk: 4, def: 2, satk: 4, sdef: 2, spe: 4 }, level: 100, exp: 0, caught: 0, shiny: false, ability: 'none', hiddenAbility: undefined, hiddenAbilityUnlocked: false, movepool: [], moves: { slot1: undefined, slot2: undefined, slot3: undefined, slot4: undefined }, ivs: { hp: 0, atk: 0, def: 0, satk: 0, sdef: 0, spe: 0 }, pokerus: false, ribbons: [], newMoves: [], newPokemon: undefined, newEvolution: undefined, tag: undefined, lockHp: true }; } } // 根据当前属性刷新可学技能池(基于 moveset 过滤) function refreshDummyMovepool() { const dummy = pkmn[dummyPkmnId]; if (!dummy) return; const types = dummy.type; const newMovepool = []; for (const moveId in move) { const m = move[moveId]; if (m.moveset) { if (m.moveset.includes('all') || types.some(t => m.moveset.includes(t))) { newMovepool.push(moveId); } } } dummy.movepool = newMovepool; console.log(`[DummyCustom] 刷新技能池,共 ${newMovepool.length} 个技能(基于属性 ${types.join('/')})`); } function ensureDummyArea() { if (!areas[dummyAreaId]) { areas[dummyAreaId] = { name: `木桩测试 (可配置)`, background: 'gym', trainer: true, type: 'vs', level: 100, team: { slot1: pkmn[dummyPkmnId], slot1Moves: [undefined, undefined, undefined, undefined] }, dummy: true, defeated: false, unlockRequirement: () => true, reward: [] }; } } function createConfigPanel() { if (document.getElementById('dummy-config-panel')) return; const panel = document.createElement('div'); panel.id = 'dummy-config-panel'; panel.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--light2, #ECDEB7); border: 2px solid var(--light1, #94886B); border-radius: 0.5rem; padding: 1.5rem; z-index: 10000; display: none; flex-direction: column; gap: 1rem; min-width: 300px; color: var(--dark1, #36342F); font-family: 'Courier New', monospace; box-shadow: 0 0 20px rgba(0,0,0,0.5); `; panel.innerHTML = `

配置木桩

`; document.body.appendChild(panel); const updateType = () => { const type1 = document.getElementById('dummy-type1').value; const type2 = document.getElementById('dummy-type2').value; pkmn[dummyPkmnId].type = type2 ? [type1, type2] : [type1]; }; document.getElementById('dummy-type1').addEventListener('change', updateType); document.getElementById('dummy-type2').addEventListener('change', updateType); document.getElementById('dummy-config-skills').addEventListener('click', () => { updateType(); const level = parseInt(document.getElementById('dummy-level').value, 10); pkmn[dummyPkmnId].level = Math.min(100, Math.max(1, level)); refreshDummyMovepool(); panel.style.display = 'none'; if (typeof tooltipData === 'function') { tooltipData('pkmnEditor', dummyPkmnId); } else { alert('无法打开编辑器'); } }); // 重置按钮:恢复默认属性、等级、锁血,并清空已配置的技能 document.getElementById('dummy-config-reset').addEventListener('click', () => { document.getElementById('dummy-type1').value = 'normal'; document.getElementById('dummy-type2').value = ''; document.getElementById('dummy-level').value = 100; document.getElementById('dummy-lockhp').checked = true; const dummy = pkmn[dummyPkmnId]; dummy.type = ['normal']; dummy.level = 100; dummy.lockHp = true; // 清空已选技能 dummy.moves = { slot1: undefined, slot2: undefined, slot3: undefined, slot4: undefined }; refreshDummyMovepool(); console.log('[DummyCustom] 木桩已重置为默认值,技能已清空'); }); document.getElementById('dummy-config-ok').addEventListener('click', () => { const type1 = document.getElementById('dummy-type1').value; const type2 = document.getElementById('dummy-type2').value; const level = parseInt(document.getElementById('dummy-level').value, 10); const lockHp = document.getElementById('dummy-lockhp').checked; const dummy = pkmn[dummyPkmnId]; dummy.type = type2 ? [type1, type2] : [type1]; dummy.level = Math.min(100, Math.max(1, level)); dummy.lockHp = lockHp; dummy.playerHp = undefined; panel.style.display = 'none'; saved.currentAreaBuffer = dummyAreaId; document.getElementById('preview-team-exit').style.display = 'flex'; document.getElementById('team-menu').style.zIndex = '50'; document.getElementById('team-menu').style.display = 'flex'; document.getElementById('menu-button-parent').style.display = 'none'; updatePreviewTeam(); afkSeconds = 0; document.getElementById('explore-menu').style.display = 'none'; }); document.getElementById('dummy-config-cancel').addEventListener('click', () => { panel.style.display = 'none'; }); } function injectDummyTarget() { ensureDummyArea(); const originalUpdateVS = updateVS; updateVS = function() { originalUpdateVS(); const vsListing = document.getElementById('vs-listing'); if (!vsListing) return; const existingCards = vsListing.querySelectorAll(`[data-trainer="${dummyAreaId}"]`); existingCards.forEach(card => card.remove()); const dummyCard = document.createElement('div'); dummyCard.className = 'vs-card'; dummyCard.dataset.trainer = dummyAreaId; dummyCard.innerHTML = `
自定义木桩 测试木桩
`; dummyCard.addEventListener('click', () => { const panel = document.getElementById('dummy-config-panel'); if (panel) { const dummy = pkmn[dummyPkmnId]; document.getElementById('dummy-type1').value = dummy.type[0] || 'normal'; document.getElementById('dummy-type2').value = dummy.type[1] || ''; document.getElementById('dummy-level').value = dummy.level; document.getElementById('dummy-lockhp').checked = dummy.lockHp; panel.style.display = 'flex'; } }); vsListing.appendChild(dummyCard); }; } const originalSetWildPkmn = setWildPkmn; setWildPkmn = function() { if (saved.currentArea === dummyAreaId) { const dummy = pkmn[dummyPkmnId]; if (!dummy) return; barProgressWild = 0; exploreCombatWildTurn = 1; ['team-indicator', 'spiraling-indicator', 'factory-indicator', 'training-indicator', 'raid-timer-indicator'] .forEach(id => document.getElementById(id) && (document.getElementById(id).style.display = 'none')); saved.currentPkmn = dummyPkmnId; wildLevel = dummy.level; const hpStars = dummy.bst.hp; wildPkmnHp = (100 + (hpStars * 30) * (1 + dummy.level * 0.2)) * 4; wildPkmnHpMax = wildPkmnHp; document.getElementById('explore-wild-name').innerHTML = (dummy.rename || '木桩') + ` lvl ${dummy.level}`; const sprite = document.getElementById('explore-wild-sprite'); sprite.src = DUMMY_SPRITE_URL; sprite.dataset.dummy = "true"; sprite.onerror = function() { console.warn('木桩图片加载失败'); }; if (pkmn.psyduck?.float) sprite.classList.add('floating-pkmn'); else sprite.classList.remove('floating-pkmn'); document.getElementById('explore-wild-sprite-data').dataset.pkmn = dummyPkmnId; const moves = [dummy.moves.slot1, dummy.moves.slot2, dummy.moves.slot3, dummy.moves.slot4]; const container = document.getElementById('explore-header-moves-wild'); container.innerHTML = ''; for (let i = 0; i < 4; i++) { const moveId = moves[i]; if (!moveId) { const emptyDiv = document.createElement('div'); emptyDiv.className = 'pkmn-movebox'; emptyDiv.style.pointerEvents = 'none'; emptyDiv.style.opacity = '0.3'; container.appendChild(emptyDiv); } else { const moveDiv = document.createElement('div'); moveDiv.className = 'pkmn-movebox'; moveDiv.style.borderColor = returnTypeColor(move[moveId].type); moveDiv.id = `pkmn-movebox-wild-${i+1}`; moveDiv.innerHTML = `
${format(moveId)} `; moveDiv.dataset.move = moveId; container.appendChild(moveDiv); } } updateWildPkmn(); voidAnimation('explore-wild-sprite', 'wildPokemonSpawn 0.5s 1'); return; } const sprite = document.getElementById('explore-wild-sprite'); if (sprite) delete sprite.dataset.dummy; originalSetWildPkmn(); }; const originalExploreCombatPlayer = exploreCombatPlayer; exploreCombatPlayer = function() { originalExploreCombatPlayer(); if (saved.currentArea === dummyAreaId && pkmn[dummyPkmnId] && pkmn[dummyPkmnId].lockHp) { if (wildPkmnHp <= 0) { wildPkmnHp = wildPkmnHpMax; updateWildPkmn(); } } }; const originalExploreCombatWild = exploreCombatWild; exploreCombatWild = function() { originalExploreCombatWild(); if (saved.currentArea === dummyAreaId && pkmn[dummyPkmnId] && pkmn[dummyPkmnId].lockHp) { wildPkmnHp = wildPkmnHpMax; updateWildPkmn(); } }; // 安全包装原函数,忽略跨域错误 if (typeof trimTransparent === 'function') { const originalTrimTransparent = trimTransparent; trimTransparent = function(img) { try { return originalTrimTransparent(img); } catch (e) { if (e.name === 'SecurityError' && e.message.includes('cross-origin')) { console.warn('[DummyCustom] 忽略跨域裁剪错误'); return { width: img.naturalWidth, height: img.naturalHeight }; } throw e; } }; } })();