import getWhSettingObj from "./func/utils/getWhSettingObj"; import cityFinder from "./func/module/cityFinder"; import elementReady from "./func/utils/elementReady"; import { missionDict } from "./dictionary/translation"; import getTaskHint from "./func/translate/getTaskHint"; import Device from "./enum/Device"; import WuhuBase from "./class/WuhuBase"; import Utils from "./class/utils/Utils"; import Log from "./class/Log"; import WuhuConfig from "./class/WuhuConfig"; import Alert from "./class/utils/Alert"; import InfoUtils from "./class/utils/InfoUtils"; export default class UrlPattern extends WuhuBase { constructor() { super(); } static resolve() { let { href, beer } = UrlPattern.glob; // 捡垃圾助手 if (href.includes('city.php') && getWhSettingObj()['cityFinder']) { cityFinder(); } // pt一键购买 if (WuhuConfig.get('ptQuickBuy') && href.includes('pmarket.php')) { new Alert('一键购买已开启'); // ns脚本 const rmv_cfm = (e) => { let el = e.firstElementChild; el.className += ' yes'; let old_href = el.getAttribute('href'); let new_href = old_href.replace(/=buy/, '=buy1').replace(/&points=\d{1,9}$/, ''); el.setAttribute('href', new_href); }; let points_sales = document.querySelector('.users-point-sell'); for (const index in points_sales.children) { 'LI' === points_sales.children[index].tagName && rmv_cfm(points_sales.children[index]) } new MutationObserver(e => { for (const t of e) { // for (const e of t.addedNodes) { // 'LI' === e.tagName && rmv_cfm(e) // } t.addedNodes.forEach(e => 'LI' === (e as HTMLElement).tagName && rmv_cfm(e)) } }).observe(points_sales, { childList: true }); } // 叠e助手 if (href.includes('gym.php')) { let cont = null; const switch_node = document.createElement('div'); switch_node.innerHTML = ``; switch_node.id = 'wh-gym-info-cont'; switch_node.querySelector('input').onchange = e => { let target = e.target as HTMLInputElement; cont.classList.toggle('wh-display-none'); WuhuConfig.set('SEProtect', target.checked, true); }; Utils.elementReady('#gymroot').then(node => { cont = node; if (getWhSettingObj()['SEProtect']) node.classList.add('wh-display-none'); node.before(switch_node); }); } // 啤酒店 if (href.includes('shops.php?step=bitsnbobs')) { // 加入啤酒 elementReady('ul.items-list').then(node => { const add_btn_node = document.createElement('div'); add_btn_node.id = 'wh-gym-info-cont'; add_btn_node.innerHTML = `

如果当前商店没有啤酒这个商品可以提前显示以省去刷新步骤,增加抢酒成功率。

`; add_btn_node.querySelector('button').addEventListener('click', e => { const msg_node = add_btn_node.querySelector('#wh-msg'); if (node.querySelector('span[id="180-name"]')) { msg_node.innerHTML = '❌ 页面已经有啤酒了'; return; } const clear_node = node.querySelector('li.clear'); const beer = document.createElement('li'); beer.classList.add('torn-divider', 'divider-vertical'); beer.style.backgroundColor = '#c8c8c8'; beer.innerHTML = `
啤酒 $10 酒 (1100存货)
点击确定购买 100 瓶啤酒 $1,000 确定
`; if (clear_node) clear_node.before(beer); else node.append(beer); (e.target).remove(); msg_node.innerHTML = '添加成功'; }); document.querySelector('.content-wrapper').prepend(add_btn_node); }); // 监听啤酒购买 $(document).ajaxComplete((_, xhr, settings) => { Log.info({ xhr, settings }); let { data } = settings, { responseText } = xhr; let response = JSON.parse(responseText); if (data.includes('step=buyShopItem') && data.includes('ID=180') && response['success']) { new Alert('已检测成功购买啤酒') beer.skip_today(); } }); } // 快速crime TODO 重构、与翻译解藕 if (href.contains(/crimes\.php/) && getWhSettingObj()['quickCrime']) { if (self !== top) { const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate'); elementReady('#header-root').then(e => e.style.display = 'none'); elementReady('#sidebarroot').then(e => e.style.display = 'none'); elementReady('#chatRoot').then(e => e.style.display = 'none'); if (!isValidate) document.body.style.overflow = 'hidden'; elementReady('.content-wrapper').then(e => { e.style.margin = '0px'; e.style.position = 'absolute'; e.style.top = '-35px'; }); elementReady('#go-to-top-btn button').then(e => e.style.display = 'none'); } const $$ = document.querySelector('.content-wrapper'); const OB = new MutationObserver(() => { OB.disconnect(); // titleTrans(); // contentTitleLinksTrans(); trans(); OB.observe($$, { characterData: true, attributes: true, subtree: true, childList: true }); }); const trans = () => { const dom = `
常用犯罪

`; const is_wh_translate = $$.querySelector('.wh-translate') !== null; const is_captcha = $$.querySelector('div#tab-menu.captcha') !== null; const $title = $('div.content-title'); const $info = $('.info-msg-cont'); if (!is_wh_translate && !is_captcha) { if ($title.length > 0) $title.before(dom); else if ($info.length > 0) $info.before(dom); } }; trans(); OB.observe($$, { characterData: true, attributes: true, subtree: true, childList: true }); } // 任务助手 TODO 重构、与翻译解藕 if (href.contains(/loader\.php\?sid=missions/) && getWhSettingObj()['missionHint']) { const $$ = $('.content-wrapper'); const OB = new MutationObserver(() => { OB.disconnect(); // titleTrans(); // contentTitleLinksTrans(); trans(); OB.observe($$.get(0), { characterData: true, attributes: true, subtree: true, childList: true }); }); const taskList = {}; const trans = () => { $('ul#giver-tabs a.ui-tabs-anchor').each((i, e) => { if ($(e).children().hasClass('mission-complete-icon')) { taskList[i] = e.innerText.trim(); } else { taskList[i] = $(e).clone().children().remove().end().text().trim(); } }); // 助手注入 $('div.max-height-fix.info').each((i, e) => { if ($(e).find('.wh-translated').length !== 0) return; $(e).append(`
任务助手

${ getTaskHint(taskList[i]) }

`); }); // 任务目标 $('ul.tasks-list span.title-wrap').contents().each((i, e) => { if (e.nodeType === 3) { if (missionDict[e.nodeValue.trim()]) { e.nodeValue = missionDict[e.nodeValue.trim()]; } } }); }; trans(); OB.observe($$.get(0), { characterData: true, attributes: true, subtree: true, childList: true }); } // 圣诞小镇 if (href.contains(/christmas_town\.php/)) { let $root = document.querySelector('#christmastownroot'); const { xmasTownWT, xmasTownNotify } = getWhSettingObj() // 解密攻略 if (xmasTownWT) { const insert_html = `
水晶球解密地图攻略

`; const wt_dict = { "None": { title: '', wt: ``, }, "Christmas Town": { title: '圣诞小镇', wt: ``, }, "Maltese Snow Globe": { title: 'Maltese Snow Globe', wt: ``, }, "Long way from home": { title: 'Long way from home', wt: ``, }, "Chedburn Towers": { title: 'Chedburn Towers', wt: ``, }, "Kidnapped Santa": { title: 'Kidnapped Santa', wt: ``, }, "Holiday terror": { title: 'Holiday terror', wt: ``, }, "Among Us": { title: 'Among Us', wt: ``, }, "Kiss My Festivus": { title: 'Kiss My Festivus', wt: ``, }, "Stanley Hotel": { title: 'Stanley Hotel', wt: ``, }, "DoggoQuest": { title: 'DoggoQuest', wt: ``, }, "Pokemon CT": { title: 'Pokemon CT', wt: ``, }, "Winter in Gatlin": { title: 'Winter in Gatlin', wt: ``, }, }; const $city_wrapper = $root.querySelectorAll('div[class^="core-layout__"]'); $city_wrapper.forEach(el => { let $wh_container = $root.querySelector('#wh-xmas-cont'); if (!$wh_container) { $(el).prepend(insert_html); $wh_container = $root.querySelector('#wh-xmas-cont'); // 显示 隐藏 const jquery$wh_container = $($wh_container); const $cont_gray = jquery$wh_container.find('.cont-gray'); jquery$wh_container.find('button').click(e => { if (e.target.innerText === '[隐藏]') { $cont_gray.hide(); e.target.innerText = '[显示]'; } else { $cont_gray.show(); e.target.innerText = '[隐藏]'; } }); // 内容 const $wt_content = jquery$wh_container.find('#wt-content'); jquery$wh_container.find('select').change(e => { const selected = e.target.value; $wt_content.html(`

${ wt_dict[selected].title }

${ wt_dict[selected].wt }

`) }); } }); } // 宝箱检测 if (xmasTownNotify) { const chestTypeDict = { '1': '金', '2': '银', '3': '铜', }; const chestTypeColorDict = { '1': 'gold', '2': 'silver', '3': 'sandybrown', }; const lootTypeDict = { 'chests': '钥匙箱', 'gifts': '礼物', 'combinationChest': '密码箱', 'keys': '钥匙', }; const keyTypeDict = { 'b': '铜', 's': '银', 'g': '金', }; let dropHist = localStorage.getItem('wh-loot-store') ? JSON.parse(localStorage.getItem('wh-loot-store')) : {}; const alertSettings = localStorage.getItem('wh-loot-setting') ? JSON.parse(localStorage.getItem('wh-loot-setting')) : { blink: 'y', sound: 'y', chest: 'y' }; let $ct_wrap; let soundLoopFlag = false; const getDOMOb = new MutationObserver(() => { $ct_wrap = $root.querySelector('#ct-wrap'); if ($ct_wrap) { getDOMOb.disconnect(); const insert_html = `
附近物品
物品
箱子

- 长时间不清空会出现奇怪的问题

历史记录
坐标地图类型发现获取
`; $($ct_wrap).before(insert_html); const $wh_loot_container = $root.querySelector('#wh-loot-container') as HTMLElement; const $btn = $wh_loot_container.querySelector('#wh-loot-btn button') as HTMLButtonElement; const $clear_btn = $wh_loot_container.querySelector('#wh-hist-clear button') as HTMLButtonElement; const $ex = $wh_loot_container.querySelector('#wh-loot-container-ex'); const $tbody = $wh_loot_container.querySelector('tbody'); const $blink = $wh_loot_container.querySelector('#wh-loot-setting-blink') as HTMLInputElement; const $sound = $wh_loot_container.querySelector('#wh-loot-setting-sound') as HTMLInputElement; const $chest = $wh_loot_container.querySelector('#wh-loot-setting-chest') as HTMLInputElement; const $audio = $wh_loot_container.querySelector('audio'); $btn.onclick = e => { let target = e.target as HTMLButtonElement; target.innerText = target.innerText === '设置' ? '收起' : '设置'; $($ex).toggleClass('wh-hide'); target.blur(); }; $clear_btn.onclick = e => { let target = e.target as HTMLButtonElement; target.blur(); dropHist = {}; $tbody.innerHTML = ''; localStorage.setItem('wh-loot-store', JSON.stringify(dropHist)); }; $blink.onchange = e => { if ((e.target).checked) { alertSettings.blink = 'y'; if ($wh_loot_container.querySelector('#wh-loot-item-count').innerText !== '(0)') { ($wh_loot_container.querySelector('#wh-loot-container-main')).style.animation = 'lootFoundAlert 2s infinite'; } } else { alertSettings.blink = 'n'; ($wh_loot_container.querySelector('#wh-loot-container-main')).style.animation = ''; } localStorage.setItem('wh-loot-setting', JSON.stringify(alertSettings)); }; $sound.onchange = e => { if ((e.target).checked) { alertSettings.sound = 'y'; if ($wh_loot_container.querySelector('#wh-loot-item-count').innerText !== '(0)') { soundLoopFlag = true; } } else { alertSettings.sound = 'n'; soundLoopFlag = false; } localStorage.setItem('wh-loot-setting', JSON.stringify(alertSettings)); }; $chest.onchange = e => { alertSettings.chest = (e.target).checked ? 'y' : 'n'; localStorage.setItem('wh-loot-setting', JSON.stringify(alertSettings)); }; const soundIntervalID = window.setInterval(() => { if (soundLoopFlag) $audio.play().then(); }, 1200); ob.observe($root, { childList: true, subtree: true }); } }); const ob = new MutationObserver(() => { ob.disconnect(); // 页面刷新重新获取dom $root = document.querySelector('#christmastownroot'); $ct_wrap = $root.querySelector('#ct-wrap'); if (!$ct_wrap) { ob.observe($root, { childList: true, subtree: true }); return; } const $ct_title = $ct_wrap.querySelector('.status-title'); const $pos = $ct_wrap.querySelector('.map-title span[class^="position___"]') || $ct_wrap.querySelector('.status-title span[class^="position___"]'); if (!$pos) { ob.observe($root, { childList: true, subtree: true }); return; } const $pos_spl = $pos.innerText.trim().split(','); const player_position = { x: parseInt($pos_spl[0]), y: parseInt($pos_spl[1]), }; // player_position.x = parseInt($pos_spl[0]); // player_position.y = parseInt($pos_spl[1]); const $wh_loot_container = $root.querySelector('#wh-loot-container'); if (!$wh_loot_container) { console.error('掉落助手未找到DOM容器'); ob.observe($root, { childList: true, subtree: true }); return; } const $blink = $wh_loot_container.querySelector('#wh-loot-setting-blink') as HTMLInputElement; const $sound = $wh_loot_container.querySelector('#wh-loot-setting-sound') as HTMLInputElement; const $chest = $wh_loot_container.querySelector('#wh-loot-setting-chest') as HTMLInputElement; const $tbody = $wh_loot_container.querySelector('tbody'); const nearby_arr = []; const items = $root.querySelectorAll('div.grid-layer div.items-layer div.ct-item'); // 附近的所有物品 items.forEach(el => { const item_props = { x: 0, y: 0, name: '', type: '', url: '', }; item_props.x = parseInt((el).style.left.replaceAll('px', '')) / 30; item_props.y = -parseInt((el).style.top.replaceAll('px', '')) / 30; item_props.url = el.firstElementChild.src; const srcSpl = item_props.url.trim().split('/'); item_props.name = srcSpl[6]; item_props.type = srcSpl[8].slice(0, 1); nearby_arr.push(item_props); }); const $wh_loot_container_items = $wh_loot_container.querySelector('#wh-loot-container-items'); const $wh_loot_container_chests = $wh_loot_container.querySelector('#wh-loot-container-chests'); let item_count = 0, chest_count = 0; $wh_loot_container_items.innerHTML = ''; $wh_loot_container_chests.innerHTML = ''; nearby_arr.forEach(nearby_item => { let path = '='; if (nearby_item.x < player_position.x && nearby_item.y < player_position.y) path = '↙'; else if (nearby_item.x < player_position.x && nearby_item.y === player_position.y) path = '←'; else if (nearby_item.x < player_position.x && nearby_item.y > player_position.y) path = '↖'; else if (nearby_item.x === player_position.x && nearby_item.y > player_position.y) path = '↑'; else if (nearby_item.x > player_position.x && nearby_item.y > player_position.y) path = '↗'; else if (nearby_item.x > player_position.x && nearby_item.y === player_position.y) path = '→'; else if (nearby_item.x > player_position.x && nearby_item.y < player_position.y) path = '↘'; else if (nearby_item.x === player_position.x && nearby_item.y < player_position.y) path = '↓'; let item_name; if (nearby_item.name === 'chests') { chest_count++; item_name = chestTypeDict[nearby_item.type] + lootTypeDict[nearby_item.name]; $wh_loot_container_chests.innerHTML += `${ path }[${ nearby_item.x },${ nearby_item.y }] ${ item_name }` } else { item_count++; item_name = (nearby_item.name === 'keys' ? keyTypeDict[nearby_item.type] || '' : '') + lootTypeDict[nearby_item.name] || nearby_item.name; $wh_loot_container_items.innerHTML += `${ path }[${ nearby_item.x },${ nearby_item.y }] ${ item_name }` } // 确认地图坐标存在 if ($ct_title) { const hist_key = `[${ nearby_item.x },${ nearby_item.y }]"${ $ct_title.firstChild.nodeValue.trim() }"${ item_name }`; const el = dropHist[hist_key]; if (el) { if (path === '=' && (nearby_item.name === 'keys' || nearby_item.name === 'gifts')) { el.isPassed = true; } } else { if (!(nearby_item.name === 'chests' && $chest.checked)) { const now = new Date(); dropHist[hist_key] = { pos: `[${ nearby_item.x },${ nearby_item.y }]`, map: $ct_title.firstChild.nodeValue.trim(), last: `${ now.getFullYear() }-${ now.getMonth() + 1 }-${ now.getDate() } ${ now.getHours() }:${ now.getMinutes() }:${ now.getSeconds() }`, name: item_name, id: Object.keys(dropHist).length, }; } } } }); $wh_loot_container.querySelector('#wh-loot-item-count').innerText = `(${ item_count })`; if (item_count === 0) { $wh_loot_container_items.innerText = '暂无'; ($wh_loot_container.querySelector('#wh-loot-container-main')).style.animation = ''; soundLoopFlag = false; } else { if ($blink.checked) ($wh_loot_container.querySelector('#wh-loot-container-main')).style.animation = 'lootFoundAlert 2s infinite'; if ($sound.checked) soundLoopFlag = true; } $wh_loot_container.querySelector('#wh-loot-chest-count').innerText = `(${ chest_count })`; if (chest_count === 0) $wh_loot_container_chests.innerText = '暂无'; const history = Object.keys(dropHist).map(key => dropHist[key]).sort((a, b) => a.id - b.id); let table_html = ''; history.forEach(e => { table_html += `${ e.pos }${ e.map }${ e.name }${ e.last }${ e.isPassed ? '已取得' : '不确定' }`; }); $tbody.innerHTML = table_html; localStorage.setItem('wh-loot-store', JSON.stringify(dropHist)); ob.observe($root, { childList: true, subtree: true }); }); getDOMOb.observe($root, { childList: true, subtree: true }); } } // rw雷达 if (href.includes('profiles.php?XID=0')) { const utl = { set: function (k, v) { const obj = JSON.parse(localStorage['wh_rw_raider']) || {}; obj[k] = v; localStorage['wh_rw_raider'] = JSON.stringify(obj); }, get: function (k) { const obj = JSON.parse(localStorage['wh_rw_raider']) || {}; return obj[k]; }, setFactionID: function (id) { this.set('faction', id); }, setRWFactionID: function (id) { this.set('rw_faction', id); }, getFactionID: async function (apikey) { const response = await fetch('https://api.torn.com/faction/?selections=basic&key=' + apikey); const res_obj = await response.json(); const faction_id = res_obj['ID']; if (faction_id) { this.setFactionID(faction_id); return faction_id; } else return -1; }, getRWFactionID: function (apikey) { }, }; const rw_raider = async function () { if (href.includes('#rader')) { Utils.addStyle('div.content-title,div.info-msg-cont{display:none;}'); const wh_node = document.createElement('div'); wh_node.id = 'wh-rd-cont'; wh_node.innerHTML = `

RW 雷达


woohoo
123456
789012
`; // 原页面完全加载 await elementReady('div.msg[role="alert"]'); const t_cont = document.querySelector('div.content-wrapper'); // t t_cont.append(wh_node); } }; addEventListener('hashchange', rw_raider); rw_raider().then(); } // 特定代码块 TODO 修复 if (InfoUtils.getInstance().getPlayerInfo().userID === 2687093 && Utils.getDeviceType() === Device.PC) { InfoUtils.getInstance().getSidebarData().then(data => { Log.info({ data }) let item = document.getElementById('nav-items'); if (item) { let copy = item.cloneNode(true); // TODO 待验证 (copy.firstChild).style.backgroundColor = '#ff5722'; // copy.firstChild.style.backgroundColor = '#ff5722'; let a = copy.firstChild.firstChild as HTMLAnchorElement; a.href = '/item.php?temp=1'; let span = a.lastChild as HTMLElement; span.innerHTML = '物品'; span.style.color = 'white'; item.after(copy); } }); } } }