// ==UserScript==
// @name HHCLUB 魔力抽奖助手-统计版
// @namespace http://tampermonkey.net/
// @version 0.4
// @description 自动抽奖工具,支持完整统计和动效优化
// @author Assistant
// @match https://hhanclub.top/lucky.php*
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-idle
// @license MIT
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// 检查抽奖页面
if (!document.querySelector('#spain1') || !document.querySelector('#lotteryButton')) return;
// 全局变量
let isAutoDrawing = false;
let sessionResults = [];
let sessionDrawCount = 0; // 总尝试次数
let sessionSuccessCount = 0; // 成功次数
const COST_PER_DRAW = 2000;
// 本次统计数据
let sessionStats = { magic: 0, upload: 0, signCard: 0, invite: 0, rainbowId: 0, vip: 0 };
// 数据存储相关
const getCumulativeStats = () => ({
totalDraws: GM_getValue('totalDraws', 0),
totalSuccess: GM_getValue('totalSuccess', 0),
totalCost: GM_getValue('totalCost', 0),
totalMagic: GM_getValue('totalMagic', 0),
totalUpload: GM_getValue('totalUpload', 0),
totalSignCard: GM_getValue('totalSignCard', 0),
totalInvite: GM_getValue('totalInvite', 0),
totalRainbowId: GM_getValue('totalRainbowId', 0),
totalVip: GM_getValue('totalVip', 0),
prizeStats: JSON.parse(GM_getValue('prizeStats', '{}'))
});
const saveCumulativeStats = (stats) => {
Object.entries(stats).forEach(([key, value]) => {
GM_setValue(key, typeof value === 'object' ? JSON.stringify(value) : value);
});
};
// 解析奖品信息
const parsePrize = (prizeName) => {
const patterns = {
magic: /魔力\s*(\d+)/,
upload: /上传量\s*(\d+)\s*GB/i,
signCard: /补签卡\s*(\d+)/,
invite: /邀请\s*(\d+)/,
rainbowId: /彩虹\s*ID.*?(\d+)\s*Day/i,
vip: /VIP.*?(\d+)\s*Day/i
};
const result = {};
Object.entries(patterns).forEach(([key, pattern]) => {
const match = prizeName.match(pattern);
result[key] = match ? parseInt(match[1]) : 0;
});
return result;
};
// 创建悬浮面板
function createFloatingPanel() {
const panel = document.createElement('div');
panel.id = 'lottery-helper-panel';
panel.innerHTML = `
🎰 魔力抽奖助手
📊 本次统计
状态:待机中
抽取:0/0
消耗:0
魔力:+0
上传量:+0 GB
补签卡:+0
邀请:+0
彩虹ID:+0天
VIP:+0天
`;
document.body.appendChild(panel);
addButtonEffects();
}
// 添加按钮特效
const addButtonEffects = () => {
['auto-draw', 'stop-draw', 'show-stats'].forEach(id => {
const btn = document.getElementById(id);
if (!btn) return;
btn.addEventListener('mouseenter', function() {
if (!this.disabled) {
this.style.transform = 'translateY(-3px) scale(1.02)';
this.style.filter = 'brightness(1.1)';
}
});
btn.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0) scale(1)';
this.style.filter = 'brightness(1)';
});
});
};
// 更新状态和统计
const updateStatus = (status) => {
const element = document.getElementById('current-status');
if (element) {
element.textContent = status;
element.style.color = status.includes('错误') ? '#FF6B6B' : '#4ECDC4';
}
};
// 🔥 修正消耗计算逻辑:只按成功次数计算消耗
const updateSessionStats = () => {
const updates = {
'session-success': sessionSuccessCount,
'session-total': sessionDrawCount,
'session-cost': (sessionSuccessCount * COST_PER_DRAW).toLocaleString(), // 👈 修正:按成功次数计算
'session-magic': '+' + sessionStats.magic.toLocaleString(),
'session-upload': '+' + sessionStats.upload + ' GB',
'session-signcard': '+' + sessionStats.signCard,
'session-invite': '+' + sessionStats.invite,
'session-rainbow': '+' + sessionStats.rainbowId + '天',
'session-vip': '+' + sessionStats.vip + '天'
};
Object.entries(updates).forEach(([id, value]) => {
const element = document.getElementById(id);
if (element) {
element.textContent = value;
if (id.startsWith('session-') && id !== 'session-success' && id !== 'session-total' && id !== 'session-cost') {
element.style.color = value === '+0' || value === '+0 GB' || value === '+0天' ? '#FFE082' : '#4ECDC4';
}
}
});
};
// 增强进度条效果
const updateProgress = (current, isInfinite = false) => {
const progressSection = document.getElementById('progress-section');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
if (!progressSection || !progressBar || !progressText) return;
if (isInfinite) {
progressSection.style.display = 'block';
progressBar.style.width = '100%';
progressBar.style.background = 'linear-gradient(90deg, #FF6B6B, #FF8E53)';
progressBar.style.animation = 'progress-pulse 1.5s ease-in-out infinite';
progressText.textContent = `连续抽奖中... 已完成 ${current} 次`;
} else {
progressSection.style.display = 'none';
progressBar.style.animation = 'none';
}
};
// 等待抽奖状态
const waitForNotRunning = (timeout = 10000) => new Promise((resolve) => {
const startTime = Date.now();
const checkInterval = setInterval(() => {
if (!window.running || Date.now() - startTime > timeout) {
clearInterval(checkInterval);
if (window.running) window.running = false;
resolve();
}
}, 100);
});
// 执行单次抽奖
const performSingleDraw = async () => {
await waitForNotRunning(8000);
if (window.running) throw new Error('抽奖状态异常');
window.running = true;
console.log(`执行第${sessionDrawCount + 1}次抽奖...`);
try {
const response = await fetch('/plugin/lucky-draw', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' },
body: ''
});
window.running = false;
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const responseData = await response.json();
if (responseData.ret !== 0) throw new Error(responseData.msg || '抽奖失败');
const result = {
prize: responseData.data['prize_text'],
angle: responseData.data.angle,
timestamp: new Date().toLocaleString(),
rawData: responseData.data
};
sessionResults.push(result);
sessionDrawCount++;
sessionSuccessCount++; // 只有成功时才增加成功计数
const parsed = parsePrize(result.prize);
Object.keys(sessionStats).forEach(key => sessionStats[key] += parsed[key] || 0);
updateSessionStats();
console.log(`第${sessionDrawCount}次抽奖成功:`, result.prize);
return result;
} catch (error) {
window.running = false;
sessionDrawCount++; // 失败也计入总尝试次数
updateSessionStats(); // 🔥 关键修正:失败时也更新统计,但成功次数不变,所以消耗不变
throw error;
}
};
// 获取称号
const getTitleByNetGain = (netGain, hasVip) => {
if (hasVip) return '万里挑一的好运!';
if (netGain >= 100000) return '全服最好运!';
if (netGain >= -5000) return '运气不错!';
if (netGain >= -10000) return '菜鸡!';
if (netGain >= -30000) return '手气真差!';
if (netGain >= -70000) return '大冤种!';
if (netGain >= -100000) return '倒霉鬼!';
return '憨的一逼!';
};
// 自动抽奖主函数
const startAutoDrawing = async () => {
if (isAutoDrawing) return alert('抽奖正在进行中...');
isAutoDrawing = true;
sessionResults = [];
sessionDrawCount = sessionSuccessCount = 0;
sessionStats = { magic: 0, upload: 0, signCard: 0, invite: 0, rainbowId: 0, vip: 0 };
updateButtonsState(true);
updateStatus('自动抽奖中...');
updateSessionStats();
updateProgress(0, true);
let consecutiveFailures = 0;
const maxConsecutiveFailures = 5;
try {
while (isAutoDrawing) {
updateStatus(`抽奖中... (已成功 ${sessionSuccessCount} 次)`);
updateProgress(sessionSuccessCount, true);
try {
await performSingleDraw();
consecutiveFailures = 0;
await new Promise(resolve => setTimeout(resolve, 1500));
} catch (error) {
consecutiveFailures++;
console.warn(`抽奖失败 (连续${consecutiveFailures}次):`, error);
if (consecutiveFailures >= maxConsecutiveFailures) {
console.error('连续失败次数过多,暂停10秒');
updateStatus('连续失败,暂停中...');
await new Promise(resolve => setTimeout(resolve, 10000));
consecutiveFailures = 0;
} else {
await new Promise(resolve => setTimeout(resolve, 3000 * consecutiveFailures));
}
}
}
} catch (error) {
console.error('自动抽奖异常:', error);
} finally {
isAutoDrawing = false;
updateButtonsState(false);
updateProgress(sessionSuccessCount, true);
updateStatus(`已停止 - 成功${sessionSuccessCount}次`);
if (sessionSuccessCount > 0) {
updateCumulativeStats(sessionResults);
setTimeout(showSessionResults, 1000);
}
}
};
// 更新累积统计
const updateCumulativeStats = (results) => {
const stats = getCumulativeStats();
results.forEach(result => {
stats.totalDraws++;
stats.totalSuccess++;
stats.totalCost += COST_PER_DRAW; // 累积统计按成功次数计算消耗
const prizeName = result.prize;
stats.prizeStats[prizeName] = (stats.prizeStats[prizeName] || 0) + 1;
const parsed = parsePrize(prizeName);
stats.totalMagic += parsed.magic;
stats.totalUpload += parsed.upload;
stats.totalSignCard += parsed.signCard;
stats.totalInvite += parsed.invite;
stats.totalRainbowId += parsed.rainbowId;
stats.totalVip += parsed.vip;
});
saveCumulativeStats(stats);
};
// 显示本次结果
const showSessionResults = () => {
if (!sessionResults.length) return;
const sessionPrizeStats = {};
sessionResults.forEach(result => {
sessionPrizeStats[result.prize] = (sessionPrizeStats[result.prize] || 0) + 1;
});
// 🔥 修正净收益计算:按成功次数计算消耗
const netGain = sessionStats.magic - (sessionSuccessCount * COST_PER_DRAW);
let resultHTML = `
🎉 本次抽奖结果
本次统计
尝试次数: ${sessionDrawCount} 次
成功次数: ${sessionSuccessCount} 次
成功率: ${sessionDrawCount > 0 ? ((sessionSuccessCount/sessionDrawCount)*100).toFixed(1) : 0}%
消耗憨豆: ${(sessionSuccessCount * COST_PER_DRAW).toLocaleString()}
获得魔力: ${sessionStats.magic.toLocaleString()}
上传量: +${sessionStats.upload} GB
补签卡: +${sessionStats.signCard}
邀请: +${sessionStats.invite}
彩虹ID: +${sessionStats.rainbowId}天
VIP: +${sessionStats.vip}天
净收益: ${netGain >= 0 ? '+' : ''}${netGain.toLocaleString()}
🏆 奖品详情
`;
Object.entries(sessionPrizeStats).sort((a, b) => b[1] - a[1]).forEach(([prize, count]) => {
const percentage = ((count / sessionResults.length) * 100).toFixed(1);
resultHTML += `
${prize}
${count} 次 (${percentage}%)
`;
});
resultHTML += `
`;
createModal('本次抽奖结果', resultHTML);
};
// 显示累积统计 - 增大称号文字
const showCumulativeStats = () => {
const stats = getCumulativeStats();
if (!stats.totalDraws) return alert('暂无累积统计数据');
const netTotalGain = stats.totalMagic - stats.totalCost;
const hasVip = stats.totalVip > 0;
const titleText = getTitleByNetGain(netTotalGain, hasVip);
let statsHTML = `
${titleText}
📊 累积统计数据
总体数据
总抽奖: ${stats.totalDraws.toLocaleString()} 次
成功率: ${((stats.totalSuccess / stats.totalDraws) * 100).toFixed(1)}%
总消耗: ${stats.totalCost.toLocaleString()}
总魔力: ${stats.totalMagic.toLocaleString()}
上传量: ${stats.totalUpload} GB
补签卡: ${stats.totalSignCard}
邀请: ${stats.totalInvite}
彩虹ID: ${stats.totalRainbowId}天
VIP: ${stats.totalVip}天
累积净收益: ${netTotalGain >= 0 ? '+' : ''}${netTotalGain.toLocaleString()}
🎁 奖品明细
`;
Object.entries(stats.prizeStats).sort((a, b) => b[1] - a[1]).forEach(([prize, count]) => {
const percentage = ((count / stats.totalSuccess) * 100).toFixed(1);
statsHTML += `
${prize}
${count} 次 (${percentage}%)
`;
});
statsHTML += `
`;
createModal('累积统计', statsHTML);
};
// 创建模态框
const createModal = (title, content) => {
document.getElementById('stats-modal')?.remove();
const modal = document.createElement('div');
modal.id = 'stats-modal';
modal.innerHTML = `
`;
document.body.appendChild(modal);
};
// 清空统计
window.clearCumulativeStats = function() {
if (!confirm('确定要清空所有累积统计数据吗?此操作不可恢复!')) return;
['totalDraws', 'totalSuccess', 'totalCost', 'totalMagic', 'totalUpload',
'totalSignCard', 'totalInvite', 'totalRainbowId', 'totalVip'].forEach(key => GM_setValue(key, 0));
GM_setValue('prizeStats', '{}');
alert('统计数据已清空');
document.getElementById('stats-modal')?.remove();
};
// 停止抽奖
const stopDrawing = () => {
isAutoDrawing = false;
updateStatus('正在停止...');
console.log('用户手动停止抽奖');
};
// 更新按钮状态
const updateButtonsState = (drawing) => {
const autoDrawBtn = document.getElementById('auto-draw');
const stopDrawBtn = document.getElementById('stop-draw');
const progressSection = document.getElementById('progress-section');
if (autoDrawBtn) {
autoDrawBtn.style.display = drawing ? 'none' : 'block';
autoDrawBtn.disabled = drawing;
}
if (stopDrawBtn) stopDrawBtn.style.display = drawing ? 'block' : 'none';
if (progressSection) progressSection.style.display = drawing ? 'block' : 'none';
};
// 初始化
const init = () => {
setTimeout(() => {
console.log('魔力抽奖助手正在初始化...');
createFloatingPanel();
// 绑定事件
document.getElementById('auto-draw')?.addEventListener('click', startAutoDrawing);
document.getElementById('stop-draw')?.addEventListener('click', stopDrawing);
document.getElementById('show-stats')?.addEventListener('click', showCumulativeStats);
// 防止意外刷新
window.addEventListener('beforeunload', (e) => {
if (isAutoDrawing) {
e.preventDefault();
e.returnValue = '抽奖正在进行中,确定要离开吗?';
return e.returnValue;
}
});
updateStatus('就绪');
updateSessionStats();
console.log('魔力抽奖助手已启动');
const stats = getCumulativeStats();
if (stats.totalDraws > 0) {
console.log(`累积统计: ${stats.totalDraws}次抽奖, 净收益: ${stats.totalMagic - stats.totalCost}`);
}
}, 1500);
};
// 启动
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();