// ==UserScript==
// @name 逆战抢领助手
// @namespace https://nz.qq.com/
// @version 1.4
// @description 逆战道具定时抢领 + 挚友力整点抽奖
// @author 逆战-牢鹊
// @match https://nz.qq.com/cp/a20251120pvphf/*
// @grant GM_log
// @grant GM_addStyle
// @run-at document-end
// @icon https://nz.qq.com/favicon.ico
// @license MIT
// @unwrap
// ==/UserScript==
(() => {
'use strict';
GM_addStyle(`
#speed-helper-box {
position: fixed;top: 50px;right: 20px;z-index: 99999999;
width: 320px;background: #fff;border: 1px solid #e6394633;border-radius: 20px;
box-shadow: 0 12px 36px rgba(0,0,0,0.15);font-family: '微软雅黑';
}
#speed-helper-header {
background: linear-gradient(90deg, #e63946, #ff6b6b);color: #fff;
padding: 16px 20px;border-top-left-radius: 20px;border-top-right-radius: 20px;
font-size: 16px;font-weight: bold;
}
#speed-helper-body {
padding: 20px;
}
.module-divider {
height: 1px;background: #e6394633;margin: 15px 0;
}
.module-title {
font-size: 14px;font-weight: 600;color: #e63946;margin: 10px 0 5px 0;
}
.time-display {
font-family: monospace;padding: 12px;margin: 10px 0;
background: #e639460d;border: 1px solid #e6394633;border-radius: 10px;
font-size: 15px;color: #e63946;text-align: center;
}
.input-label {
display: block;margin: 8px 0 4px 0;font-size: 14px;color: #333;
}
.speed-helper-input {
width: 100%;padding: 10px 12px;margin: 4px 0 8px 0;
border: 1px solid #e6394633;border-radius: 8px;box-sizing: border-box;
font-size: 14px;
}
.speed-helper-input::placeholder {
color: #999;
}
.prop-name-text {
width: 100%;padding: 10px 12px;margin: 4px 0 8px 0;
border: 1px solid #e6394633;border-radius: 8px;box-sizing: border-box;
font-size: 14px;background: #f9f9f9;color: #333;
}
.countdown {
text-align: center;font-size: 22px;font-weight: bold;
color: #e63946;margin: 15px 0;padding: 10px;
border: 1px solid #e6394633;border-radius: 10px;
}
.lottery-countdown {
text-align: center;font-size: 18px;font-weight: bold;
color: #457b9d;margin: 10px 0;padding: 10px;
border: 1px solid #457b9d33;border-radius: 10px;
}
.speed-helper-actions {
display: flex;gap: 10px;margin-top: 15px;
}
.speed-helper-btn {
flex: 1;padding: 12px;border: none;border-radius: 10px;
cursor: pointer;font-size: 15px;font-weight: 600;
transition: all 0.3s;
}
.btn-start {background: #e63946;color: white;}
.btn-start:hover {background: #d62828;}
.btn-stop {background: #457b9d;color: white;}
.btn-stop:hover {background: #1d3557;}
.btn-lottery-start {background: #ffb703;color: white;}
.btn-lottery-start:hover {background: #fb8500;}
.btn-lottery-stop {background: #219ebc;color: white;}
.btn-lottery-stop:hover {background: #023047;}
.btn-get-time {
width: 100%;background: #f8f9fa;color: #e63946;
border: 1px solid #e6394633;margin: 5px 0 10px 0;
}
.speed-helper-toast {
position: fixed;bottom: 30px;left: 50%;transform: translateX(-50%);
background: rgba(0,0,0,0.8);color: white;padding: 10px 20px;
border-radius: 8px;z-index: 99999999;font-size: 14px;
animation: slideUp 0.3s ease-out;
}
@keyframes slideUp {
from {transform: translate(-50%, 20px);opacity: 0;}
to {transform: translate(-50%, 0);opacity: 1;}
}
`);
class SpeedHelper {
constructor() {
this.isRunning = false;
this.countdownTimer = null;
this.convertTimer = null;
this.convertFunction = () => part1_2_limitConvert(1);
this.execTimes = 10;
this.propName = '10000NZ购物券(3天)';
this.isLotteryRunning = false;
this.lotteryCountdownTimer = null;
this.lotteryExecTimer = null;
this.lotteryExecTimes = 10;
this.lotteryFunction = () => part4_zylChouTen();
this.lotteryName = '挚友力10连抽';
}
init() {
const box = document.createElement('div');
box.id = 'speed-helper-box';
box.innerHTML = `
🎁 道具定时抢领
当前时间:--:--:--.---
${this.propName}
等待开始...
🎡 挚友力整点抽奖(每小时一次)
等待开启自动抽奖...
`;
document.body.appendChild(box);
this.bindEvents();
this.updateRealTime();
}
bindEvents() {
document.getElementById('get-time').addEventListener('click', () => {
const now = new Date();
const timeStr = this.formatTime(now);
document.getElementById('target-time').value = timeStr;
this.toast(`已导入当前时间:${timeStr}`);
});
document.getElementById('start').addEventListener('click', () => this.start());
document.getElementById('stop').addEventListener('click', () => this.stop());
document.getElementById('lottery-start').addEventListener('click', () => this.startLottery());
document.getElementById('lottery-stop').addEventListener('click', () => this.stopLottery());
}
updateRealTime() {
setInterval(() => {
const timeStr = this.formatTime(new Date());
document.getElementById('real-time').textContent = `当前时间:${timeStr}`;
if (this.isLotteryRunning) {
this.updateLotteryCountdown();
}
}, 10);
}
formatTime(date) {
return [
String(date.getHours()).padStart(2, '0'),
String(date.getMinutes()).padStart(2, '0'),
String(date.getSeconds()).padStart(2, '0')
].join(':') + `.${String(date.getMilliseconds()).padStart(3, '0')}`;
}
parseTargetTime(timeStr) {
try {
const [hms, ms] = timeStr.split('.');
const [h, m, s] = hms.split(':').map(Number);
const now = new Date();
const target = new Date(now.getFullYear(), now.getMonth(), now.getDate(), h, m, s, ms || 0);
return target.getTime();
} catch (e) {
return null;
}
}
start() {
if (this.isRunning) return;
const targetTimeStr = document.getElementById('target-time').value.trim();
const execTimes = parseInt(document.getElementById('grab-exec-times').value.trim()) || this.execTimes;
if (!targetTimeStr) {
this.toast('请填写目标时间!');
return;
}
if (isNaN(execTimes) || execTimes < 1 || execTimes > 10) {
this.toast('抢领次数请填写1-10之间的数字!');
return;
}
const targetTime = this.parseTargetTime(targetTimeStr);
if (!targetTime) {
this.toast('时间格式错误!请按 HH:MM:SS.ms 填写');
return;
}
const nowTime = Date.now();
if (targetTime <= nowTime) {
this.toast('目标时间不能小于当前时间,请重新输入!');
return;
}
this.isRunning = true;
document.getElementById('start').disabled = true;
document.getElementById('stop').disabled = false;
this.countdownTimer = setInterval(() => {
const now = Date.now();
const remaining = targetTime - now;
if (remaining <= 0) {
clearInterval(this.countdownTimer);
document.getElementById('countdown').textContent = `开始抢领【${this.propName}】!`;
this.runConvert(execTimes);
return;
}
const sec = Math.floor(remaining / 1000);
const ms = remaining % 1000;
document.getElementById('countdown').textContent = `剩余:${sec}.${ms.toString().padStart(3, '0')} 秒`;
}, 10);
this.toast(`已启动抢领【${this.propName}】,等待目标时间...`);
}
runConvert(execTimes) {
let current = 0;
const interval = Math.max(100, Math.floor(1000 / execTimes));
this.convertTimer = setInterval(() => {
if (current >= execTimes) {
clearInterval(this.convertTimer);
document.getElementById('countdown').textContent = `【${this.propName}】抢领完成!`;
this.toast(`【${this.propName}】抢领完成!`);
this.stop();
return;
}
try {
this.convertFunction();
current++;
document.getElementById('countdown').textContent = `抢领【${this.propName}】中...(${current}/${execTimes})`;
GM_log(`第${current}次抢领【${this.propName}】成功`);
const originalFetch = window.fetch;
window.fetch = function(url, options) {
return originalFetch.apply(this, arguments).then(res => {
if (url.includes('comm.ams.game.qq.com/ams/ame/amsvr')) {
res.clone().json().then(data => {
if (data.iRet === '0') {
this.toast(`🎉 【${this.propName}】抢领成功!`);
this.stop();
} else if (current === execTimes) {
this.toast(`❌ 【${this.propName}】抢领失败:${data.sMsg || '未知错误'}`);
}
});
}
return res;
});
}.bind(this);
} catch (e) {
clearInterval(this.convertTimer);
document.getElementById('countdown').textContent = `【${this.propName}】抢领失败:${e.message}`;
this.toast(`【${this.propName}】抢领失败:${e.message}`);
this.stop();
}
}, interval);
}
stop() {
this.isRunning = false;
clearInterval(this.countdownTimer);
clearInterval(this.convertTimer);
const today = new Date();
const dateStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
document.getElementById('countdown').textContent = `今日日期:${dateStr}`;
document.getElementById('start').disabled = false;
document.getElementById('stop').disabled = true;
}
getNextHourTime() {
const now = new Date();
const nextHour = new Date(now);
nextHour.setHours(nextHour.getHours() + 1);
nextHour.setMinutes(0);
nextHour.setSeconds(0);
nextHour.setMilliseconds(0);
return nextHour.getTime();
}
updateLotteryCountdown() {
const nextHourTime = this.getNextHourTime();
const now = Date.now();
const remaining = nextHourTime - now;
if (remaining <= 0) return;
const hours = Math.floor(remaining / 3600000);
const minutes = Math.floor((remaining % 3600000) / 60000);
const seconds = Math.floor((remaining % 60000) / 1000);
const ms = remaining % 1000;
document.getElementById('lottery-countdown').textContent =
`距离下次抽奖:${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${ms.toString().padStart(3, '0')}`;
}
startLottery() {
if (this.isLotteryRunning) return;
const lotteryExecTimes = parseInt(document.getElementById('lottery-exec-times').value.trim()) || this.lotteryExecTimes;
if (isNaN(lotteryExecTimes) || lotteryExecTimes < 1 || lotteryExecTimes > 10) {
this.toast('抽奖次数请填写1-10之间的数字!');
return;
}
this.lotteryExecTimes = lotteryExecTimes;
this.isLotteryRunning = true;
document.getElementById('lottery-start').disabled = true;
document.getElementById('lottery-stop').disabled = false;
this.updateLotteryCountdown();
this.lotteryCountdownTimer = setInterval(() => {
const now = Date.now();
const nextHourTime = this.getNextHourTime();
if (now >= nextHourTime - 10 && now <= nextHourTime + 1000) {
clearInterval(this.lotteryCountdownTimer);
document.getElementById('lottery-countdown').textContent = `开始${this.lotteryName}...`;
this.runLottery();
}
}, 10);
this.toast(`已开启挚友力整点抽奖!每小时执行${this.lotteryExecTimes}次${this.lotteryName}`);
}
runLottery() {
let current = 0;
const interval = Math.max(100, Math.floor(1000 / this.lotteryExecTimes));
this.lotteryExecTimer = setInterval(() => {
if (current >= this.lotteryExecTimes) {
clearInterval(this.lotteryExecTimer);
document.getElementById('lottery-countdown').textContent = `${this.lotteryName}执行完成!`;
this.toast(`✅ ${this.lotteryName}已执行${this.lotteryExecTimes}次`);
setTimeout(() => {
this.startLottery();
}, 1000);
return;
}
try {
this.lotteryFunction();
current++;
document.getElementById('lottery-countdown').textContent = `${this.lotteryName}中...(${current}/${this.lotteryExecTimes})`;
GM_log(`第${current}次${this.lotteryName}执行成功`);
const originalFetch = window.fetch;
window.fetch = function(url, options) {
return originalFetch.apply(this, arguments).then(res => {
if (url.includes('chouTen') || url.includes('lottery') || url.includes('zylChouTen')) {
res.clone().json().then(data => {
if (data.iRet === '0' || data.code === 0) {
this.toast(`🎉 ${this.lotteryName}成功!${data.sMsg || '抽奖完成'}`);
} else if (current === this.lotteryExecTimes) {
this.toast(`❌ ${this.lotteryName}失败:${data.sMsg || '未知错误'}`);
}
}).catch(e => GM_log('解析抽奖返回数据失败:', e));
}
return res;
});
}.bind(this);
} catch (e) {
clearInterval(this.lotteryExecTimer);
document.getElementById('lottery-countdown').textContent = `${this.lotteryName}执行失败:${e.message}`;
this.toast(`❌ ${this.lotteryName}执行失败:${e.message}`);
setTimeout(() => {
this.startLottery();
}, 60000);
}
}, interval);
}
stopLottery() {
this.isLotteryRunning = false;
clearInterval(this.lotteryCountdownTimer);
clearInterval(this.lotteryExecTimer);
const now = new Date();
const timeStr = this.formatTime(now);
document.getElementById('lottery-countdown').textContent = `自动抽奖已停止 | 当前时间:${timeStr}`;
document.getElementById('lottery-start').disabled = false;
document.getElementById('lottery-stop').disabled = true;
this.toast('已停止挚友力整点自动抽奖');
}
toast(msg) {
const oldToast = document.querySelector('.speed-helper-toast');
if (oldToast) oldToast.remove();
const toast = document.createElement('div');
toast.className = 'speed-helper-toast';
toast.textContent = msg;
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
}
window.addEventListener('load', () => {
setTimeout(() => new SpeedHelper().init(), 1000);
});
})();