import doQuickFly from "../func/module/doQuickFly"; import loadGS from "../func/module/loadGS"; import adHelper from "../func/module/adHelper"; import safeKeeper from "../func/module/safeKeeper"; import updateTransDict from "../func/translate/updateTransDict"; import landedRedirect from "../func/module/landedRedirect"; import initMiniProf from "../func/utils/initMiniProf"; import WuhuBase from "./WuhuBase"; import Log from "./Log"; import CommonUtils from "./utils/CommonUtils"; import WuhuConfig from "./WuhuConfig"; import Alert from "./utils/Alert"; import * as EVENTS from "../static/json/event.json"; import * as FEST from "../static/json/fest.json"; import Popup from "./utils/Popup"; import TravelItem from "./action/TravelItem"; import QUICK_FLY_HTML from "../static/html/quick_fly.html"; import NNB_INFO_HTML from "../static/html/nnb_info.html"; import PRICE_WATCHER_HTML from "../static/html/price_watcher.html"; import DANGER_ZONE_HTML from "../static/html/danger_zone.html"; import ZHONG_MENU_HTML from "../static/html/zhong/zhong_menu.html"; import ZHONG_UPDATE_HTML from "../static/html/zhong/zhong_update.html"; import ZHONG_LOOT_HTML from "../static/html/zhong/zhong_loot.html"; import QUICK_CRIMES_HTML from "../static/html/quick_crimes.html"; import QUICK_FLY_CSS from "../static/css/quick_fly.css"; import QUICK_LINK_CSS from "../static/css/quick_link.css"; import MDUtils from "./utils/MDUtils"; import Test from "../test/Test"; import TornStyleSwitch from "./utils/TornStyleSwitch"; import Global from "./Global"; import BuyBeerHelper from "./action/BuyBeerHelper"; import Timer from "./utils/Timer"; export default class ZhongIcon extends WuhuBase { className = 'ZhongIcon'; public static ZhongNode: MyHTMLElement = null; private menuItemList: MenuItemConfig[] = null; private settingItemList: MenuItemConfig[] = null; public constructor() { Log.info('ZhongIcon初始化, 设置图标开始'); super(); this.setDefaultSettings() .constructWuhuSettingList() .constructMenuList() .insert2Dom(); Log.info('设置图标结束, ZhongIcon初始化结束'); } private elemGenerator(setting: MenuItemConfig, root_node: Element): HTMLElement { let { tip, domType } = setting; let new_node = null; switch (domType) { case 'checkbox': { new_node = document.createElement('div'); let { domId, dictName, domText, changeEv } = setting; let switcher = new TornStyleSwitch(domText); let _input = switcher.getInput(); switcher.getBase().id = domId; (tip) && (switcher.getBase().setAttribute('title', tip)); _input.checked = WuhuConfig.get(dictName); _input.onchange = e => { WuhuConfig.set(dictName, _input.checked, true); if (changeEv) changeEv(e); }; new_node.appendChild(switcher.getBase()); break; } case 'button': { new_node = document.createElement('div'); let { domId, domText, clickFunc } = setting; let btn = document.createElement('button'); (tip) && (btn.setAttribute('title', tip)); btn.id = domId; btn.innerHTML = domText; btn.addEventListener('click', clickFunc); new_node.appendChild(btn); break; } case 'select': { new_node = document.createElement('div'); let { domSelectOpt, dictName, domId, domText } = setting; let label = document.createElement('label'); (tip) && (label.setAttribute('title', tip)); let text = document.createTextNode(domText); let select = document.createElement('select'); select.id = domId; domSelectOpt.forEach((opt, i) => { let { domVal, domText } = opt; let option = document.createElement('option'); option.value = domVal; option.innerHTML = domText; option.selected = i === WuhuConfig.get(dictName); option.innerHTML = domText; select.appendChild(option); }); select.onchange = e => WuhuConfig.set(dictName, (e.target).selectedIndex); label.appendChild(text); label.appendChild(select); new_node.appendChild(label); break; } case 'plain': { let tag = setting.tagName || 'div'; new_node = document.createElement(tag); if (setting.domId) new_node.id = setting.domId; new_node.innerHTML += setting['domHTML']; break; } } // 移动节点 // Log.info('创建node', new_node); return root_node.appendChild(new_node); } /** * 添加左侧图标 */ private insert2Dom() { let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon'); let settings = this.menuItemList; let { version } = WuhuBase.glob; if ((self !== top) || !!zhong_node) return null; zhong_node = document.createElement('div'); zhong_node.id = 'wh-trans-icon'; zhong_node.classList.add('cont-gray'); zhong_node.innerHTML = ZHONG_MENU_HTML.replace('{{}}', version.slice(-1) === '$' ? 'DEV' : version); // 助手菜单 const menu_cont = zhong_node.querySelector('#wh-gSettings'); // 遍历菜单node设置、生成node、插入dom this.menuItemList.forEach(setting => this.elemGenerator(setting, menu_cont)); Log.info('生成元素插入完成'); // 计时node zhong_node.initTimer = zhong_node.querySelector('#wh-inittimer'); // 芜湖助手图标点击事件 (zhong_node.querySelector('#wh-trans-icon-btn')).onclick = () => { zhong_node.classList.toggle('wh-icon-expanded'); const click_func = e => { Log.info(e.target); if (e.target === zhong_node.querySelector('#wh-trans-icon-btn')) return; if (!zhong_node.contains(e.target)) { Log.info('移除事件监听器'); document.body.removeEventListener('click', click_func); zhong_node.classList.remove('wh-icon-expanded'); } }; if (zhong_node.classList.contains('wh-icon-expanded')) { Log.info('添加事件监听器'); document.body.addEventListener('click', click_func); } else { Log.info('移除事件监听器'); document.body.removeEventListener('click', click_func); } }; // 更新按钮点击事件 (zhong_node.querySelector('#wh-update-btn')).onclick = e => { (e.target).blur(); const innerHtml = ZHONG_UPDATE_HTML; // 直接复制的按钮 new Popup(innerHtml, '如何更新') .getElement() .querySelector('button').onclick = async (e) => { let target = e.target as HTMLButtonElement; target.innerHTML = '加载中'; const js_text = await CommonUtils.COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${ performance.now() }`); target.innerHTML = '点击复制到剪切板'; target.onclick = () => { const textarea_node = document.createElement('textarea'); textarea_node.innerHTML = js_text; target.parentElement.append(textarea_node); textarea_node.focus(); textarea_node.select(); document.execCommand('Copy'); textarea_node.remove(); target.innerHTML = '已复制'; target.onclick = null; new Alert('脚本已复制,请前往粘贴'); }; }; }; // 节日 zhong_node.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0 ? el.addEventListener('click', () => { let html = ''; settings.fest_date_list.sort().forEach(date => html += `` ); new Popup(html += '
${ 1 + ((date.slice(0, 2)) | 0) }月${ date.slice(2) }日${ settings.fest_date_dict[date].name }${ settings.fest_date_dict[date].eff }
', '节日'); }) : el.addEventListener('click', null)); // 活动 zhong_node.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0 ? el.addEventListener('click', () => { let html = ''; settings.events.forEach(el => html += ``); new Popup(html += '
${ el.name }${ el.start[0] + 1 }月${ el.start[1] }日${ el.start[2] }:00~${ el.end[0] + 1 }月${ el.end[1] }日${ el.end[2] }:00
${ el.eff }

更多信息请关注群聊和公众号

', '活动'); }) : el.addEventListener('click', null)); document.body.append(zhong_node); // 引入torn自带浮动提示 Log.info('引入torn自带浮动提示'); (window.initializeTooltip) && (window.initializeTooltip('.wh-container', 'white-tooltip')); // 加载torn mini profile Log.info('加载torn mini profile'); let miniProfileInterval = { id: window.setInterval(() => { miniProfileInterval.counter++; if (window.$ || (window.unsafeWindow && window.unsafeWindow.$)) { initMiniProf('#wh-trans-icon'); window.clearInterval(miniProfileInterval.id); } if (miniProfileInterval.counter > 30) window.clearInterval(miniProfileInterval.id); }, 1000), counter: 0 }; ZhongIcon.ZhongNode = zhong_node; Log.info('图标加入文档树完成'); } // 菜单 private constructMenuList(): ZhongIcon { Log.info('构造展开菜单列表开始'); let timer = new Timer(); let glob = Global.getInstance(); const date = new Date(); let list: MenuItemConfig[] = []; // 欢迎 显示玩家id if (glob.player_info.userID !== 0) { list.push({ domType: 'plain', domId: 'wh-trans-welcome', domHTML: `欢迎 ${ glob.player_info.playername }[${ glob.player_info.userID }] 大佬`, }); } // 节日 let fest_date_html = ': '; { // 节日字典 const dict = FEST.val; list.fest_date_dict = dict; list.fest_date_list = Object.keys(dict); const formatMMDD = (m, d) => { const MM = m < 10 ? `0${ m }` : m.toString(); const DD = d < 10 ? `0${ d }` : d.toString(); return MM + DD; } const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate()); if (dict[fest_date_key]) fest_date_html += `今天 - ${ dict[fest_date_key]['name'] }()`; else { // 月日列表 let list = Object.keys(dict); list.push(fest_date_key); // 下个节日的位置 const index: number = list.sort().indexOf(fest_date_key) + 1; // 下个节日obj const next_fest_date = dict[list[index] || list[0]]; // 下个节日的时间 let next = new Date( index !== list.length ? date.getUTCFullYear() : date.getUTCFullYear() + 1, (list[index !== list.length ? index : 0] as any).slice(0, 2) | 0, (list[index !== list.length ? index : 0] as any).slice(2) | 0, 8 ).getTime(); // 剩余天数 const left = (next - date.getTime()) / 86400000 | 0; fest_date_html += `${ left }天后 - ${ next_fest_date.name }()`; } } list.push({ domType: 'plain', domId: 'wh-trans-fest-date', domHTML: fest_date_html, }); // 活动 let eventObj: EventWrapper = { onEv: false, daysLeft: Infinity, events: EVENTS.default, }; list.events = eventObj.events; eventObj.events.forEach((obj, index) => { if (eventObj.onEv) return; // 当前年份 const nowYear = date.getFullYear(); // 当前遍历的活动开始时间 const start = new Date(nowYear, obj.start[0], obj.start[1], obj.start[2]); // 当前遍历的活动结束时间 const end = new Date(nowYear, obj.end[0], obj.end[1], obj.end[2]); // 当前处于活动中 if (start < date && date < end) { eventObj.onEv = true; eventObj.daysLeft = (end.getTime() - date.getTime()) / 86400000 | 0; eventObj.current = obj; } // 当前没有活动 else { // 当前遍历的活动如果已经经过了,那么下次活动就是遍历的下一个活动对象,否则为当前活动。 // 如果本年度活动都经过了,那么下次活动是列表的第一个活动对象 const next = end < date ? eventObj.events[index + 1] || eventObj.events[0] : obj; // 经过了最后一个活动所以下次活动开始时间是第二年 const start = new Date(next !== obj && index === eventObj.events.length - 1 ? nowYear + 1 : nowYear, next.start[0], next.start[1], next.start[2]); const daysLeft = (start.getTime() - date.getTime()) / 86400000 | 0; if (0 <= daysLeft && daysLeft < eventObj.daysLeft) { eventObj.daysLeft = daysLeft; eventObj.next = next; } } }); eventObj.html = ': '; eventObj.onEv ? eventObj.html += `${ eventObj.current.name }() - 剩余${ eventObj.daysLeft }天` : eventObj.html += `${ eventObj.daysLeft }天后 - ${ eventObj.next.name }()`; list.push({ domType: 'plain', domId: 'wh-trans-event-cont', domHTML: eventObj.html, }); // 飞花库存 list.push({ domType: 'button', domId: 'wh-foreign-stock-btn', domText: '🌸 飞花库存', clickFunc: async function (e) { e.target.blur(); // forStock().then(); TravelItem.getInstance().clickHandler().then(); }, }); // 一键起飞 list.push({ domType: 'button', domId: 'wh-quick-fly-btn', domText: '✈️ 一键起飞', clickFunc: async function () { if (window.hasWHQuickFlyOpt) return; window.hasWHQuickFlyOpt = true; // TODO CommonUtils.addStyle(QUICK_FLY_CSS); const node = document.createElement('div'); node.id = 'wh-quick-fly-opt'; node.innerHTML = QUICK_FLY_HTML; const [dest_node, type_node] = node.querySelectorAll('select') as any as HTMLSelectElement[]; node.querySelector('button').addEventListener('click', () => { sessionStorage['wh-quick-fly'] = `${ dest_node.selectedIndex } ${ type_node.selectedIndex } ${ new Date().getTime() }`; if (!glob.href.contains('travelagency.php')) { new Alert('正在转跳'); location.href = 'https://www.torn.com/travelagency.php'; } else { doQuickFly(); } }); node.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); // forStock(); TravelItem.getInstance().clickHandler(); }); node.querySelector('input').addEventListener('click', (e) => { node.classList.toggle('wh-quick-fly-opt-hide'); const el = e.target as HTMLInputElement; el.value = el.value === ' - ' ? ' + ' : ' - '; }); const info_node = node.querySelector('info'); const time_predict = document.createElement('p'); const yaoCD = document.createElement('p'); info_node.append(time_predict); info_node.append(yaoCD); const predict = [ ['~54分', '~36分', '~26分', '~16分',], ['~1时10分', '~50分', '~36分', '~22分',], ['~1时22分', '~58分', '~40分', '~24分',], ['~4时28分', '~3时8分', '~2时14分', '~1时20分',], ['~5时18分', '~3时42分', '~2时40分', '~1时36分',], ['~5时34分', '~3时54分', '~2时46分', '~1时40分',], ['~5时50分', '~4时6分', '~2时56分', '~1时46分',], ['~7时30分', '~5时16分', '~3时46分', '~2时16分',], ['~8时4分', '~5时38分', '~4时2分', '~2时24分',], ['~9时2分', '~6时20分', '~4时30分', '~2时42分',], ['~9时54分', '~6时56分', '~4时58分', '~2时58分',], ]; const showTime = function () { time_predict.innerHTML = `往返时间:${ predict[dest_node.selectedIndex][type_node.selectedIndex] }`; } dest_node.addEventListener('change', showTime); type_node.addEventListener('change', showTime); document.body.append(node); showTime(); yaoCD.innerHTML = `药CD剩余:${ CommonUtils.getYaoCD() }`; }, }); // NPC LOOT list.push({ domType: 'button', domId: 'wh-npc-loot-btn', domText: '🔫 LOOT', clickFunc: function (e) { e.target.blur(); const insert = ZHONG_LOOT_HTML.replace('{{}}', performance.now().toString()); new Popup(insert, 'NPC LOOT'); }, tip: '显示5个可击杀NPC的开打时间', }); // 查看NNB list.push({ domType: 'button', domId: 'wh-nnb-info', domText: '👮‍ 查看NNB', clickFunc: function (e) { e.target.blur(); const insert = NNB_INFO_HTML .replace('{{}}', localStorage.getItem('APIKey') || '不可用') .replace('{{}}', glob.isPDA ? glob.PDA_APIKey : '不可用'); const popup = new Popup(insert, '查看NNB').getElement(); const select = popup.querySelector('input'); const node = popup.querySelector('p'); popup.querySelector('button').addEventListener('click', ev => { let target = ev.target as HTMLInputElement; target.style.display = 'none'; node.innerHTML = '加载中'; // API 计算 if (select.checked) { const api_key = glob.isPDA ? glob.PDA_APIKey : window.localStorage.getItem('APIKey'); window.fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`) .then(res => res.json()) .then(data => { if (data['error']) { node.innerHTML = `出错了 ${ JSON.stringify(data['error']) }`; target.style.display = null; return; } let nb = data['nerve']['maximum']; let perks = 0; Object.values(data).forEach(val => { (val instanceof Array) && val.forEach(s => { s = s.toLowerCase(); s.includes('maximum nerve') && (perks += (new RegExp('[0-9].').exec(s))[0] | 0) }) }); node.innerHTML = `NNB: ${ nb - perks }`; target.style.display = null; }); } // 主页计算 else { if (window.location.href.includes('index.php') && document.title.includes('Home')) { let nb = (document.querySelector('#barNerve p[class^="bar-value___"]').innerText.split('/')[1]) | 0; let perks = 0; document.querySelectorAll('#personal-perks li').forEach(elem => { const str = elem.innerText.toLowerCase(); str.includes('maximum nerve') && (perks += (/[0-9]./.exec(str) as any)[0] | 0) }); node.innerHTML = `NNB: ${ nb - perks }`; target.style.display = null; return; } node.innerHTML = '不在主页面,点击前往'; target.style.display = null; } }); }, }); // 常用链接 list.push({ domType: 'button', domId: 'wh-link-collection', domText: '🔗 常用链接', clickFunc: function (e) { if (!this.styleAdded) { CommonUtils.addStyle(QUICK_LINK_CSS); this.styleAdded = true; } e.target.blur(); const quick_link_dict = []; // 生存手册 quick_link_dict.push({ name: '生存手册', url: 'https://docs.qq.com/doc/DTVpmV2ZaRnB0RG56', new_tab: true, img: 'https://www.torn.com/images/items/293/medium.png', }); // 买啤酒 quick_link_dict.push({ name: '抢啤酒', url: 'https://www.torn.com/shops.php?step=bitsnbobs', new_tab: true, img: 'https://www.torn.com/images/items/180/medium.png', }); // 买XAN quick_link_dict.push({ name: '买XAN', url: 'https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax', new_tab: true, img: 'https://www.torn.com/images/items/206/medium.png', }); // 起飞 quick_link_dict.push({ name: '起飞', url: 'https://www.torn.com/travelagency.php', new_tab: true, img: 'https://www.torn.com/images/items/396/medium.png', }); // 买PT quick_link_dict.push({ name: '买PT', url: 'https://www.torn.com/pmarket.php', new_tab: true, img: 'https://www.torn.com/images/items/722/medium.png', }); // 租PI quick_link_dict.push({ name: '租PI', url: 'https://www.torn.com/properties.php?step=rentalmarket#/property=13', new_tab: false, img: 'https://www.torn.com/images/v2/properties/350x230/350x230_default_private_island.png', }); // 找工作 quick_link_dict.push({ name: '找工作', url: 'https://www.torn.com/joblist.php#!p=main', new_tab: false, img: 'https://www.torn.com/images/items/421/medium.png', }); // 下悬赏 quick_link_dict.push({ name: '下悬赏', url: 'https://www.torn.com/bounties.php#/p=add', new_tab: false, img: 'https://www.torn.com/images/items/431/medium.png', }); let insert = '

'; quick_link_dict.forEach(el => { insert += `${ el.name }`; }); insert += '

' let popup = new Popup(insert, '常用链接'); popup.getElement().classList.add('wh-link-collection-cont'); popup.getElement().addEventListener('click', ev => { let target = ev.target as HTMLElement; if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'span') { popup.close(); } }); }, }); // 飞贼 list.push({ domType: 'button', domId: 'wh-gs-btn', domText: '🐏 飞贼小助手', clickFunc: function (e) { e.target.blur(); loadGS(CommonUtils.getScriptEngine()); }, tip: '加载从PC端移植的伞佬的油猴版飞贼小助手', }); // 物品价格监视 list.push({ domType: 'button', domId: 'wh-price-watcher-btn', domText: '💊 价格监视', clickFunc: function () { const watcher_conf = WuhuConfig.get('priceWatcher'); const pre_str = JSON.stringify(watcher_conf); const html = PRICE_WATCHER_HTML .replace('{{}}', localStorage.getItem('APIKey') || '不可用') .replace('{{}}', glob.isPDA ? glob.PDA_APIKey : '不可用') .replace('{{}}', watcher_conf['pt'] || -1) .replace('{{}}', watcher_conf['xan'] || -1); const popup = new Popup(html, '价格监视设置'); popup.getElement().querySelector('button').onclick = () => { const [pt_node, xan_node] = Array.from(>popup.getElement().querySelectorAll('input[type="number"]')); watcher_conf.pt = (pt_node.value as any) | 0; watcher_conf.xan = (xan_node.value as any) | 0; if (JSON.stringify(watcher_conf) !== pre_str) WuhuConfig.set('priceWatcher', watcher_conf); popup.close(); }; } }); // 小窗犯罪 list.push({ domType: 'button', domId: 'wh-crime-iframe-btn', domText: '🤑 小窗犯罪', clickFunc: function () { // 弹出小窗口 const ifHTML = ``; const popup_insert = `

加载中请稍后${ CommonUtils.loading_gif_html() }

`; const $popup = new Popup(popup_insert, '小窗快速犯罪').getElement(); // 运行状态node let loading_node = $popup.querySelector('p:first-of-type'); // if容器 const if_cont = $popup.querySelector('#wh-quick-crime-if-container'); if_cont.innerHTML = ifHTML; // if内未加载脚本时插入的快捷crime node const mobile_prepend_node = document.createElement('div'); mobile_prepend_node.classList.add('wh-translate'); mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML; // if对象加载后运行 let cIframe = $popup.querySelector('iframe'); // 加载状态 const if_onload_func = () => { // if内部文档对象 const ifDocu = cIframe.contentWindow.document; // 内部插件运行flag const ifWH = cIframe.contentWindow.WHTRANS; // 文档加载完成后移除 if (!!loading_node) loading_node.remove(); // 文档加载完成后才显示if cIframe.style.display = 'block'; // 验证码flag const isValidate = ifDocu.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate'); // 如果iframe内部未运行脚本 if (ifWH === undefined) { // 隐藏顶部 CommonUtils.elementReady('#header-root', ifDocu).then(e => e.style.display = 'none'); // 隐藏4条 CommonUtils.elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none'); // 隐藏聊天 CommonUtils.elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none'); // 非验证码页面隐藏滚动条 if (!isValidate) ifDocu.body.style.overflow = 'hidden'; // 调整容器位置 CommonUtils.elementReady('.content-wrapper', ifDocu).then(elem => { // 加入 elem.prepend(mobile_prepend_node); elem.style.margin = '0px'; elem.style.position = 'absolute'; elem.style.top = '-35px'; new MutationObserver((m, o) => { o.disconnect(); if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node); o.observe(elem, { childList: true, subtree: true }); }) .observe(elem, { childList: true, subtree: true }); }); // 隐藏返回顶部按钮 CommonUtils.elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none'); } }; cIframe.onload = if_onload_func; // 超时判断 let time_counter = 0; let time_out_id = window.setInterval(() => { loading_node = $popup.querySelector('p:first-of-type'); if (!loading_node) { clearInterval(time_out_id); time_out_id = undefined; return; } time_counter++; if (time_counter > 0 && !loading_node.querySelector('button')) { const reload_btn = document.createElement('button'); reload_btn.innerHTML = '重新加载'; reload_btn.onclick = () => { reload_btn.remove(); time_counter = 0; if_cont.innerHTML = null; if_cont.innerHTML = ifHTML; cIframe = $popup.querySelector('iframe'); cIframe.onload = if_onload_func; }; loading_node.append(reload_btn); } }, 1000); } }); // 危险行为开关⚠️ list.push({ domType: 'button', domId: 'wh-danger-zone', domText: '⚠️ 危险功能', clickFunc: function (e) { e.target.blur(); const insert = DANGER_ZONE_HTML.replace('{{}}', WuhuConfig.get('dangerZone') ? 'checked ' : ' '); const popup = new Popup(insert, '⚠️警告'); const warning_check = popup.getElement().querySelector('input'); const ok_btn = popup.getElement().querySelector('button'); warning_check.onchange = () => ok_btn.disabled = false; ok_btn.onclick = () => { WuhuConfig.set('dangerZone', warning_check.checked); popup.close(); window.location.reload(); }; }, }); // 传单助手 list.push({ domType: 'button', domId: '', domText: '📜️ 传单助手', clickFunc: adHelper }); // 守望者 list.push({ domType: 'button', domId: '', domText: '🛡️ 守望者', clickFunc: function () { safeKeeper(); }, }); // 寻找木桩 list.push({ domType: 'button', domId: '', domText: '🪵 寻找木桩', clickFunc: () => window.location.href = 'https://www.torn.com/item.php?temp=4#xunzhaomuzhuang' }); // 更新历史 list.push({ domType: 'button', domId: '', domText: '🐞 更新历史', clickFunc: async () => { let popup = new Popup( '更新历史:
https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md
', '更新历史' ).getElement(); popup.classList.add('wh-changeLog'); let progressBar = document.createElement('div'); progressBar.style.height = '2px'; progressBar.style.width = '1%'; progressBar.style.backgroundColor = 'red'; let progressText = document.createElement('p'); progressText.innerText = '加载更新文件……'; progressText.style.textAlign = 'center'; let style = document.createElement('style'); style.innerHTML = `.wh-changeLog h2,.wh-changeLog h3,.wh-changeLog h4 {margin:8px 0;}.wh-changeLog li{list-style: inside;}`; popup.append(progressBar, progressText, style); let update = await CommonUtils.COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + Date.now()); progressBar.style.width = '60%'; progressText.innerText = '解析中……'; let md = MDUtils.getInstance().parse(update); popup.append(md); progressBar.style.width = '100%'; progressText.innerText = '加载完成'; setTimeout(() => { progressBar.remove(); progressText.remove() }, 3000); }, }); // 助手设置 list.push({ domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => { let startTime = performance.now(); Log.info('构造设置开始'); let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置'); let tmp = document.createElement('div'); tmp.classList.add('gSetting'); this.settingItemList.forEach(set => this.elemGenerator(set, tmp)); pop.getElement().innerHTML = ''; pop.getElement().appendChild(tmp); // 本日不提醒 pop.getElement().querySelector('#wh-qua-alarm-check-btn').addEventListener('click', () => Global.getInstance().beer.skip_today()); // 开发详情按钮 // if (Log.debug()) $zhongNode.setting_root.querySelector('button#wh-devInfo').onclick = () => { // const date = new Date(); // let os = '未知'; // try { // os = window.navigator.userAgentData.platform || window.navigator.platform // } catch { // } // // pop.close(); // new Popup(DEV_DETAILS_HTML, '开发者详情'); // }; (window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip')); Log.info('构造设置结束,' + ((performance.now() - startTime) | 0) + 'ms'); }, }); // 测试 if (Log.debug()) list.push({ domType: 'button', domId: '', domText: '📐️ 测试', clickFunc: async function () { let startTime = performance.now(); Log.info('测试开始'); try { Test.getInstance().test(); } catch (e) { Log.error('测试异常,' + JSON.stringify(e)); } Log.info('测试结束 ' + ((performance.now() - startTime) | 0) + 'ms'); }, }); this.menuItemList = list; Log.info('构造展开菜单列表结束' + timer.getTimeMs()); return this; } // 设置 private constructWuhuSettingList(): ZhongIcon { Log.info('构造设置列表开始'); let timer = new Timer(); const date = new Date(); let beer = BuyBeerHelper.getInstance(); let list: MenuItemConfig[] = []; // 12月时加入圣诞小镇选项 if (date.getMonth() === 11) { list.push({ domType: 'plain', domId: '', domHTML: '圣诞小镇', tagName: 'h4', }) list.push({ domType: 'checkbox', domId: 'wh-xmastown-wt', domText: ' 圣诞小镇攻略', dictName: 'xmasTownWT', isHide: true, }); list.push({ domType: 'checkbox', domId: 'wh-xmastown-notify', domText: ' 圣诞小镇物品提示', dictName: 'xmasTownNotify', isHide: true, }); } // 翻译 list.push({ domType: 'plain', domId: '', domHTML: '翻译', tagName: 'h4', }); // 开启翻译 list.push({ domType: 'checkbox', domId: 'wh-trans-enable', domText: ' 开启翻译', dictName: 'transEnable', isHide: true, }); // 更新翻译词库 list.push({ domType: 'button', domId: '', domText: '更新翻译词库', clickFunc: updateTransDict }); // 战斗优化 list.push({ domType: 'plain', domId: '', domHTML: '战斗优化', tagName: 'h4', }); // 光速拔刀 list.push({ domType: 'select', domId: 'wh-quick-attack-index', domText: '光速拔刀 ', domSelectOpt: [ { domVal: 'pri', domText: '主手', }, { domVal: 'sec', domText: '副手', }, { domVal: 'wea', domText: '近战', }, { domVal: 'gre', domText: '手雷', }, { domVal: 'fis', domText: '拳头', }, { domVal: 'kic', domText: '脚踢', }, { domVal: 'none', domText: '关闭', }, ], dictName: 'quickAttIndex', isHide: true, tip: '将Start Fight按钮移动到指定格子上', }); // 光速跑路 list.push({ domType: 'select', domId: 'wh-quick-mug', domText: '光速跑路 ', domSelectOpt: [ { domVal: 'leave', domText: '跑路(LEAVE)', }, { domVal: 'mug', domText: '打劫(MUG)', }, { domVal: 'hosp', domText: '住院(HOSP)', }, { domVal: 'none', domText: '关闭', }, ], dictName: 'quickFinishAtt', isHide: true, tip: '将结束后指定按钮移动到上面指定的格子上暂时关闭', }); // 攻击链接转跳 list.push({ domType: 'checkbox', domId: 'wh-attack-relocate', domText: ' 真·攻击界面转跳', dictName: 'attRelocate', tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面', isHide: true, }); // 飞行 list.push({ domType: 'plain', domId: '', domHTML: '飞行', tagName: 'h4', }); // 起飞警告 list.push({ domType: 'checkbox', domId: 'wh-energy-alert', domText: ' 起飞爆E警告', dictName: 'energyAlert', tip: '起飞前计算来回是否会爆体,红字警告', isHide: true, }); // 飞行闹钟 list.push({ domType: 'checkbox', domId: 'wh-trv-alarm-check', domText: ' 飞行闹钟', dictName: 'trvAlarm', tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限', isHide: true, }); // 海外警告 list.push({ domType: 'checkbox', domId: '', domText: ' 海外警告', dictName: 'abroadWarning', tip: '海外落地后每30秒通知警告', }); // 落地转跳 list.push({ domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect }); // 公司 list.push({ domType: 'plain', domId: '', domHTML: '公司', tagName: 'h4', }); // 浮动存钱框 list.push({ domType: 'checkbox', domId: '', domText: ' 浮动存钱框', dictName: 'floatDepo', tip: '打开公司或帮派的存钱页面后存钱框将浮动显示', }); // 公司转跳存钱 list.push({ domType: 'checkbox', domId: '', domText: ' 公司转跳存钱', dictName: 'companyRedirect', tip: '打开公司页面时自动打开存钱选项卡', }); // 收起公司冰蛙效率表 list.push({ domType: 'checkbox', domId: '', domText: ' 收起公司冰蛙效率表', dictName: 'companyBWCollapse', tip: '开启后可手动显示隐藏冰蛙公司表格', }); // 任何位置一键存钱 list.push({ domType: 'checkbox', domId: '', domText: ' 任何位置一键存钱', dictName: 'companyDepositAnywhere', tip: '在所有页面显示一键存钱按钮,Torn OK状态下可用,此功能未完全测试无害,使用请慎重', }); // 啤酒 list.push({ domType: 'plain', domId: '', domHTML: '啤酒', tagName: 'h4', }); // 啤酒提醒 list.push({ domType: 'checkbox', domId: 'wh-qua-alarm-check', domText: ' 啤酒提醒 ', dictName: '_15Alarm', tip: '每小时的整15分钟的倍数时通知提醒抢啤酒或者血包', isHide: true, changeEv: function (ev) { ev.target.checked ? beer.start() : beer.stop(); }, }); // 啤酒提醒状态 list.push({ domType: 'button', domId: '', domText: '啤酒提醒状态', clickFunc: function () { new Alert(`啤酒提醒${ beer.status() }`); } }); // 啤酒提醒时间 list.push({ domType: 'button', domId: '', domText: '啤酒提醒时间设定', // tip: '通知提前时间', clickFunc: function () { let popup = new Popup(`

区间为 1 ~ 60,默认 50

`, '啤酒提醒时间设定'); let confirm = document.createElement('button'); confirm.innerHTML = '确定'; confirm.style.float = 'right'; confirm.addEventListener('click', () => { let input: HTMLInputElement = popup.getElement().querySelector('input'); let num = (input.value as any) | 0; if (num === WuhuConfig.get('_15AlarmTime')) return; if (num < 1 || num > 60) num = 50; input.value = num.toString(); WuhuConfig.set('_15AlarmTime', num); beer.set_time(num); // 之前的运行状态 if (beer.is_running()) beer.start(); popup.close(); }); popup.getElement().appendChild(confirm); }, }); // 其他 list.push({ domType: 'plain', domId: '', domHTML: '其他', tagName: 'h4', }); // 任务助手 list.push({ domType: 'checkbox', domId: 'wh-mission-lint', domText: ' 任务助手', dictName: 'missionHint', tip: 'Duke任务的一些中文小提示', isHide: true, }); // 捡垃圾助手 list.push({ domType: 'checkbox', domId: 'wh-city-finder', domText: ' 捡垃圾助手', dictName: 'cityFinder', tip: '城市地图中放大显示物品并且估计价值', isHide: true, }); // 快速crime list.push({ domType: 'checkbox', domId: 'wh-quick-crime', domText: ' 快速犯罪', dictName: 'quickCrime', tip: '显示快捷操作按钮,目前不支持自定义', isHide: true, }); // 叠E保护 list.push({ domType: 'checkbox', domId: 'wh-SEProtect-check', domText: ' 叠E保护', dictName: 'SEProtect', tip: '隐藏健身房的锻炼按钮,防止误操作', isHide: true, }); // PT一键购买 list.push({ domType: 'checkbox', domId: 'wh-ptQuickBuy-check', domText: ' PT一键购买', dictName: 'ptQuickBuy', tip: 'PT市场页面购买时跳过确认', isHide: true, }); // 4条转跳 list.push({ domType: 'checkbox', domId: '', domText: ' 4条转跳', dictName: 'barsRedirect', tip: '点击4条时转跳对应页面', }); // 清除多余的脚本 list.push({ domType: 'checkbox', domId: '', domText: ' 清除多余的脚本', dictName: 'removeScripts', tip: '清除Google相关脚本、顶部横幅等', }); // 危险行为⚠️ if (WuhuConfig.get('dangerZone') === true) { // 攻击界面自刷新 list.push({ domType: 'select', domId: 'wh-attack-reload', domText: '⚠️攻击界面自动刷新 ', dictName: 'attReload', domSelectOpt: [ { domVal: 'none', domText: '无间隔', }, { domVal: '1', domText: '约1s', }, { domVal: '2', domText: '约2s', }, { domVal: '3', domText: '约3s', }, { domVal: '4', domText: '约4s', }, { domVal: '5', domText: '约5s', }, { domVal: 'disabled', domText: '关闭', }, ], isHide: true, tip: '危险功能:接机时常用,将自动刷新页面直到目标落地', }); // 自动开打和结束 list.push({ domType: 'checkbox', domId: 'wh-auto-start-finish', domText: ' ⚠️自动开打和结束', dictName: 'autoStartFinish', tip: '脚本将会自动按下战斗和结束按钮', isHide: true, }); } else { WuhuConfig.set('autoStartFinish', false) WuhuConfig.set('attReload', 6) } // dev list.push({ domType: 'checkbox', domId: 'wh-dev-mode', domText: '开发模式', dictName: 'isDev', isHide: true, }); // 查看logs list.push({ domType: 'button', domId: null, domText: '查看日志', clickFunc: () => { let logCounter = Log.getCounter(); let pop = new Popup('', '查看日志'); let text = pop.getElement().querySelector('textarea'); text.innerHTML = Log.getLogs(); text.onclick = () => text.select(); pop.getElement().insertAdjacentHTML('afterbegin', `

${ logCounter.info }信息 ${ logCounter.warning }警告 ${ logCounter.error }错误

`) } }); // 更多设定 list.push({ domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => { let pop = new Popup('', '更多设定'); let insertHtml = '

'; pop.getElement().insertAdjacentHTML('beforeend', insertHtml); let [btn1, btn2, btn3] = Array.from(pop.getElement().querySelectorAll('button')); btn1.addEventListener('click', () => { localStorage.removeItem('wh_trv_alarm'); localStorage.removeItem('wh_trans_settings'); localStorage.removeItem('whuuid'); localStorage.removeItem('wh-gs-storage'); localStorage.removeItem('WHTEST'); new Alert('已清空,刷新页面'); window.location.reload(); }); btn2.addEventListener('click', () => { }); btn3.addEventListener('click', () => { }); }, // isHide: true, }); this.settingItemList = list; Log.info('构造设置列表结束' + timer.getTimeMs()); return this; } // 默认设置 private setDefaultSettings(): ZhongIcon { Log.info('设置默认值开始'); let count = 0; [ // 开启翻译 { key: 'transEnable', val: false }, // 快速犯罪 { key: 'quickCrime', val: true }, // 任务助手 { key: 'missionHint', val: true }, // 小镇攻略 { key: 'xmasTownWT', val: true }, // 小镇提醒 { key: 'xmasTownNotify', val: true }, // 起飞爆e { key: 'energyAlert', val: true }, // 飞行闹钟 { key: 'trvAlarm', val: true }, // 啤酒提醒 { key: '_15Alarm', val: true }, // 捡垃圾助手 { key: 'cityFinder', val: false }, // 叠E保护 { key: 'SEProtect', val: false }, // PT一键购买 { key: 'ptQuickBuy', val: false }, // 光速拔刀 6-关闭 { key: 'quickAttIndex', val: 2 }, // 光速跑路 0-leave 1-mug 2-hos 3-关闭 { key: 'quickFinishAtt', val: 3 }, // 自动开打和结束 { key: 'autoStartFinish', val: false }, // 废弃 { key: 'attRelocate', val: true }, // 攻击自刷新 0-无间隔 1-5s 6-关闭 { key: 'attReload', val: 6 }, // 价格监视 { key: 'priceWatcher', val: { xan: -1, pt: -1 } }, // 开发者模式 { key: 'isDev', val: false }, // 啤酒提醒时间 { key: '_15AlarmTime', val: 50 }, // 4条转跳 { key: 'barsRedirect', val: true }, // 浮动存钱框 { key: 'floatDepo', val: true }, // 公司转跳存钱 { key: 'companyRedirect', val: true }, // 收起公司冰蛙效率表 { key: 'companyBWCollapse', val: true }, // 清除多余的脚本 { key: 'removeScripts', val: true }, // 海外警告 { key: 'abroadWarning', val: true }, // 落地转跳 { key: 'landedRedirect', val: '' }, // 任何位置一键存钱 { key: 'companyDepositAnywhere', val: false }, // 危险行为⚠️ { key: 'dangerZone', val: false }, ].forEach(df => { if (typeof WuhuConfig.get(df.key) !== typeof df.val) { WuhuConfig.set(df.key, df.val); count++; } }); Log.info('设置默认值结束,新:' + count); return this; } } interface MenuItemConfig { domType: 'button' | 'plain' | 'checkbox' | 'select'; tagName?: string; domId?: string; domText?: string; clickFunc?: (ev?) => void; domHTML?: string; tip?: string; dictName?: string; changeEv?: (ev) => void; domSelectOpt?: { domVal: string, domText: string }[]; /** * 隐藏菜单已弃用 * @deprecated */ isHide?: boolean; } interface EventWrapper { onEv: boolean; daysLeft: number; events: Event[]; current?: Event; next?: Event; html?: string; } interface Event { start: number[]; end: number[]; name: string; eff: string; }