// ==UserScript== // @name 逆战活动工具箱 // @namespace https://nz.qq.com/ // @version 1.3 // @description 逆战活动自动领取助手 // @author 逆战-牢鹊 // @match https://nz.qq.com/* // @grant GM_log // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @run-at document-end // @icon https://nz.qq.com/favicon.ico // @license MIT // @unwrap // ==/UserScript== (() => { 'use strict'; const ACTIVITY_CONFIGS = [ { id: 'nz_january_login_202512', name: '1.1登录领5000', icon: '🎊', url: 'https://nz.qq.com/cp/a20251205knact/', urlRegex: /a20251205knact/, steps: [ { name: 'daily_reward', func: 'selectDailyRewards', param: null, delay: 0 }, { name: 'update1', func: 'autoClick', param: '.btn_p1lq.sp.isGray30', delay: 1000 }, { name: 'close1', func: 'closePopup', param: 'update1', delay: 1800 }, { name: 'update2', func: 'autoClick', param: '.btn_p1lq.sp.isGray31', delay: 1000 }, { name: 'close2', func: 'closePopup', param: 'update2', delay: 1800 }, { name: 'update3', func: 'autoClick', param: '.btn_p1lq.sp.isGray32', delay: 1000 }, { name: 'close3', func: 'closePopup', param: 'update3', delay: 1800 }, { name: 'update4', func: 'autoClick', param: '.btn_p1lq.sp.isGray33', delay: 1000 }, { name: 'close4', func: 'closePopup', param: 'update4', delay: 1800 }, { name: 'update5', func: 'autoClick', param: '.btn_p1lq.sp.isGray34', delay: 1000 }, { name: 'close5', func: 'closePopup', param: 'update5', delay: 1800 }, { name: 'update6', func: 'autoClick', param: '.btn_p1lq.sp.isGray35', delay: 1000 }, { name: 'close6', func: 'closePopup', param: 'update6', delay: 1800 }, { name: 'game30min', func: 'autoClick', param: '.btn_p6open.sp.isGray36', delay: 1000 }, { name: 'close7', func: 'closePopup', param: 'game30min', delay: 1800 }, { name: 'draw1', func: 'autoClick', param: '.btn_p6open.sp.isGray18', delay: 1000 }, { name: 'close8', func: 'closePopup', param: 'draw1', delay: 1800 }, { name: 'draw2', func: 'autoClick', param: '.btn_p6open.sp.isGray19', delay: 1000 }, { name: 'close9', func: 'closePopup', param: 'draw2', delay: 1800 }, { name: 'draw3', func: 'autoClick', param: '.btn_p6open.sp.isGray20', delay: 1000 }, { name: 'close10', func: 'closePopup', param: 'draw3', delay: 1800 }, { name: 'draw4', func: 'autoClick', param: '.btn_p6open.sp.isGray21', delay: 1000 }, { name: 'close11', func: 'closePopup', param: 'draw4', delay: 1800 }, { name: 'game1round', func: 'autoClick', param: '.btn_p6open.sp.isGray22', delay: 1000 }, { name: 'close12', func: 'closePopup', param: 'game1round', delay: 1800 }, { name: 'hunt1round', func: 'autoClick', param: '.btn_p6open.sp.isGray23', delay: 1000 }, { name: 'close13', func: 'closePopup', param: 'hunt1round', delay: 1800 }, { name: 'energy10min', func: 'autoClick', param: '.sp.isGray1', delay: 1000 }, { name: 'close14', func: 'closePopup', param: 'energy10min', delay: 1800 }, { name: 'energy30min', func: 'autoClick', param: '.sp.isGray2', delay: 1000 }, { name: 'close15', func: 'closePopup', param: 'energy30min', delay: 1800 }, { name: 'energyupdate', func: 'autoClick', param: '.sp.isGray3', delay: 1000 }, { name: 'close16', func: 'closePopup', param: 'energyupdate', delay: 1800 }, { name: 'energyget', func: 'autoClick', param: '.btn_p1lq.sp.isGray4', delay: 1000 }, { name: 'close17', func: 'closePopup', param: 'energyget', delay: 1800 }, { name: 'silvereegg', func: 'autoClick', param: '.sp.isGray5', delay: 1000 }, { name: 'close18', func: 'closePopup', param: 'silvereegg', delay: 1800 }, { name: 'huntsilvereegg', func: 'autoClick', param: '.sp.isGray6', delay: 1000 }, { name: 'close19', func: 'closePopup', param: 'huntsilvereegg', delay: 1800 }, { name: 'goldegg1', func: 'autoClick', param: '.sp.btn_p4btn1.isGray7', delay: 1000 }, { name: 'close20', func: 'closePopup', param: 'goldegg1', delay: 1800 }, { name: 'goldegg2', func: 'autoClick', param: '.sp.btn_p4btn1.isGray8', delay: 1000 }, { name: 'close21', func: 'closePopup', param: 'goldegg2', delay: 1800 }, { name: 'reward1', func: 'autoClick', param: '.sp.btn_p4lq.isGray12', delay: 1000 }, { name: 'close22', func: 'closePopup', param: 'reward1', delay: 1800 }, { name: 'reward2', func: 'autoClick', param: '.sp.btn_p4lq.isGray13', delay: 1000 }, { name: 'close23', func: 'closePopup', param: 'reward2', delay: 1800 }, { name: 'reward3', func: 'autoClick', param: '.sp.btn_p4lq.isGray14', delay: 1000 }, { name: 'close24', func: 'closePopup', param: 'reward3', delay: 1800 }, { name: 'reward4', func: 'autoClick', param: '.sp.btn_p4lq.isGray15', delay: 1000 }, { name: 'close25', func: 'closePopup', param: 'reward4', delay: 1800 }, { name: 'reward5', func: 'autoClick', param: '.sp.btn_p4lq.isGray16', delay: 1000 }, { name: 'close26', func: 'closePopup', param: 'reward5', delay: 1800 }, { name: 'hatchspeed', func: 'autoClick', param: '.btn_p4jsfh.sp.isGray11', delay: 1000 }, { name: 'close27', func: 'closePopup', param: 'hatchspeed', delay: 1800 }, { name: '3daysgame', func: 'autoClick', param: '.sp.isGray9', delay: 1000 }, { name: 'close28', func: 'closePopup', param: '3daysgame', delay: 1800 }, { name: '5daysgame', func: 'autoClick', param: '.sp.isGray10', delay: 1000 }, { name: 'close29', func: 'closePopup', param: '5daysgame', delay: 1800 }, { name: 'coupon', func: 'autoClick', param: '.sp.btn_p5btns.isGray17', delay: 1000 }, { name: 'close30', func: 'closePopup', param: 'coupon', delay: 1800 } ] }, { id: 'nz_gala_202512', name: '感恩福利大放送', icon: '🎁', url: 'https://nz.qq.com/cp/a20251202gegala/', urlRegex: /a20251202gegala/, steps: [ { name: 'draw', func: 'autoClick', param: '#part1_used_1', delay: 3000 }, { name: 'close1', func: 'closePopup', param: 'draw', delay: 1800 }, { name: 'lvupday', func: 'autoClick', param: '#part2_used1_1', delay: 1000 }, { name: 'close2', func: 'closePopup', param: 'lvupday', delay: 1800 }, { name: 'lvupweek', func: 'autoClick', param: '#part2_used1_2', delay: 1000 }, { name: 'close3', func: 'closePopup', param: 'lvupweek', delay: 1800 }, { name: 'lv3', func: 'autoClick', param: '#part2_used2_1', delay: 1000 }, { name: 'close4', func: 'closePopup', param: 'lv3', delay: 1800 }, { name: 'lv6', func: 'autoClick', param: '#part2_used2_2', delay: 1000 }, { name: 'close5', func: 'closePopup', param: 'lv6', delay: 1800 }, { name: 'lv9', func: 'autoClick', param: '#part2_used2_3', delay: 1000 }, { name: 'close6', func: 'closePopup', param: 'lv9', delay: 1800 }, { name: 'lv12', func: 'autoClick', param: '#part2_used2_4', delay: 1000 }, { name: 'close7', func: 'closePopup', param: 'lv12', delay: 1800 }, { name: 'lv15', func: 'autoClick', param: '#part2_used2_5', delay: 1000 }, { name: 'close8', func: 'closePopup', param: 'lv15', delay: 1800 }, { name: 'minesweep1', func: 'autoClick', param: '.btn_cq:contains("立即扫雷")', delay: 1000 }, { name: 'close9', func: 'closePopup', param: 'minesweep1', delay: 1800 }, { name: 'delay1', func: 'delayExecution', param: null, delay: 2000 }, { name: 'minesweep2', func: 'autoClick', param: '.btn_cq:contains("立即扫雷")', delay: 1000 }, { name: 'close10', func: 'closePopup', param: 'minesweep2', delay: 1800 }, { name: 'delay2', func: 'delayExecution', param: null, delay: 2000 }, { name: 'minesweep3', func: 'autoClick', param: '.btn_cq:contains("立即扫雷")', delay: 1000 }, { name: 'close11', func: 'closePopup', param: 'minesweep3', delay: 1800 }, { name: 'p4gr1', func: 'autoClick', param: '.btn_cq.isGray3', delay: 1000 }, { name: 'close12', func: 'closePopup', param: 'p4gr1', delay: 1800 }, { name: 'p4gr2', func: 'autoClick', param: '.btn_cq.isGray4', delay: 1000 }, { name: 'close13', func: 'closePopup', param: 'p4gr2', delay: 1800 }, { name: 'p4gr3', func: 'autoClick', param: '.btn_cq.isGray5', delay: 1000 }, { name: 'close14', func: 'closePopup', param: 'p4gr3', delay: 1800 }, { name: 'p4qf1', func: 'autoClick', param: '.btn_cq.isGray6', delay: 1000 }, { name: 'close15', func: 'closePopup', param: 'p4qf1', delay: 1800 }, { name: 'p4qf2', func: 'autoClick', param: '.btn_cq.isGray7', delay: 1000 }, { name: 'close16', func: 'closePopup', param: 'p4qf2', delay: 1800 }, { name: 'p4qf3', func: 'autoClick', param: '.btn_cq.isGray8', delay: 1000 }, { name: 'close17', func: 'closePopup', param: 'p4qf3', delay: 1800 } ] }, { id: 'nz_celebration_202511', name: '感恩庆典全面开启', icon: '🎉', url: 'https://nz.qq.com/cp/a20251120geqd/?e_code=554044', urlRegex: /a20251120geqd/, steps: [ { name: 'p1game', func: 'autoClick', param: '.p2btn1.isGray1', delay: 1000 }, { name: 'close1', func: 'closePopup', param: 'p1game', delay: 1800 }, { name: 'sharelive', func: 'autoClick', param: '.p2btn2:not(.isGray2)', delay: 1000 }, { name: 'close2', func: 'closePopup', param: 'sharelive', delay: 1800 }, { name: 'p1share', func: 'autoClick', param: '.p2btn2.isGray2', delay: 1000 }, { name: 'close3', func: 'closePopup', param: 'p1share', delay: 1800 }, { name: 'p1watch', func: 'autoClick', param: '.p2btn1.isGray3', delay: 1000 }, { name: 'close4', func: 'closePopup', param: 'p1watch', delay: 1800 }, { name: 'p1login', func: 'autoClick', param: '.p2btn1.isGray4', delay: 1000 }, { name: 'close5', func: 'closePopup', param: 'p1login', delay: 1800 }, { name: 'gamemap1', func: 'autoClick', param: '.p2btn1.isGray5', delay: 1000 }, { name: 'close6', func: 'closePopup', param: 'gamemap1', delay: 1800 }, { name: 'gamemap2', func: 'autoClick', param: '.p2btn1.isGray6', delay: 1000 }, { name: 'close7', func: 'closePopup', param: 'gamemap2', delay: 1800 }, { name: 'gamemap3', func: 'autoClick', param: '.p2btn1.isGray7', delay: 1000 }, { name: 'close8', func: 'closePopup', param: 'gamemap3', delay: 1800 }, { name: 'logindraw', func: 'autoClick', param: '.p3lotbtn1.isGray8', delay: 1000 }, { name: 'close9', func: 'closePopup', param: 'logindraw', delay: 1800 }, { name: 'matchdraw', func: 'autoClick', param: '.p3lotbtn1.isGray9', delay: 1000 }, { name: 'close10', func: 'closePopup', param: 'matchdraw', delay: 1800 }, { name: 'chestcard', func: 'autoClick', param: '.p4btn1.isGray10', delay: 1000 }, { name: 'close11', func: 'closePopup', param: 'chestcard', delay: 1800 }, { name: 'weekdraw', func: 'autoClick', param: '.p4btn1.isGray11', delay: 1000 }, { name: 'close12', func: 'closePopup', param: 'weekdraw', delay: 1800 }, { name: 'check1', func: 'autoClick', param: '.p5btn1.daka1', delay: 1000 }, { name: 'close13', func: 'closePopup', param: 'check1', delay: 1800 }, { name: 'check2', func: 'autoClick', param: '.p5btn1.daka2', delay: 1000 }, { name: 'close14', func: 'closePopup', param: 'check2', delay: 1800 }, { name: 'check3', func: 'autoClick', param: '.p5btn1.daka3', delay: 1000 }, { name: 'close15', func: 'closePopup', param: 'check3', delay: 1800 }, { name: 'check4', func: 'autoClick', param: '.p5btn1.daka4', delay: 1000 }, { name: 'close16', func: 'closePopup', param: 'check4', delay: 1800 }, { name: 'check5', func: 'autoClick', param: '.p5btn1.daka5', delay: 1000 }, { name: 'close17', func: 'closePopup', param: 'check5', delay: 1800 }, { name: 'check6', func: 'autoClick', param: '.p5btn1.daka6', delay: 1000 }, { name: 'close18', func: 'closePopup', param: 'check6', delay: 1800 }, { name: 'check7', func: 'autoClick', param: '.p5btn1.daka7', delay: 1000 }, { name: 'close19', func: 'closePopup', param: 'check7', delay: 1800 }, { name: 'check8', func: 'autoClick', param: '.p5btn1.daka8', delay: 1000 }, { name: 'close20', func: 'closePopup', param: 'check8', delay: 1800 }, { name: 'check9', func: 'autoClick', param: '.p5btn1.daka9', delay: 1000 }, { name: 'close21', func: 'closePopup', param: 'check9', delay: 1800 }, { name: 'check10', func: 'autoClick', param: '.p5btn1.daka10', delay: 1000 }, { name: 'close22', func: 'closePopup', param: 'check10', delay: 1800 }, { name: 'check11', func: 'autoClick', param: '.p5btn1.daka11', delay: 1000 }, { name: 'close23', func: 'closePopup', param: 'check11', delay: 1800 }, { name: 'check12', func: 'autoClick', param: '.p5btn1.daka12', delay: 1000 }, { name: 'close24', func: 'closePopup', param: 'check12', delay: 1800 }, { name: 'artifact', func: 'autoClick', param: '.p5btn2.isGray27', delay: 1000 }, { name: 'close25', func: 'closePopup', param: 'artifact', delay: 1800 }, { name: 'prechecktip', func: 'autoClick', param: '.p5btn2.isGray15', delay: 1000 }, { name: 'close26', func: 'closePopup', param: 'prechecktip', delay: 1800 }, { name: 'precheckdraw', func: 'autoClick', param: '.p5btn3.isGray13', delay: 1000 }, { name: 'close27', func: 'closePopup', param: 'precheckdraw', delay: 1800 }, { name: 'precheck', func: 'autoClick', param: '.p5btn3.isGray14', delay: 1000 }, { name: 'close28', func: 'closePopup', param: 'precheck', delay: 1800 }, { name: 'mainweapon', func: 'autoClick', param: '.p6btn1.isGray16', delay: 1000 }, { name: 'close29', func: 'closePopup', param: 'mainweapon', delay: 1800 }, { name: 'sideweapon', func: 'autoClick', param: '.p6btn1.isGray17', delay: 1000 }, { name: 'close30', func: 'closePopup', param: 'sideweapon', delay: 1800 }, { name: 'meleewapon', func: 'autoClick', param: '.p6btn1.isGray18', delay: 1000 }, { name: 'close31', func: 'closePopup', param: 'meleewapon', delay: 1800 }, { name: 'throwweapon', func: 'autoClick', param: '.p6btn1.isGray19', delay: 1000 }, { name: 'close32', func: 'closePopup', param: 'throwweapon', delay: 1800 }, { name: 'mainsideget', func: 'autoClick', param: '.p6btn1.isGray20', delay: 1000 }, { name: 'close33', func: 'closePopup', param: 'mainsideget', delay: 1800 }, { name: 'knifegrenade', func: 'autoClick', param: '.p6btn1.isGray21', delay: 1000 }, { name: 'close34', func: 'closePopup', param: 'knifegrenade', delay: 1800 }, { name: 'fullunlock', func: 'autoClick', param: '.p6btn1.isGray22', delay: 1000 }, { name: 'close35', func: 'closePopup', param: 'fullunlock', delay: 1800 }, { name: 'card1', func: 'autoClick', param: '.p7btn1.isGray23', delay: 1000 }, { name: 'close36', func: 'closePopup', param: 'card1', delay: 1800 }, { name: 'card2', func: 'autoClick', param: '.p7btn1.isGray24', delay: 1000 }, { name: 'close37', func: 'closePopup', param: 'card2', delay: 1800 } ] }, { id: 'nz_return_202512', name: '12月新老玩家回归', icon: '🎯', url: 'https://nz.qq.com/cp/a20251120pvphf/', urlRegex: /a20251120pvphf/, steps: [ { name: 'loginday1', func: 'autoClick', param: '.btnA.isGray35', delay: 1000 }, { name: 'close1', func: 'closePopup', param: 'loginday1', delay: 1800 }, { name: 'loginday2', func: 'autoClick', param: '.btnA.isGray36', delay: 1000 }, { name: 'close2', func: 'closePopup', param: 'loginday2', delay: 1800 }, { name: 'loginday3', func: 'autoClick', param: '.btnA.isGray37', delay: 1000 }, { name: 'close3', func: 'closePopup', param: 'loginday3', delay: 1800 }, { name: 'loginday4', func: 'autoClick', param: '.btnA.isGray38', delay: 1000 }, { name: 'close4', func: 'closePopup', param: 'loginday4', delay: 1800 }, { name: 'loginday5', func: 'autoClick', param: '.btnB.isGray52', delay: 1000 }, { name: 'close5', func: 'closePopup', param: 'loginday5', delay: 1800 }, { name: 'ticket1', func: 'autoClick', param: '.btnA.isGray106', delay: 1000 }, { name: 'close6', func: 'closePopup', param: 'ticket1', delay: 1800 }, { name: 'ticket2', func: 'autoClick', param: '.btnA:contains("领取两张奖券")', delay: 1000 }, { name: 'close7', func: 'closePopup', param: 'ticket2', delay: 1800 }, { name: 'drawnow', func: 'autoClick', param: '.btnA:contains("立即抽奖")', delay: 1000 }, { name: 'close8', func: 'closePopup', param: 'drawnow', delay: 1800 }, { name: 'inviteveteran', func: 'autoClick', param: '.btnB.isGray26', delay: 1000 }, { name: 'close9', func: 'closePopup', param: 'inviteveteran', delay: 1800 }, { name: 'get1', func: 'autoClick', param: '.btnA.isGray30', delay: 1000 }, { name: 'close10', func: 'closePopup', param: 'get1', delay: 1800 }, { name: 'get2', func: 'autoClick', param: '.btnA.isGray31', delay: 1000 }, { name: 'close11', func: 'closePopup', param: 'get2', delay: 1800 }, { name: 'get3', func: 'autoClick', param: '.btnA.isGray32', delay: 1000 }, { name: 'close12', func: 'closePopup', param: 'get3', delay: 1800 }, { name: 'get4', func: 'autoClick', param: '.btnB.isGray33', delay: 1000 }, { name: 'close13', func: 'closePopup', param: 'get4', delay: 1800 }, { name: 'draw0', func: 'autoClick', param: '.btn_cj1.y.zylChouOne', delay: 1000 }, { name: 'close14', func: 'closePopup', param: 'draw0', delay: 1800 }, { name: 'draw10', func: 'autoClick', param: '.btn_cj2.y.zylChouTen.gray', delay: 1000 }, { name: 'close15', func: 'closePopup', param: 'draw10', delay: 1800 } ] } ]; const STYLE = GM_addStyle(` #nz-toolbox { position: fixed !important; top: 50px !important; left: 20px !important; z-index: 99999999 !important; width: 320px !important; background: #fff !important; border: 1px solid rgba(230, 57, 70, 0.3) !important; border-radius: 20px !important; box-shadow: 0 12px 36px rgba(0, 0, 0, 0.15) !important; font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif !important; overflow: hidden !important; backdrop-filter: none !important; display: block !important; opacity: 1 !important; visibility: visible !important; pointer-events: auto !important; } #nz-toolbox-header { background: linear-gradient(90deg, #e63946 0%, #ff6b6b 100%) !important; color: #fff !important; padding: 20px 24px !important; display: flex !important; justify-content: space-between !important; align-items: center !important; cursor: move !important; user-select: none !important; border-top-left-radius: 20px !important; border-top-right-radius: 20px !important; position: relative !important; overflow: hidden !important; } #nz-toolbox-header::before { content: '' !important; position: absolute !important; top: 0 !important; left: 0 !important; right: 0 !important; height: 3px !important; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.8), transparent) !important; } .nz-toolbox-title { font-size: 18px !important; font-weight: 700 !important; display: flex !important; align-items: center !important; gap: 12px !important; letter-spacing: 0.8px !important; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2) !important; } .nz-toolbox-icon { width: 28px !important; height: 28px !important; object-fit: contain !important; border-radius: 8px !important; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3) !important; } .nz-toolbox-mini { background: rgba(255, 255, 255, 0.2) !important; border: 1px solid rgba(255, 255, 255, 0.3) !important; color: #fff !important; font-size: 20px !important; cursor: pointer !important; width: 36px !important; height: 36px !important; border-radius: 10px !important; display: flex !important; align-items: center !important; justify-content: center !important; transition: all 0.3s !important; } .nz-toolbox-mini:hover { background: rgba(255, 255, 255, 0.3) !important; transform: translateY(-2px) !important; box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2) !important; } #nz-toolbox-body { padding: 24px !important; max-height: 600px !important; height: auto !important; overflow-y: auto !important; } #nz-toolbox-body::-webkit-scrollbar { width: 8px !important; } #nz-toolbox-body::-webkit-scrollbar-track { background: rgba(230, 57, 70, 0.08) !important; border-radius: 4px !important; } #nz-toolbox-body::-webkit-scrollbar-thumb { background: linear-gradient(180deg, #e63946 0%, #ff6b6b 100%) !important; border-radius: 4px !important; } .nz-group-title { font-size: 14px !important; color: #e63946 !important; margin: 24px 0 12px 0 !important; padding-left: 10px !important; border-left: 3px solid #e63946 !important; text-transform: uppercase !important; letter-spacing: 1.2px !important; font-weight: 600 !important; } .nz-group-title:first-child { margin-top: 0 !important; } .nz-toolbox-btn { width: 100% !important; background: #f8f9fa !important; border: 1px solid rgba(230, 57, 70, 0.2) !important; color: #333 !important; padding: 14px 20px !important; margin: 8px 0 !important; border-radius: 14px !important; cursor: pointer !important; font-size: 15px !important; text-align: left !important; display: flex !important; align-items: center !important; gap: 14px !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; position: relative !important; overflow: hidden !important; } .nz-toolbox-btn::before { content: '' !important; position: absolute !important; top: 0 !important; left: -100% !important; width: 100% !important; height: 100% !important; background: linear-gradient(90deg, transparent, rgba(230, 57, 70, 0.1), transparent) !important; transition: left 0.6s cubic-bezier(0.4, 0, 0.2, 1) !important; } .nz-toolbox-btn:hover { background: linear-gradient(145deg, #e63946 0%, #ff6b6b 100%) !important; color: #fff !important; transform: translateY(-3px) !important; box-shadow: 0 8px 24px rgba(230, 57, 70, 0.3) !important; border-color: rgba(230, 57, 70, 0.5) !important; } .nz-toolbox-btn:hover::before { left: 100% !important; } .nz-toolbox-btn:active { transform: translateY(-1px) !important; box-shadow: 0 4px 12px rgba(230, 57, 70, 0.2) !important; } .nz-btn-icon { width: 24px !important; height: 24px !important; display: flex !important; align-items: center !important; justify-content: center !important; flex-shrink: 0 !important; font-size: 20px !important; } #nz-toolbox.mini { width: 70px !important; height: 70px !important; border-radius: 22px !important; overflow: hidden !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; } #nz-toolbox.mini #nz-toolbox-body, #nz-toolbox.mini .nz-toolbox-title span { display: none !important; } #nz-toolbox.mini #nz-toolbox-header { width: 100% !important; height: 100% !important; justify-content: center !important; border-radius: 22px !important; padding: 0 !important; } .nz-toast { position: fixed !important; bottom: 60px !important; left: 50% !important; transform: translateX(-50%) !important; background: #fff !important; color: #333 !important; padding: 16px 28px !important; border-radius: 14px !important; font-size: 15px !important; z-index: 99999999 !important; box-shadow: 0 12px 36px rgba(0, 0, 0, 0.15) !important; border: 1px solid rgba(230, 57, 70, 0.3) !important; animation: nzSlideUp 0.4s ease-out !important; } @keyframes nzSlideUp { from { transform: translate(-50%, 30px); opacity: 0; } to { transform: translate(-50%, 0); opacity: 1; } } .reward-select-overlay { position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; background: rgba(0, 0, 0, 0.7) !important; z-index: 99999999 !important; display: flex !important; align-items: center !important; justify-content: center !important; } .reward-select-dialog { background: #fff !important; border-radius: 20px !important; width: 400px !important; max-width: 90% !important; padding: 24px !important; box-shadow: 0 15px 50px rgba(0, 0, 0, 0.3) !important; } .reward-select-title { color: #e63946 !important; font-size: 18px !important; margin: 0 0 20px 0 !important; text-align: center !important; } .reward-select-list { max-height: 300px !important; overflow-y: auto !important; margin-bottom: 20px !important; } .reward-item { padding: 12px 16px !important; border: 1px solid #eee !important; border-radius: 12px !important; margin-bottom: 10px !important; cursor: pointer !important; transition: all 0.2s !important; display: flex !important; align-items: center !important; gap: 12px !important; } .reward-item.selected { border-color: #e63946 !important; background-color: rgba(230, 57, 70, 0.05) !important; } .reward-checkbox { width: 20px !important; height: 20px !important; border-radius: 4px !important; border: 2px solid #ccc !important; display: flex !important; align-items: center !important; justify-content: center !important; flex-shrink: 0 !important; } .reward-item.selected .reward-checkbox { background-color: #e63946 !important; border-color: #e63946 !important; color: white !important; } .reward-select-buttons { display: flex !important; gap: 16px !important; } .reward-select-btn { flex: 1 !important; padding: 12px !important; border-radius: 12px !important; border: none !important; font-size: 16px !important; cursor: pointer !important; transition: all 0.3s !important; } .reward-cancel { background-color: #f1f1f1 !important; color: #333 !important; } .reward-confirm { background-color: #e63946 !important; color: white !important; } `); class StorageManager { static get(key) { try { return GM_getValue(`nz_${key}`, null); } catch (e) { return null; } } static set(key, val) { try { GM_setValue(`nz_${key}`, val); } catch (e) { console.log(e); } } } class UIHelper { static toast(msg, duration = 2000) { const existing = document.querySelector('.nz-toast'); if (existing) existing.remove(); const el = document.createElement('div'); el.className = 'nz-toast'; el.textContent = msg; document.body.appendChild(el); setTimeout(() => el.parentNode && el.remove(), duration); } static confirm(title, msg) { return new Promise(resolve => { const overlay = document.createElement('div'); overlay.style.cssText = `position: fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);z-index:99999998;`; const dialog = document.createElement('div'); dialog.style.cssText = `position: fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;border-radius:20px;padding:28px;width:360px;box-shadow:0 20px 60px rgba(0,0,0,0.15);border:1px solid rgba(230,57,70,0.3);z-index:99999999;`; dialog.innerHTML = `

${title}

${msg}

`; document.body.appendChild(overlay); document.body.appendChild(dialog); const cleanup = () => { overlay.parentNode && overlay.remove(); dialog.parentNode && dialog.remove(); }; dialog.querySelector('#nz-dialog-cancel').addEventListener('click', () => { resolve(false); cleanup(); }); dialog.querySelector('#nz-dialog-confirm').addEventListener('click', () => { resolve(true); cleanup(); }); overlay.addEventListener('click', () => { resolve(false); cleanup(); }); }); } static showRewardSelection() { return new Promise(resolve => { const rewards = [ { id: 1, name: '橙色神兵礼盒R3*1' }, { id: 2, name: '+4宝箱掉落卡(2小时)' }, { id: 3, name: '武装能量*5000' }, { id: 4, name: '交易币*400' }, { id: 5, name: '轮回经验箱R3*3' }, { id: 6, name: '高级轮回石*1' } ]; const overlay = document.createElement('div'); overlay.className = 'reward-select-overlay'; const dialog = document.createElement('div'); dialog.className = 'reward-select-dialog'; dialog.innerHTML = `

选择每日自动领取的奖励

${rewards.map(reward => `
${reward.id === 3 ? '✓' : ''}
${reward.id}. ${reward.name}
`).join('')}
`; overlay.appendChild(dialog); document.body.appendChild(overlay); const savedReward = StorageManager.get('daily_selected_reward') || 3; const items = dialog.querySelectorAll('.reward-item'); items.forEach(item => { if (parseInt(item.dataset.id) === savedReward) { item.classList.add('selected'); item.querySelector('.reward-checkbox').textContent = '✓'; } }); items.forEach(item => { item.addEventListener('click', () => { items.forEach(i => { i.classList.remove('selected'); i.querySelector('.reward-checkbox').textContent = ''; }); item.classList.add('selected'); item.querySelector('.reward-checkbox').textContent = '✓'; }); }); dialog.querySelector('.reward-confirm').addEventListener('click', () => { const selectedItem = dialog.querySelector('.reward-item.selected'); if (selectedItem) { const selectedId = parseInt(selectedItem.dataset.id); StorageManager.set('daily_selected_reward', selectedId); StorageManager.set('last_reward_selection_date', new Date().toDateString()); overlay.remove(); resolve(selectedId); } }); dialog.querySelector('.reward-cancel').addEventListener('click', () => { resolve(null); overlay.remove(); }); overlay.addEventListener('click', (e) => { if (e.target === overlay) { resolve(null); overlay.remove(); } }); }); } } class Executor { static closePopup(popupType = "default") { try { const newActivityCloseBtn = document.querySelector('.sp.btn_qr'); if (newActivityCloseBtn) { newActivityCloseBtn.click(); GM_log(`Close popup ${popupType}: .sp.btn_qr success`); return true; } const closeBtn = document.querySelector('.close.sp'); if (closeBtn) { closeBtn.click(); GM_log(`Close popup ${popupType}: .close.sp success`); return true; } const returnCloseBtn = document.querySelector('.pop_btn1.sp'); if (returnCloseBtn) { returnCloseBtn.click(); GM_log(`Close popup ${popupType}: .pop_btn1.sp success`); return true; } const cafeCloseBtn = document.querySelector('.pop-btn2'); if (cafeCloseBtn) { cafeCloseBtn.click(); GM_log(`Close popup ${popupType}: .pop-btn2 success`); return true; } const confirmBtn = document.querySelector('.pop1btn1'); if (confirmBtn) { confirmBtn.click(); GM_log(`Close popup ${popupType}: .pop1btn1 success`); return true; } const firstCloseBtn = document.querySelector('.pop_close.pa'); if (firstCloseBtn) { firstCloseBtn.click(); GM_log(`Close popup ${popupType}: .pop_close.pa success`); return true; } if (typeof closeDialog === 'function') { closeDialog(); GM_log(`Close popup ${popupType}: closeDialog() success`); return true; } GM_log(`Close popup ${popupType}: no element found`); return false; } catch (e) { GM_log(`Close popup ${popupType} error: ${e.message}`); return false; } } static autoClick(selector, actionName = "button") { try { let btn = null; if (selector.includes(':contains')) { const [baseSelector, textPart] = selector.split(':contains'); const text = textPart.replace(/[()"]/g, '').split(':nth-of-type')[0]; const nth = textPart.includes(':nth-of-type') ? parseInt(textPart.match(/:nth-of-type\((\d+)\)/)[1]) - 1 : 0; const allBtns = document.querySelectorAll(baseSelector.trim()); const matchedBtns = Array.from(allBtns).filter(btn => btn.textContent.includes(text)); if (matchedBtns.length > nth) { btn = matchedBtns[nth]; } } else { btn = document.querySelector(selector); } if (!btn) { GM_log(`${actionName}: selector ${selector} not found`); return false; } btn.click(); if (btn.dispatchEvent) { const event = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); btn.dispatchEvent(event); } GM_log(`${actionName}: selector ${selector} click success`); return true; } catch (e) { GM_log(`${actionName}: selector ${selector} click error: ${e.message}`); return false; } } static delayExecution(param = null, actionName = "delay") { GM_log(`${actionName}: delay ${param || '2000ms'}`); return new Promise(resolve => setTimeout(resolve, 2000)); } static async selectDailyRewards() { try { const today = new Date().toDateString(); const lastSelectionDate = StorageManager.get('last_reward_selection_date'); const selectedReward = StorageManager.get('daily_selected_reward'); if (!selectedReward || lastSelectionDate !== today) { const userChoice = await UIHelper.showRewardSelection(); if (userChoice === null) { GM_log('Reward selection cancelled'); return false; } return await Executor.collectSelectedReward(userChoice); } else { GM_log(`Use saved reward selection: ${selectedReward}`); return await Executor.collectSelectedReward(selectedReward); } } catch (e) { GM_log(`Select daily reward error: ${e.message}`); return false; } } static async collectSelectedReward(rewardId) { try { const rewards = [ { id: 1, selector: '.btn_p1lq.sp.chakan1.isGray24', name: '橙色神兵礼盒R3*1' }, { id: 2, selector: '.btn_p1lq.sp.chakan2.isGray25', name: '+4宝箱掉落卡(2小时)' }, { id: 3, selector: '.btn_p1lq.sp.chakan3.isGray26', name: '武装能量*5000' }, { id: 4, selector: '.btn_p1lq.sp.chakan4.isGray27', name: '交易币*400' }, { id: 5, selector: '.btn_p1lq.sp.chakan5.isGray28', name: '轮回经验箱R3*3' }, { id: 6, selector: '.btn_p1lq.sp.chakan6.isGray29', name: '高级轮回石*1' } ]; const reward = rewards.find(r => r.id === rewardId); if (!reward) { GM_log(`Reward id ${rewardId} not found`); return false; } GM_log(`Get reward: ${reward.name}`); const clickSuccess = Executor.autoClick(reward.selector, `Get ${reward.name}`); if (!clickSuccess) { return false; } await new Promise(resolve => setTimeout(resolve, 1000)); const closeSuccess = Executor.closePopup(`Get ${reward.name}`); if (!closeSuccess) { return false; } return true; } catch (e) { GM_log(`Collect reward error: ${e.message}`); return false; } } } class Toolbox { static quickPages = { activity: { icon: '🎮', name: '活动中心', url: 'https://nz.qq.com/web202403/activity-list.shtml' } }; static create() { const oldBox = document.getElementById('nz-toolbox'); if (oldBox) oldBox.remove(); const box = document.createElement('div'); box.id = 'nz-toolbox'; const pos = StorageManager.get('toolbox_pos'); if (pos) { box.style.top = `${pos.top}px`; box.style.left = `${pos.left}px`; } if (StorageManager.get('toolbox_mini')) box.classList.add('mini'); box.innerHTML = `
逆战活动助手
-
快速访问
${Object.values(Toolbox.quickPages).map(page => ` `).join('')}
活动列表
${ACTIVITY_CONFIGS.map(activity => ` `).join('')}
活动助手
`; document.body.appendChild(box); Toolbox.setupEvents(box); return box; } static setupEvents(box) { box.querySelector('.nz-toolbox-mini').addEventListener('click', (e) => { e.stopPropagation(); box.classList.toggle('mini'); StorageManager.set('toolbox_mini', box.classList.contains('mini')); }); const header = box.querySelector('#nz-toolbox-header'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - box.getBoundingClientRect().left; offsetY = e.clientY - box.getBoundingClientRect().top; header.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const x = e.clientX - offsetX; const y = e.clientY - offsetY; box.style.left = `${x}px`; box.style.top = `${y}px`; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; header.style.cursor = 'move'; StorageManager.set('toolbox_pos', { top: parseInt(box.style.top), left: parseInt(box.style.left) }); } }); box.querySelectorAll('[data-action]').forEach(btn => { btn.addEventListener('click', () => { const action = btn.dataset.action; const url = btn.dataset.url; if (action === 'openUrl' && url) { window.open(url, '_self'); } }); }); box.querySelector('#execute-all').addEventListener('click', async () => { const currentUrl = window.location.href; const currentActivity = ACTIVITY_CONFIGS.find(act => act.urlRegex.test(currentUrl)); if (!currentActivity) { UIHelper.toast('当前页面不是支持的活动页面'); return; } if (await UIHelper.confirm('执行操作', `确定要执行【${currentActivity.name}】一键领取吗?`)) { UIHelper.toast('开始执行一键领取'); await Toolbox.executeSteps(currentActivity.steps); UIHelper.toast('一键领取执行完成'); } }); box.querySelector('#reset-settings').addEventListener('click', async () => { if (await UIHelper.confirm('重置设置', '确定要重置所有设置吗?')) { StorageManager.set('toolbox_pos', null); StorageManager.set('toolbox_mini', false); StorageManager.set('daily_selected_reward', null); StorageManager.set('last_reward_selection_date', null); UIHelper.toast('设置已重置'); setTimeout(() => { Toolbox.create(); }, 1000); } }); } static async executeSteps(steps) { for (const [index, step] of steps.entries()) { GM_log(`[${index + 1}/${steps.length}] Execute: ${step.name}`); try { if (Executor[step.func]) { await Executor[step.func](step.param, step.name); } else { GM_log(`Unknown function: ${step.func}`); } } catch (e) { GM_log(`Step error: ${e.message}`); } if (step.delay > 0) { await new Promise(resolve => setTimeout(resolve, step.delay)); } } } } window.addEventListener('load', () => { setTimeout(() => { Toolbox.create(); }, 1000); }); })();