// ==UserScript== // @name [Pokechill] 星象系统大改 (修复预览队伍计数) // @namespace http://tampermonkey.net/ // @version 1.1 // @description 星象系统大改,通过修改队伍属性动态调整星象概率。 // @author 人民当家做主 // @match https://play-pokechill.github.io/* // @match https://g1tyx.github.io/play-pokechill/* // @match https://play-pokechill.g8hh.com.cn/* // @icon https://play-pokechill.github.io/img/icons/icon.png // @grant none // ==/UserScript== (function() { 'use strict'; const scriptContent = ` (function() { 'use strict'; console.log('[星象] 注入脚本执行 (修复预览队伍计数)'); // ---------- 配置 ---------- const ATTRIBUTE_TO_STAR = { 'fire': 'sol', 'fighting': 'sol', 'steel': 'sol', 'water': 'luna', 'ice': 'luna', 'fairy': 'luna', 'ghost': 'pluto', 'dark': 'pluto', 'poison': 'pluto', 'grass': 'ceres', 'ground': 'ceres', 'rock': 'ceres', 'electric': 'terra', 'flying': 'terra', 'bug': 'terra', 'psychic': 'eris', 'dragon': 'eris', 'normal': 'eris' }; const STAR_LIST = ['sol', 'luna', 'pluto', 'ceres', 'terra', 'eris']; const LUCKY_MULTIPLIER = 2; const BASE_RATE = 1 / 4000; const STAR_TO_ATTRIBUTES = {}; for (const [attr, star] of Object.entries(ATTRIBUTE_TO_STAR)) { if (!STAR_TO_ATTRIBUTES[star]) STAR_TO_ATTRIBUTES[star] = []; STAR_TO_ATTRIBUTES[star].push(attr); } // 备用格式化函数 function safeFormat(str) { if (typeof format === 'function') { return format(str); } return str.charAt(0).toUpperCase() + str.slice(1); } // 等待所有游戏对象就绪 function waitForGame() { if (typeof team !== 'undefined' && typeof pkmn !== 'undefined' && typeof saved !== 'undefined' && typeof starsign !== 'undefined') { console.log('[星象] 游戏对象已就绪'); initStarSignSystem(); } else { console.log('[星象] 等待游戏对象...'); setTimeout(waitForGame, 200); } } waitForGame(); // ---------- 核心函数 ---------- function isTeamValid(targetTeam) { if (!targetTeam || typeof targetTeam !== 'object') return false; for (let slot in targetTeam) { if (targetTeam[slot]?.pkmn) return true; } return false; } function getEffectiveTeam() { console.log('[星象] 开始寻找有效队伍...'); if (saved.previewTeams && saved.currentPreviewTeam) { console.log('[星象] saved.previewTeams 存在,当前预览队伍索引:', saved.currentPreviewTeam); const currentPreview = saved.previewTeams[saved.currentPreviewTeam]; if (currentPreview) { console.log('[星象] 当前预览队伍对象:', currentPreview); if (isTeamValid(currentPreview)) { console.log('[星象] 使用当前预览队伍'); return currentPreview; } else { console.log('[星象] 当前预览队伍为空'); } } } if (saved.previewTeams) { for (let key in saved.previewTeams) { const preview = saved.previewTeams[key]; if (isTeamValid(preview)) { console.log('[星象] 使用预览队伍:', key); return preview; } } } for (let i = 1; i <= 6; i++) { const oldKey = 'preview' + i; if (saved[oldKey] && isTeamValid(saved[oldKey])) { console.log('[星象] 使用旧版预览队伍:', oldKey); return saved[oldKey]; } } if (isTeamValid(team)) { console.log('[星象] 使用战斗队伍'); return team; } console.log('[星象] 警告:未找到任何有效队伍'); return null; } // 计算指定队伍中每个星象的属性数量(兼容字符串ID或对象) function calculateStarCountsFromTeam(targetTeam) { const counts = { sol:0, luna:0, pluto:0, ceres:0, terra:0, eris:0 }; if (!targetTeam || typeof targetTeam !== 'object') return counts; for (let slot in targetTeam) { const slotData = targetTeam[slot]; if (!slotData) continue; // 获取宝可梦ID(可能是字符串或对象) let pokemonId = null; if (typeof slotData.pkmn === 'string') { pokemonId = slotData.pkmn; } else if (slotData.pkmn && typeof slotData.pkmn === 'object' && slotData.pkmn.id) { pokemonId = slotData.pkmn.id; } if (!pokemonId) continue; const pkmnData = pkmn[pokemonId]; if (!pkmnData?.type) continue; pkmnData.type.forEach(type => { const star = ATTRIBUTE_TO_STAR[type]; if (star) counts[star]++; }); } return counts; } function calculateBaseWeight(count) { if (count === 0) return 0; return (5/108) * count * count + (7/36) * count; } function calculateStarWeightsFromTeam(targetTeam) { const counts = calculateStarCountsFromTeam(targetTeam); const weights = {}; STAR_LIST.forEach(star => { let weight = calculateBaseWeight(counts[star]); if (star === saved.luckyStarSign) weight *= LUCKY_MULTIPLIER; weights[star] = weight; }); return weights; } function getMillisToNextMidnight() { const now = new Date(); const next = new Date(now); next.setDate(now.getDate() + 1); next.setHours(0, 0, 0, 0); return next - now; } function updateLuckyStar() { saved.luckyStarSign = STAR_LIST[Math.floor(Math.random() * STAR_LIST.length)]; saved.luckyStarLastUpdate = Date.now(); if (typeof saveGame === 'function') saveGame(); console.log('[星象] 幸运星象更新为:', safeFormat(saved.luckyStarSign)); } function checkAndRefreshLuckyStar() { const now = Date.now(); if (!saved.luckyStarLastUpdate) { updateLuckyStar(); return; } const last = new Date(saved.luckyStarLastUpdate); const today = new Date(); if (last.getDate() !== today.getDate() || last.getMonth() !== today.getMonth() || last.getFullYear() !== today.getFullYear()) { updateLuckyStar(); } } function scheduleMidnightUpdate() { const ms = getMillisToNextMidnight(); setTimeout(() => { updateLuckyStar(); scheduleMidnightUpdate(); }, ms); } // ---------- UI ---------- function createStarSignDisplay() { const menuParent = document.getElementById('menu-button-parent'); if (!menuParent) { setTimeout(createStarSignDisplay, 500); return; } if (document.getElementById('star-sign-display')) return; console.log('[星象] 找到主菜单容器,插入悬浮框'); const display = document.createElement('div'); display.id = 'star-sign-display'; display.style.cssText = 'position: absolute; top: 0.5rem; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(10, 15, 30, 0.85); backdrop-filter: blur(4px); border: 1.5px solid #4a7ab0; border-radius: 2rem; padding: 0.2rem 1rem; cursor: pointer; font-size: 0.9rem; color: white; text-shadow: 0 0 8px #7ab0ff, 0 0 12px #2a5a9a; box-shadow: 0 0 20px rgba(74, 122, 176, 0.6); z-index: 1000; transition: all 0.3s ease;'; display.addEventListener('mouseenter', () => { display.style.transform = 'scale(1.05)'; display.style.boxShadow = '0 0 30px rgba(100, 180, 255, 0.9)'; }); display.addEventListener('mouseleave', () => { display.style.transform = 'scale(1)'; display.style.boxShadow = '0 0 20px rgba(74, 122, 176, 0.6)'; }); const luckyStar = saved.luckyStarSign || 'sol'; const hue = starsign[luckyStar]?.hue || 0; const row = document.createElement('div'); row.style.cssText = 'display: flex; align-items: center; gap: 0.3rem; margin-bottom: 0.1rem;'; const nameSpan = document.createElement('span'); nameSpan.id = 'lucky-star-name'; nameSpan.style.fontSize = '0.9rem'; nameSpan.style.fontWeight = 'bold'; nameSpan.textContent = safeFormat(luckyStar); const iconSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); iconSvg.setAttribute('width', '16'); iconSvg.setAttribute('height', '16'); iconSvg.setAttribute('viewBox', '0 0 24 24'); iconSvg.style.color = 'white'; iconSvg.style.filter = 'hue-rotate(' + hue + 'deg)'; const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill', 'currentColor'); path.setAttribute('d', 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z'); iconSvg.appendChild(path); row.appendChild(nameSpan); row.appendChild(iconSvg); const timer = document.createElement('div'); timer.id = 'lucky-star-timer'; timer.style.cssText = 'font-size: 0.8rem; text-align: center; width: 100%; text-shadow: 0 0 5px cyan;'; timer.textContent = '00:00:00'; display.appendChild(row); display.appendChild(timer); menuParent.appendChild(display); display.addEventListener('click', showProbabilityTooltip); } function updateStarSignDisplay() { const nameSpan = document.getElementById('lucky-star-name'); const timerSpan = document.getElementById('lucky-star-timer'); if (!nameSpan || !timerSpan) return; const luckyStar = saved.luckyStarSign || 'sol'; nameSpan.textContent = safeFormat(luckyStar); const svg = document.querySelector('#star-sign-display svg'); if (svg) { const hue = starsign[luckyStar]?.hue || 0; svg.style.filter = 'hue-rotate(' + hue + 'deg)'; } const ms = getMillisToNextMidnight(); const hours = Math.floor(ms / 3600000); const minutes = Math.floor((ms % 3600000) / 60000); const seconds = Math.floor((ms % 60000) / 1000); timerSpan.textContent = hours.toString().padStart(2,'0') + ':' + minutes.toString().padStart(2,'0') + ':' + seconds.toString().padStart(2,'0'); } // ---------- 详细概率显示 ---------- function showProbabilityTooltip() { const effectiveTeam = getEffectiveTeam(); console.log('[星象] showProbabilityTooltip: 有效队伍 =', effectiveTeam); let counts, weights; let noTeamMessage = ''; if (effectiveTeam) { counts = calculateStarCountsFromTeam(effectiveTeam); weights = calculateStarWeightsFromTeam(effectiveTeam); console.log('[星象] counts =', counts); console.log('[星象] weights =', weights); } else { counts = { sol:0, luna:0, pluto:0, ceres:0, terra:0, eris:0 }; weights = { sol:0, luna:0, pluto:0, ceres:0, terra:0, eris:0 }; noTeamMessage = '
当前无有效队伍,所有概率为0
'; } let content = '
星象获取概率详情
'; content += noTeamMessage; content += ''; content += ''; STAR_LIST.forEach(star => { const hue = starsign[star]?.hue || 0; const attrs = STAR_TO_ATTRIBUTES[star] || []; const attrNames = attrs.map(a => safeFormat(a)).join(', '); const count = counts[star] || 0; const baseWeight = calculateBaseWeight(count); const finalWeight = weights[star]; const actualProb = (finalWeight * BASE_RATE * 100).toFixed(3) + '%'; const isLucky = (star === saved.luckyStarSign); const starName = safeFormat(star) + (isLucky ? ' ✦' : ''); content += ''; content += ''; content += ''; content += ''; content += ''; content += ''; content += ''; content += ''; }); content += '
星象包含属性数量基础权重最终权重实际概率
' + starName + '' + attrNames + '' + count + '' + baseWeight.toFixed(3) + '' + finalWeight.toFixed(3) + '' + actualProb + '
'; const tooltipTop = document.getElementById('tooltipTop'); const tooltipTitle = document.getElementById('tooltipTitle'); const tooltipMid = document.getElementById('tooltipMid'); const tooltipBottom = document.getElementById('tooltipBottom'); if (tooltipTop && tooltipTitle && tooltipMid && tooltipBottom) { tooltipTop.style.display = 'none'; tooltipTitle.style.display = 'none'; tooltipMid.innerHTML = content; tooltipBottom.style.display = 'none'; if (typeof openTooltip === 'function') { openTooltip(); } else { alert('无法打开提示框'); } } else { alert('无法显示概率信息:tooltip元素缺失'); } } // ---------- 覆盖 giveStarsign ---------- const originalGiveStarsign = giveStarsign; giveStarsign = function(id, mode) { if (mode === 'check') { if (pkmn[id].starsignList?.length >= 6) return 'complete'; return; } if (!pkmn[id].starsignList) pkmn[id].starsignList = []; const available = STAR_LIST.filter(star => !pkmn[id].starsignList.includes(star)); if (available.length === 0) return; const effectiveTeam = getEffectiveTeam(); if (!effectiveTeam) { const chosen = available[Math.floor(Math.random() * available.length)]; pkmn[id].starsignList.push(chosen); if (typeof updateFamilyStarsign === 'function') updateFamilyStarsign(); console.log('[星象] (无队伍) 为 ' + id + ' 添加星象 ' + chosen); return; } const weights = calculateStarWeightsFromTeam(effectiveTeam); let total = 0; available.forEach(star => total += weights[star] || 0); if (total === 0) { const chosen = available[Math.floor(Math.random() * available.length)]; pkmn[id].starsignList.push(chosen); if (typeof updateFamilyStarsign === 'function') updateFamilyStarsign(); console.log('[星象] (权重为零) 为 ' + id + ' 添加星象 ' + chosen); return; } let rand = Math.random() * total; let chosen = available[0]; for (let star of available) { if (rand < weights[star]) { chosen = star; break; } rand -= weights[star]; } pkmn[id].starsignList.push(chosen); if (typeof updateFamilyStarsign === 'function') updateFamilyStarsign(); console.log('[星象] 为 ' + id + ' 添加星象 ' + chosen); }; function initStarSignSystem() { console.log('[星象] 开始初始化'); if (saved.luckyStarSign === undefined) { updateLuckyStar(); } else { checkAndRefreshLuckyStar(); } createStarSignDisplay(); updateStarSignDisplay(); setInterval(() => { updateStarSignDisplay(); }, 1000); scheduleMidnightUpdate(); const observer = new MutationObserver(() => { if (!document.getElementById('star-sign-display')) { createStarSignDisplay(); } }); observer.observe(document.body, { childList: true, subtree: true }); console.log('[星象] 初始化完成'); } })(); `; const script = document.createElement('script'); script.textContent = scriptContent; document.documentElement.appendChild(script); script.remove(); })();