// ==UserScript==
// @name 放生鱼鱼小助手
// @namespace http://tampermonkey.net/
// @version 2.0
// @description 基于页面源码数据的概率统计与收益分析,提供可视化的掉落概率与倍率展示。
// @author kiwi4814
// @license MIT
// @match https://si-qi.xyz/free_fishes.php*
// @grant none
// @run-at document-end
// @downloadURL https://update.greasyfork.icu/scripts/556738/%E6%94%BE%E7%94%9F%E9%B1%BC%E9%B1%BC%E5%B0%8F%E5%8A%A9%E6%89%8B.user.js
// @updateURL https://update.greasyfork.icu/scripts/556738/%E6%94%BE%E7%94%9F%E9%B1%BC%E9%B1%BC%E5%B0%8F%E5%8A%A9%E6%89%8B.meta.js
// ==/UserScript==
(function () {
'use strict';
/**
* 配置常量
*/
const CONFIG = {
MULTIPLIERS: {
'common': 1,
'uncommon': 1,
'rare': 1,
'epic': 2,
'legendary': 4
},
LABELS: {
'mowan': '⚗️ 魔丸',
'corn': '🌽 玉米',
'carrot': '🥕 胡萝卜',
'worm': '🪱 蚯蚓',
'popularity': '🍽️ 受欢迎值',
'tomato': '🍅 西红柿',
'mushroom': '🍄 蘑菇',
'eggplant': '🍆 茄子',
'none': '无收益'
},
PRIORITY_KEYS: ['mowan', 'popularity'] // 优先展示的物品
};
/**
* 核心逻辑类
*/
class FishAnalytics {
constructor() {
this.data = this.fetchGameData();
if (this.data) {
this.initUI();
}
}
/**
* 从页面源码中提取 FREE_FISH_DATA
*/
fetchGameData() {
try {
const regex = /const\s+FREE_FISH_DATA\s*=\s*(\{.*?\});/s;
const match = document.documentElement.innerHTML.match(regex);
if (match && match[1]) {
return JSON.parse(match[1]);
}
} catch (error) {
console.error('[数据分析面板] 数据解析异常:', error);
}
console.error('[数据分析面板] 未检测到源数据');
return null;
}
/**
* 解析文本中的数值 (例如 "受欢迎 +20" -> "+20")
*/
extractValue(label, key) {
if (!label) return '';
const plusMatch = label.match(/\+(\d+)/);
if (plusMatch) return `+${plusMatch[1]}`;
const quantityMatch = label.match(/(\d+)\s*个/);
if (quantityMatch) return `x${quantityMatch[1]}`;
if (key !== 'popularity' && key !== 'none') return 'x1';
return '';
}
/**
* 构建概率概览表格 HTML
*/
renderOverviewTable() {
const rarities = this.data.rarity_order || ['common', 'uncommon', 'rare', 'epic', 'legendary'];
let rows = rarities.map(key => {
const rewards = this.data.release_rewards[key] || [];
const noneItem = rewards.find(r => r.key === 'none');
// 假设总权重为1000,计算百分比
const failRate = noneItem ? (noneItem.weight / 10) : 0;
const successRate = (100 - failRate).toFixed(1);
const multiplier = CONFIG.MULTIPLIERS[key];
const meta = this.data.rarity_map[key];
// 动态计算颜色,与原站稀有度颜色保持一致或使用通用警告色
const rateColor = failRate > 50 ? '#d9534f' : '#2c9b61'; // Bootstrap danger/success colors matches theme
return `
${this.renderOverviewTable()}
${this.renderDetailTable()}
* 数据来源于游戏源码实时计算,仅供参考
`;
// 插入到页面合适位置 (在 freeFishApp 之前或之后)
const app = document.getElementById('freeFishApp');
if (app) {
app.parentNode.insertBefore(container, app);
} else {
// 兜底插入
const main = document.querySelector('.mainouter');
if (main) main.appendChild(container);
}
// 绑定折叠事件
this.bindEvents(container);
}
bindEvents(container) {
const header = container.querySelector('#analytics-toggle');
const body = container.querySelector('#analytics-body');
const icon = container.querySelector('.toggle-icon');
// 读取本地存储的状态
const isExpanded = localStorage.getItem('siqi_analytics_expanded') === 'true';
const updateState = (expanded) => {
body.style.display = expanded ? 'block' : 'none';
icon.style.transform = expanded ? 'rotate(180deg)' : 'rotate(0deg)';
};
// 初始化状态
updateState(isExpanded);
header.addEventListener('click', () => {
const currentDisplay = body.style.display;
const newState = currentDisplay === 'none';
updateState(newState);
localStorage.setItem('siqi_analytics_expanded', newState);
});
}
}
// 启动脚本
new FishAnalytics();
})();