import init from "./init"; import { titleDict, titleLinksDict, sidebarDict, // tooltipDict, statusDict, // miniProfileDict, homeDict, attackDict, newspaperDict, propertyDict, travelingDict, tipsDict, cityDict, gymDict, gymList, eduDict, headerDict, eventsDict, chatDict, hosDict, awDict, // playerTitleList, ocList, profileDict, sendCashDict, stockDict, itemPageDict, itemNameDict, // itemDescDict, itemEffectDict, itemTypeDict, // itemReqDict, tornSettingsDict, missionDict, pcDict, npcShopDict, calDict, CC_set, } from './dictionary/translation'; import Device from "./enum/Device"; import UserScriptEngine from "./enum/UserScriptEngine"; import getPlayerInfo from "./function/utils/getPlayerInfo"; import autoFetchJSON from "./function/utils/autoFetchJSON"; export default function userscript(): void { const start_timestamp: number = Date.now(); if (document.title.toLowerCase().includes('just a moment')) return; let {version, isIframe, $, PDA_APIKey, isPDA} = init(); const date = new Date(); const device = window.innerWidth >= 1000 ? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET; // 玩家信息 const player_info = getPlayerInfo(); // 海外库存对象 const fstock = autoFetchJSON('https://yata.yt/api/v1/travel/export/'); // 价格监视实例对象 const priceWatcher = isIframe ? null : priceWatcherHandle(); // 返回一个加载中gif图形HTML const loading_gif_html = () => { const gif_base64 = `data:image/svg+xml,%3Csvg t='1656084442571' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3924' width='14' height='14'%3E%3Cpath d='M512.032002 237.105181a29.310168 29.310168 0 0 1-29.310168-29.246172V29.310168a29.310168 29.310168 0 0 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 237.105181zM512.032002 1024a29.310168 29.310168 0 0 1-29.310168-29.310168v-178.484845a29.310168 29.310168 0 1 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 1024z m482.657834-482.657834h-178.484845a29.310168 29.310168 0 1 1 0-58.620336h178.548841a29.310168 29.310168 0 1 1 0 58.620336z m-786.830823 0H29.310172a29.310168 29.310168 0 0 1 0-58.620336h178.548841a29.310168 29.310168 0 0 1 0 58.620336z m519.263546-215.090557a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412 41.405412l-126.264108 126.264108a29.182176 29.182176 0 0 1-20.670708 8.575464zM170.741333 882.568839a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.246172 29.246172 0 1 1 41.405412 41.405412L191.412041 874.057371a29.182176 29.182176 0 0 1-20.670708 8.575464z m682.581338 0a29.182176 29.182176 0 0 1-20.670708-8.575464l-126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688zM297.005441 326.251609a29.182176 29.182176 0 0 1-20.670708-8.575464L150.006629 191.412037a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688z' p-id='3925'%3E%3C/path%3E%3C/svg%3E` return `lgif`; } // 抢啤酒 let beer = buyBeer(); let popup_node = null; // 当窗口关闭时关闭所有还存在的通知 let notifies = {count: 0}; window.addEventListener( 'beforeunload', () => { if (notifies.count !== 0) { for (let i = 0; i < notifies.count; i++) { (notifies[i] !== null) && (notifies[i].close()) } } } ); // 引入rfc方法 let addRFC = window['addRFC']; // 记录当前窗口唯一id const isWindowActive = getWindowActiveState(); // 对新值应用「默认」设置 [ // 开启翻译 {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 getWhSettingObj()[df.key] !== typeof df.val) setWhSetting(df.key, df.val); }); // region 助手各项「设置」 let setting_list = []; // 12月时加入圣诞小镇选项 if (date.getMonth() === 11) { setting_list.push({ domType: 'plain', domId: '', domHTML: '圣诞小镇', tagName: 'h4', }) setting_list.push({ domType: 'checkbox', domId: 'wh-xmastown-wt', domText: ' 圣诞小镇攻略', dictName: 'xmasTownWT', isHide: true, }); setting_list.push({ domType: 'checkbox', domId: 'wh-xmastown-notify', domText: ' 圣诞小镇物品提示', dictName: 'xmasTownNotify', isHide: true, }); } // 翻译 setting_list.push({ domType: 'plain', domId: '', domHTML: '翻译', tagName: 'h4', }); // 开启翻译 setting_list.push({ domType: 'checkbox', domId: 'wh-trans-enable', domText: ' 开启翻译', dictName: 'transEnable', isHide: true, }); // 更新翻译词库 setting_list.push({ domType: 'button', domId: '', domText: '更新翻译词库', clickFunc: updateTransDict }); // 战斗优化 setting_list.push({ domType: 'plain', domId: '', domHTML: '战斗优化', tagName: 'h4', }); // 光速拔刀 setting_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按钮移动到指定格子上', }); // 光速跑路 setting_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: '将结束后指定按钮移动到上面指定的格子上', }); // 攻击链接转跳 setting_list.push({ domType: 'checkbox', domId: 'wh-attack-relocate', domText: ' 真·攻击界面转跳', dictName: 'attRelocate', tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面', isHide: true, }); // 飞行 setting_list.push({ domType: 'plain', domId: '', domHTML: '飞行', tagName: 'h4', }); // 起飞警告 setting_list.push({ domType: 'checkbox', domId: 'wh-energy-alert', domText: ' 起飞爆E警告', dictName: 'energyAlert', tip: '起飞前计算来回是否会爆体,红字警告', isHide: true, }); // 飞行闹钟 setting_list.push({ domType: 'checkbox', domId: 'wh-trv-alarm-check', domText: ' 飞行闹钟', dictName: 'trvAlarm', tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限', isHide: true, }); // 海外警告 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 海外警告', dictName: 'abroadWarning', tip: '海外落地后每30秒通知警告', }); // 落地转跳 setting_list.push({domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect}); // 公司 setting_list.push({ domType: 'plain', domId: '', domHTML: '公司', tagName: 'h4', }); // 浮动存钱框 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 浮动存钱框', dictName: 'floatDepo', tip: '打开公司或帮派的存钱页面后存钱框将浮动显示', }); // 公司转跳存钱 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 公司转跳存钱', dictName: 'companyRedirect', tip: '打开公司页面时自动打开存钱选项卡', }); // 收起公司冰蛙效率表 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 收起公司冰蛙效率表', dictName: 'companyBWCollapse', tip: '开启后可手动显示隐藏冰蛙公司表格', }); // 任何位置一键存钱 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 任何位置一键存钱', dictName: 'companyDepositAnywhere', tip: '在所有页面显示一键存钱按钮,Torn OK状态下可用,此功能未完全测试无害,使用请慎重', }); // 啤酒 setting_list.push({ domType: 'plain', domId: '', domHTML: '啤酒', tagName: 'h4', }); // 啤酒提醒 setting_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(); }, }); // 啤酒提醒状态 setting_list.push({ domType: 'button', domId: '', domText: '啤酒提醒状态', clickFunc: function () { WHNotify(`啤酒提醒${beer.status()}`); } }); // 啤酒提醒时间 setting_list.push({ domType: 'button', domId: '', domText: '啤酒提醒时间设定', // tip: '通知提前时间', clickFunc: function () { popup_node.close(); let popup = popupMsg(`

区间为 1 ~ 60,默认 50

`, '啤酒提醒时间设定'); let confirm = document.createElement('button'); confirm.innerHTML = '确定'; confirm.style.float = 'right'; confirm.addEventListener('click', () => { let input = popup.querySelector('input'); let num = input.value | 0; if (num === getWhSettingObj()['_15AlarmTime']) return; if (num < 1 || num > 60) num = 50; input.value = num.toString(); setWhSetting('_15AlarmTime', num); // 之前的运行状态 let before_state = beer.is_running(); beer.set_time(num); if (before_state) beer.start(); popup.close(); }); popup.appendChild(confirm); }, }); // 其他 setting_list.push({ domType: 'plain', domId: '', domHTML: '其他', tagName: 'h4', }); // 任务助手 setting_list.push({ domType: 'checkbox', domId: 'wh-mission-lint', domText: ' 任务助手', dictName: 'missionHint', tip: 'Duke任务的一些中文小提示', isHide: true, }); // 捡垃圾助手 setting_list.push({ domType: 'checkbox', domId: 'wh-city-finder', domText: ' 捡垃圾助手', dictName: 'cityFinder', tip: '城市地图中放大显示物品并且估计价值', isHide: true, }); // 快速crime setting_list.push({ domType: 'checkbox', domId: 'wh-quick-crime', domText: ' 快速犯罪', dictName: 'quickCrime', tip: '显示快捷操作按钮,目前不支持自定义', isHide: true, }); // 叠E保护 setting_list.push({ domType: 'checkbox', domId: 'wh-SEProtect-check', domText: ' 叠E保护', dictName: 'SEProtect', tip: '隐藏健身房的锻炼按钮,防止误操作', isHide: true, }); // PT一键购买 setting_list.push({ domType: 'checkbox', domId: 'wh-ptQuickBuy-check', domText: ' PT一键购买', dictName: 'ptQuickBuy', tip: 'PT市场页面购买时跳过确认', isHide: true, }); // 4条转跳 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 4条转跳', dictName: 'barsRedirect', tip: '点击4条时转跳对应页面', }); // 清除多余的脚本 setting_list.push({ domType: 'checkbox', domId: '', domText: ' 清除多余的脚本', dictName: 'removeScripts', tip: '清除Google相关脚本、顶部横幅等', }); // 危险行为⚠️ if (getWhSettingObj()['dangerZone'] === true) { // 攻击界面自刷新 setting_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: '危险功能:接机时常用,将自动刷新页面直到目标落地', }); // 自动开打和结束 setting_list.push({ domType: 'checkbox', domId: 'wh-auto-start-finish', domText: ' ⚠️自动开打和结束', dictName: 'autoStartFinish', tip: '脚本将会自动按下战斗和结束按钮', isHide: true, }); } else { setWhSetting('autoStartFinish', false, false) setWhSetting('attReload', 6, false) } // dev setting_list.push({ domType: 'checkbox', domId: 'wh-dev-mode', domText: ` 开发者模式${isDev() ? ' ' : ''}`, dictName: 'isDev', isHide: true, }); // 更多设定 if (isDev()) setting_list.push({ domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => { const html = `清空设置数据、请求通知权限、测试跨域请求`; const popup = popupMsg(html, '更多设定'); }, isHide: true, }); // endregion // region 菜单中的「选项」 const menu_list = []; //const date = new Date(2022, 2, 4, 23); // 欢迎 显示玩家id if (player_info.userID !== 0) { menu_list.push({ domType: 'plain', domId: 'wh-trans-welcome', domHTML: `欢迎 ${player_info.playername}[${player_info.userID}] 大佬`, }); } // 节日 let fest_date_html = ': '; { const fest_date_dict = { '0105': {name: '周末自驾游', eff: '获得双倍的赛车点数与赛车技能等级增益'}, '0114': {name: '情人节', eff: '使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益'}, '0204': {name: '员工激励日', eff: '获得三倍的工作点数与火车增益'}, '0217': {name: '圣帕特里克日', eff: '获得双倍的酒类效果增益,城市中可以捡到绿色世涛(Green Stout)'}, '0320': {name: '420日', eff: '获得三倍的大麻(Cannabis)效果增益'}, '0418': {name: '博物馆日', eff: '获得10%提高的博物馆PT兑换增益'}, '0514': {name: '世界献血日', eff: '获得减半的抽血CD和扣血增益'}, '0611': {name: '世界人口日', eff: '获得双倍的通过攻击获取的经验的增益'}, '0629': {name: '世界老虎日', eff: '获得5倍的狩猎技能增益'}, '0705': {name: '国际啤酒节', eff: '获得5倍的啤酒物品效果增益'}, '0827': {name: '旅游节', eff: '获得双倍的起飞后物品携带容量增益'}, '0915': {name: '饮料节', eff: '获得双倍的能量饮料效果增益'}, '1014': {name: '世界糖尿病日', eff: '获得三倍的糖类效果增益'}, '1015': {name: '周年庆', eff: '左上角的TORN图标可以食用'}, '1025': {name: '黑色星期五', eff: '某些商家将提供1元购活动'}, '1114': {name: '住院日', eff: '获得降低75%的住院时间增益'}, }; menu_list.fest_date_dict = fest_date_dict; menu_list.fest_date_list = Object.keys(fest_date_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 (fest_date_dict[fest_date_key]) fest_date_html += `今天 - ${fest_date_dict[fest_date_key]['name']}()`; else { // 月日列表 let fest_date_list = Object.keys(fest_date_dict); fest_date_list.push(fest_date_key); // 下个节日的位置 const next_fest_date_index = fest_date_list.sort().indexOf(fest_date_key) + 1; // 下个节日obj const next_fest_date = fest_date_dict[fest_date_list[next_fest_date_index] || fest_date_list[0]]; // 下个节日的时间 const days_left = (new Date( next_fest_date_index !== fest_date_list.length ? date.getUTCFullYear() : date.getUTCFullYear() + 1, fest_date_list[next_fest_date_index !== fest_date_list.length ? next_fest_date_index : 0].slice(0, 2) / 1, fest_date_list[next_fest_date_index !== fest_date_list.length ? next_fest_date_index : 0].slice(2) / 1, 8 ) - date) / 86400000 | 0; fest_date_html += `${days_left}天后 - ${next_fest_date.name}()`; } } menu_list.push({ domType: 'plain', domId: 'wh-trans-fest-date', domHTML: fest_date_html, }); // 活动 let eventObj = { onEv: false, daysLeft: Infinity, events: [ { start: [0, 17, 8], end: [0, 24, 8], name: '捡垃圾周', eff: '获得捡垃圾概率提升的增益', }, { start: [3, 5, 20], end: [3, 25, 20], name: '复活节狩猎', eff: '复活节彩蛋会随机出现,集齐10个可兑换金蛋和一个独特的头像框(章)。', }, { start: [5, 20, 20], end: [5, 29, 20], name: '狗牌', eff: '击败其他玩家以获得狗牌,小心保护你的狗牌。', }, { start: [6, 5, 20], end: [6, 25, 20], name: '托恩先生和托恩女士', eff: '上传你的真实图片,然后拿章', }, { start: [8, 5, 20], end: [8, 23, 20], name: '大逃杀', eff: '加入特定队伍后,攻击其他队伍玩家,存活下来的3个队伍可以拿章', }, { start: [9, 25, 20], end: [10, 1, 20], name: '不给糖就捣蛋', eff: '买篮子之后攻击其他玩家后会随机掉落糖果,可用于兑换许多高价值物品', }, { start: [11, 14, 20], end: [11, 31, 20], name: '圣诞小镇', eff: '在小镇中闲逛来获取随机掉落的物品', }, ], }; menu_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 - date) / 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 - date) / 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}()`; menu_list.push({ domType: 'plain', domId: 'wh-trans-event-cont', domHTML: eventObj.html, }); // 飞花库存 menu_list.push({ domType: 'button', domId: 'wh-foreign-stock-btn', domText: '🌸 飞花库存', clickFunc: async function (e) { e.target.blur(); forStock().then(); }, }); // 一键起飞 menu_list.push({ domType: 'button', domId: 'wh-quick-fly-btn', domText: '✈️ 一键起飞', clickFunc: async function () { if (window.hasWHQuickFlyOpt) return; window.hasWHQuickFlyOpt = true; addStyle(`#wh-quick-fly-opt{ position:fixed; left:64px; top:64px; background: #008000db; padding: 8px; border-radius: 4px; box-shadow: 0 0 5px 1px #ffffff29; color: white; font-size: 15px; width: 220px; z-index: 199999; } #wh-quick-fly-opt p{margin:4px 0;} #wh-quick-fly-opt a{ cursor: pointer; border: 1px solid; padding: 4px; display: inline-block; border-radius: 2px; } #wh-quick-fly-opt label{ display:block; } #wh-quick-fly-opt select{ width: 100%; padding: 6px; margin: 4px 0; } #wh-quick-fly-opt button{ font-size: 16px; color: white; cursor: pointer; float: right; background: #00BCD4; padding: 8px; border-radius: 4px; } #wh-quick-fly-opt.wh-quick-fly-opt-hide *{ display: none; } #wh-quick-fly-opt.wh-quick-fly-opt-hide input{ display: inline-block; } info{display:block;} `); const node = document.createElement('div'); node.id = 'wh-quick-fly-opt'; node.innerHTML = `

主要用途:出院秒飞

点起飞,页面加载完成后会马上飞走


查看花偶库存

注:需要验证时无法起飞

`; const [dest_node, type_node] = node.querySelectorAll('select'); node.querySelector('button').addEventListener('click', () => { sessionStorage['wh-quick-fly'] = `${dest_node.selectedIndex} ${type_node.selectedIndex} ${new Date().getTime()}`; if (!href.contains('travelagency.php')) { WHNotify('正在转跳'); location.href = 'https://www.torn.com/travelagency.php'; } else { doQuickFly(); } }); node.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); forStock(); }); node.querySelector('input').addEventListener('click', (e) => { node.classList.toggle('wh-quick-fly-opt-hide'); const el = e.target; 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剩余:${getYaoCD()}`; }, }); // NPC LOOT menu_list.push({ domType: 'button', domId: 'wh-npc-loot-btn', domText: '🔫 LOOT', clickFunc: function (e) { e.target.blur(); const insert = `

点击开打:

stock.png
`; popupMsg(insert, 'NPC LOOT'); }, tip: '显示5个可击杀NPC的开打时间', }); // 查看NNB menu_list.push({ domType: 'button', domId: 'wh-nnb-info', domText: '👮‍ 查看NNB', clickFunc: function (e) { e.target.blur(); const insert = `

NNBNatural Nerve Bar)意思是:扣除所有加成后,玩家本身的犯罪条上限,可用于衡量大佬隐藏的犯罪技能等级

一般来说,左侧红色的犯罪条(Nerve Bar/NB)的上限都是包含加成的,如来自帮派、天赋的加成等。额外的加成不会影响玩家的犯罪技能

查看NNB的方法很简单,在Torn主页面的最下方有一栏Perks,NB-Perks=NNB

以下是两种计算NNB的方法:

`; const popup = popupMsg(insert, '查看NNB'); const select = popup.querySelector('input'); const node = popup.querySelector('p'); popup.querySelector('button').addEventListener('click', ev => { ev.target.style.display = 'none'; node.innerHTML = '加载中'; // API 计算 if (select.checked) { const api_key = isPDA ? PDA_APIKey : window.localStorage.getItem('APIKey'); fetch(`https://api.torn.com/user/?selections=bars,perks&key=${api_key}`) .then(res => res.json()) .then(data => { if (data['error']) { node.innerHTML = `出错了 ${Obj2Str(data['error'])}`; ev.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 += /[0-9]./.exec(s)[0] | 0) }) }); node.innerHTML = `NNB: ${nb - perks}`; ev.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)[0] | 0) }); node.innerHTML = `NNB: ${nb - perks}`; ev.target.style.display = null; return; } node.innerHTML = '不在主页面,点击前往'; ev.target.style.display = null; } }); }, }); // 常用链接 menu_list.push({ domType: 'button', domId: 'wh-link-collection', domText: '🔗 常用链接', clickFunc: function (e) { if (!this.styleAdded) { addStyle(` .wh-link-collection-cont a{ display: inline-block; border: solid 1px #b3b3b3; border-radius: 4px; margin: 0 5px 2px 0; padding: 4px 8px; text-align:center; background: #efefef; background: linear-gradient(#f1f1f1,#e3e3e3); color:black !important; } .wh-link-collection-cont span{ display: block; /*padding: 0 4px 8px;*/ } .wh-link-collection-cont .wh-link-collection-img{ display: block; width:60px; height:30px; background-size: 100% auto !important; } `); 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 = popupMsg(insert, '常用链接'); popup.classList.add('wh-link-collection-cont'); popup.addEventListener('click', ev => { if (ev.target.tagName.toLowerCase() === 'a' || ev.target.tagName.toLowerCase() === 'span') { popup.close(); } }); }, }); // 飞贼 menu_list.push({ domType: 'button', domId: 'wh-gs-btn', domText: '🐏 飞贼小助手', clickFunc: function (e) { e.target.blur(); loadGS(getScriptEngine()); }, tip: '加载从PC端移植的伞佬的油猴版飞贼小助手', }); // 物品价格监视 menu_list.push({ domType: 'button', domId: 'wh-price-watcher-btn', domText: '💊 价格监视', clickFunc: function () { const watcher_conf = getWhSettingObj()['priceWatcher']; const pre_str = JSON.stringify(watcher_conf); const html = `

输入需要监视的价格,低于该价格发出通知,-1为关闭

注:需要APIKey,当前可用APIKey为
(来自冰蛙)
(来自PDA)

PT

XAN

`; const popup = popupMsg(html, '价格监视设置'); popup.querySelector('button').onclick = () => { const [pt_node, xan_node] = popup.querySelectorAll('input[type="number"]'); watcher_conf.pt = pt_node.value | 0; watcher_conf.xan = xan_node.value | 0; if (JSON.stringify(watcher_conf) !== pre_str) setWhSetting('priceWatcher', watcher_conf); popup.close(); }; } }); // 小窗犯罪 menu_list.push({ domType: 'button', domId: 'wh-crime-iframe-btn', domText: '🤑 小窗犯罪', clickFunc: function () { // 弹出小窗口 const ifHTML = ``; const popup_insert = `

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

`; const $popup = popupMsg(popup_insert, '小窗快速犯罪'); // 运行状态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 = `
快捷操作:

`; // 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) { // 隐藏顶部 elementReady('#header-root', ifDocu).then(e => e.style.display = 'none'); // 隐藏4条 elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none'); // 隐藏聊天 elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none'); // 非验证码页面隐藏滚动条 if (!isValidate) ifDocu.body.style.overflow = 'hidden'; // 调整容器位置 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}); }); // 隐藏返回顶部按钮 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); } }); // 危险行为开关⚠️ menu_list.push({ domType: 'button', domId: 'wh-danger-zone', domText: '⚠️ 危险功能', clickFunc: function (e) { e.target.blur(); const insert = `

即将打开危险功能,使用这些功能可能会造成账号封禁。请自行考虑是否使用。

`; const popup = popupMsg(insert, '⚠️警告'); const warning_check = popup.querySelector('input'); const ok_btn = popup.querySelector('button'); warning_check.onchange = () => ok_btn.disabled = false; ok_btn.onclick = () => { setWhSetting('dangerZone', warning_check.checked); popup['close'](); window.location.reload(); }; }, }); // 传单助手 menu_list.push({ domType: 'button', domId: '', domText: '📜️ 传单助手', clickFunc: adHelper }); // 守望者 menu_list.push({ domType: 'button', domId: '', domText: '🛡️ 守望者', clickFunc: function () { safeKeeper(); }, }); // 更新历史 menu_list.push({ domType: 'button', domId: '', domText: '🐞 更新历史', clickFunc: () => { popupMsg('更新历史现已迁移:
https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md', '更新历史'); }, }); // 助手设置 menu_list.push({ domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => { $zhongNode.setting_root = document.createElement('div'); $zhongNode.setting_root.classList.add('gSetting'); setting_list.forEach(set => elemGenerator(set, $zhongNode.setting_root)); let pop = popupMsg('', '芜湖助手设置'); pop.appendChild($zhongNode.setting_root); // 本日不提醒 $zhongNode.setting_root.querySelector('#wh-qua-alarm-check-btn').addEventListener('click', beer.skip_today); // 开发详情按钮 if (isDev()) $zhongNode.setting_root.querySelector('button#wh-devInfo').onclick = () => { const date = new Date(); let os = '未知'; try { os = window.navigator.userAgentData.platform || window.navigator.platform } catch { } const insert = `
URL${window.location.href}
页面尺寸${window.innerWidth}x${window.innerHeight}
设备类型${getDeviceType().toUpperCase()}
脚本运行方式${{'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA'}[getScriptEngine()]}
时间${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}
插件版本${version}
操作系统${os}
UA${window.navigator.userAgent}
用户ID${player_info.userID}
用户名${player_info.playername}
`; pop['close'](); popupMsg(insert, '开发者详情'); }; (window['initializeTooltip']) && (window['initializeTooltip']('#wh-popup-cont', 'white-tooltip')); }, }); // 测试 if (isDev()) menu_list.push({ domType: 'button', domId: '', domText: '📐️ 测试', clickFunc: function () { WHNotify('芜湖助手', {sysNotify: true, timeout: 15}) }, }); // endregion // 菜单node const $zhongNode = initIcon(menu_list); addStyle(` .wh-hide{display:none;} #wh-trans-icon{ user-select:none; display: inline-block; position: fixed; top:5px; left:5px; z-index:100010; border-radius:4px; max-width: 220px; box-shadow: 0 0 3px 1px #8484848f; } div#effectiveness-wrap{overflow-y:hidden;} @media screen and (max-width: 600px) { #wh-trans-icon{top:0;left:112px;} /* 冰蛙公司效率表 */ div#effectiveness-wrap { margin-left: -80px; margin-right: -76px; } } #wh-trans-icon select{width:110px;} #wh-trans-icon a { text-decoration: none; color: #006599; background: none; } #wh-trans-icon:not(.wh-icon-expanded):hover {background: #f8f8f8;} #wh-trans-icon button{ margin:0; padding:0; border:0; cursor:pointer; } #wh-inittimer{margin-top:6px;color:#b0b0b0;} #wh-gSettings div{margin: 4px 0;} #wh-trans-icon .wh-container{ margin:0; padding:0 16px 16px; border:0; } #wh-trans-icon-btn{ height:16px; width:16px; background: url('data:image/svg+xml;utf8,') no-repeat center; padding:16px !important; } #wh-trans-icon .wh-container{display:none;} #wh-trans-icon.wh-icon-expanded .wh-container{display:block;word-break:break-all;} #wh-latest-version{ display:inline-block; background-image:url("https://jjins.github.io/t2i/version.png?${performance.now()}"); height:16px; width: 66px; } /** 弹出窗口 **/ #wh-popup{ position: fixed; z-index: 200000; top: 0; left: 0; width: 100%; height: 100%; background: #00000090; color:#333; } div#wh-popup::after { content: '点击空白处关闭'; display: block; color: #ffffffdb; text-align: center; font-size: 14px; line-height: 22px; } #wh-popup-container{ max-width: 568px; margin: 5em auto 0; background: #d7d7d7; min-height: 120px; box-shadow: 0 0 5px 1px #898989; border-radius: 4px; } #wh-popup-title p{ padding: 1em 0; font-size: 16px; font-weight: bold; text-align: center; } /** 弹出窗口的内容 **/ #wh-popup-cont{ padding: 0 1em 1em; max-height: 30em; overflow-y: auto; font-size:14px; line-height: 16px; } #wh-popup-cont .gSetting > div{ display: inline-block; width: 47%; margin: 2px 0; } #wh-popup-cont .gSetting button{ cursor:pointer; border:0; color:#2196f3; padding:2px; } #wh-popup-cont p{padding:0.25em 0;} #wh-popup-cont a{color:red;text-decoration:none;} #wh-popup-cont li{margin:4px 0;} #wh-popup-cont h4{margin:0;padding: 0.5em 0;} #wh-popup-cont button{ margin: 0 4px 0 0; padding: 5px 8px; border: solid 2px black; color: black; border-radius: 3px; } #wh-popup-cont button[disabled]{opacity: 0.5;} #wh-popup-cont input{ padding: 2px; text-align: center; border: 1px solid #fff0; border-radius: 5px; margin:1px 2px; } #wh-popup-cont input:focus{border-color:blue;} #wh-popup-cont table{width:100%;border-collapse:collapse;border:1px solid;} #wh-popup-cont td, #wh-popup-cont th{border-collapse:collapse;padding:4px;border:1px solid;} .wh-display-none{display:none !important;} #wh-gym-info-cont{ background-color: #363636; color: white; padding: 8px; font-size: 15px; border-radius: 4px; text-shadow: 0 0 2px black; background-image: linear-gradient(90deg,transparent 50%,rgba(0,0,0,.07) 0); background-size: 4px; line-height: 20px; } #wh-gym-info-cont button{ cursor:pointer; } `); if ('Ok' !== localStorage['WHTEST']) { if (!(player_info.userID | 0 === -1 || player_info.playername === '未知')) { COFetch(atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), atob('cG9zdA=='), `{"uid":"${player_info.userID}","name":"${player_info.playername}"}`) .then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok')); } } const href = window.location.href; // 开启翻译 transToZhCN(href, getWhSettingObj()['transEnable']); // 啤酒提醒 不终止 if (getWhSettingObj()['_15Alarm']) beer.start(); // 点击4条转跳对应的页面 不终止 if (getWhSettingObj()['barsRedirect']) { const eb = document.getElementById('barEnergy'); const nb = document.getElementById('barNerve'); const hb = document.getElementById('barHappy'); const lb = document.getElementById('barLife'); if (eb) { eb.addEventListener('click', () => location.href = '/gym.php'); eb.href = '/gym.php'; } else { elementReady('#barEnergy').then(eb => { eb.addEventListener('click', () => location.href = '/gym.php'); eb.href = '/gym.php'; }); } if (nb) { nb.addEventListener('click', () => location.href = '/crimes.php'); nb.href = '/crimes.php'; } else { elementReady('#barNerve').then(nb => { nb.addEventListener('click', () => location.href = '/crimes.php'); nb.href = '/crimes.php'; }); } if (hb) { hb.addEventListener('click', () => location.href = '/item.php#boosters-items'); hb.href = '/item.php#boosters-items'; } else { elementReady('#barHappy').then(hb => { hb.addEventListener('click', () => location.href = '/item.php#boosters-items'); hb.href = '/item.php#boosters-items'; }); } if (lb) { lb.addEventListener('click', () => location.href = '/item.php#medical-items'); lb.href = '/item.php#medical-items'; } else { elementReady('#barLife').then(lb => { lb.addEventListener('click', () => location.href = '/item.php#medical-items'); lb.href = '/item.php#medical-items'; }); } } // 清除多余的脚本 if (getWhSettingObj()['removeScripts']) { let goog = document.querySelector('script[src*="google"]'); (goog) && (goog.remove()); let goog2 = document.querySelector('#gtm_tag'); (goog2) && (goog2.remove()); let gonline = document.querySelector('script[src*="chat/gonline"]'); (gonline) && (gonline.remove()); } // region 存钱 不终止 let depo_channel; const depo_selector = {CMPY: "div#funds div.deposit", FAC: "div#armoury-donate div.cash"}; // 公司 if (href.includes('companies.php')) { depo_channel = "CMPY"; // 公司转跳存钱 if (!href.includes('funds') && getWhSettingObj()['companyRedirect']) { const btn = document.getElementById('ui-id-9'); if (btn) { btn.click(); log('已自动打开存钱页面'); } } // 收起冰蛙表格 if (getWhSettingObj()['companyBWCollapse']) { elementReady('#effectiveness-wrap').then(BWtable_node => { document.body.classList.add('wh-bwtable-ctrl'); addStyle(`.wh-bwtable-ctrl #effectiveness-wrap {display:none !important;}`); const btn = document.createElement('button'); btn.innerHTML = '展开冰蛙表格'; btn.addEventListener('click', () => { document.body.classList.toggle('wh-bwtable-ctrl'); btn.innerText = btn.innerText === '展开冰蛙表格' ? '收起冰蛙表格' : '展开冰蛙表格'; }); BWtable_node.before(btn); }); } // 一键存钱按钮 addActionBtn('一键存钱', companyDeposit, $zhongNode); } // 帮派 if (href.includes('factions.php')) { depo_channel = "FAC"; // 一键存钱按钮 addActionBtn('一键存钱', factionDeposit, $zhongNode); } if (getWhSettingObj()['floatDepo'] && depo_channel) { document.body.classList.add('wh-depo-helper'); addStyle(`.wh-depo-helper div#funds div.deposit, .wh-depo-helper div#armoury-donate div.cash{position: fixed !important; top: 150px; right: 12px; box-shadow: 0 0 8px 1px #00000091; background: #f2f2f2; z-index: 999999;}`); elementReady(depo_selector[depo_channel]).then(node => { const close_btn = document.createElement('button'); close_btn.addEventListener('click', () => { document.body.classList.remove('wh-depo-helper'); close_btn.remove(); }); close_btn.innerHTML = '恢复原位'; close_btn.style.float = 'right'; node.prepend(close_btn); }); } // endregion // GT交易存钱 if (location.pathname.startsWith('/trade.php')) { // GT助手 let node_link = null; let handle = () => { // 不重复加载、已关闭的交易不加载 if (node_link !== null || location.hash.includes('logview')) return; log('已添加GT助手'); // 获取交易id let query_params = location.hash.slice(1); let traceId; query_params.split('&') .forEach(param => (param.startsWith('ID=')) && (traceId = param.slice(3)) ); log('交易id为', traceId); // 获取全部的钱数 let getTraceMoney = async () => { if (typeof addRFC === 'function') { let url = addRFC('/trade.php?step=getFullMoney&ID=' + traceId); return (await ajaxFetch({url: url, method: 'GET', referrer: 'trade.php'})).text(); } }; // 监听jquery ajax请求 if (isDev()) $(document).ajaxComplete((_, xhr, settings) => log({xhr, settings})); // react 加载完成后将节点加入视图中 elementReady('#trade-container').then(() => document.querySelector('#trade-container').before(node) ); // 构建dom节点 let node = document.createElement('div'); node_link = node; let nodeTitle = document.createElement('div'); let nodeCont = document.createElement('div'); let inputMoney = document.createElement('input'); let buttonDepositAll = document.createElement('button'); let buttonWithdraw = document.createElement('button'); let buttonWithdrawAll = document.createElement('button'); let style = document.createElement('style'); inputMoney.placeholder = '定额取钱'; inputMoney.type = 'number'; inputMoney.style.padding = '7px'; inputMoney.style.paddingLeft = '14px'; inputMoney.classList.add('m-right10'); buttonDepositAll.innerHTML = '全存'; buttonDepositAll.style.color = 'green'; buttonWithdraw.innerHTML = '定取'; buttonWithdrawAll.innerHTML = '全取'; buttonWithdrawAll.style.color = 'red'; nodeTitle.innerHTML = 'GT助手'; nodeTitle.classList.add('title-black', 'top-round'); style.innerHTML = '#WHGTHelper button{cursor:pointer;}#WHGTHelper button:hover{opacity:0.5;}'; nodeCont.append(inputMoney, buttonWithdraw, buttonDepositAll, buttonWithdrawAll); nodeCont.classList.add('cont-gray', 'bottom-round'); nodeCont.style.padding = '10px'; node.id = 'WHGTHelper'; node.classList.add('m-bottom10'); node.append(nodeTitle, nodeCont, style); // 定取 buttonWithdraw.addEventListener('click', async () => { if ((inputMoney.value | 0) < 1) { WHNotify('无法定额取钱,原因:输入有误'); return; } let money = await getTraceMoney(); let int = {'input': inputMoney.value | 0, 'all': money | 0}; let diff = int.all - int.input; if (diff < 1) { WHNotify('无法定额取钱,原因:数不对'); return; } await ajaxFetch({ url: addRFC('/trade.php'), method: 'POST', referrer: 'trade.php', body: `step=view&sub_step=addmoney2&ID=${traceId}&amount=${diff}&ajax=true`, }); WHNotify(`已取 ${int.input}`); }); // 全存 buttonDepositAll.addEventListener('click', async () => { let money = await getTraceMoney(); if (money === '0') return; await ajaxFetch({ url: addRFC('/trade.php'), method: 'POST', referrer: 'trade.php', body: `step=view&sub_step=addmoney2&ID=${traceId}&amount=${money}&ajax=true`, }); WHNotify(`$${money} 全部存入GT`); }); // 全取 buttonWithdrawAll.addEventListener('click', async () => { await ajaxFetch({ url: addRFC('/trade.php'), method: 'POST', referrer: 'trade.php', body: `step=view&sub_step=addmoney2&ID=${traceId}&amount=0&ajax=true`, }); WHNotify('已全取'); }); }; if (location.hash.includes('ID=')) handle(); addEventListener('hashchange', () => { if (location.hash.includes('ID=')) handle(); else { node_link.remove(); node_link = null; log('已移除GT助手'); } }); } // 飞行页面 if (href.includes('index.php') && getSidebarData()['traveling']) { // 飞行闹钟 if (device === Device.PC && getWhSettingObj()['trvAlarm']) elementReady('#countrTravel.hasCountdown').then(node => { const logo_node = document.querySelector('#tcLogo[title]'); let dest_cn = ''; if (logo_node) dest_cn = { 'Mexico': '墨西哥', 'Canada': '加拿大', 'Cayman Islands': '开曼', 'Hawaii': '夏威夷', 'United Kingdom': '英国', 'Argentina': '阿根廷', 'Switzerland': '瑞士', 'Japan': '日本', 'China': '中国', 'United Arab Emirates': 'UAE', 'South Africa': '南非', }[logo_node.attributes['title'].nodeValue] || '回城'; else dest_cn = '回城'; const remaining_arr = node.innerText.trim().split(':'); const wh_trv_alarm = localStorage.getItem('wh_trv_alarm') ? JSON.parse(localStorage.getItem('wh_trv_alarm')) : {'enable': true, 'alert_time': 30, 'node_pos': [240, 240]}; const save_trv_settings = () => localStorage.setItem('wh_trv_alarm', JSON.stringify(wh_trv_alarm)); const wh_trv_alarm_node = document.createElement('div'); wh_trv_alarm_node.id = 'wh-trv-alarm'; wh_trv_alarm_node.style.left = `${wh_trv_alarm.node_pos[0]}px`; wh_trv_alarm_node.style.top = `${wh_trv_alarm.node_pos[1]}px`; wh_trv_alarm_node.innerHTML = `

❌ 没有权限
点击网页内任意位置以激活闹钟

飞行闹钟

正在${dest_cn === '回城' ? dest_cn : '飞往' + dest_cn}

`; addStyle(` #wh-trv-alarm{ position:absolute; width:248px; /*left:${wh_trv_alarm.node_pos[0] || 240}px; top:${wh_trv_alarm.node_pos[1] || 240}px;*/ background:white; border-radius:4px; box-shadow:#0000001f 0 0 10px 4px; border:solid 1px #aaa; z-index:100001; margin:2em; } #wh-trv-alarm button{ margin:0; } #wh-trv-error{ position:absolute; width:100%; height:100%; /*display: table;*/ display:none; } #wh-trv-error p{ background:#ffd0d0; color:red; display:table-cell; vertical-align:middle; padding:1em; text-align:center; } #wh-trv-alarm-title{ height: 30px; border-bottom: solid #aaa 1px; cursor: move; } /*#wh-trv-alarm-move-btn span{ background:url(/images/v2/home_main/move.svg); width: 30px; height: 30px; float: right; cursor: move; }*/ h5#wh-trv-alarm-header{ height: 100%; line-height: 30px; padding:0 12px; font-weight: bold; text-align: center; } #wh-trv-alarm-bottom{ padding: 12px; } #wh-trv-alarm-remaining{ float:right; color:red; } #wh-trv-alarm-cont input[type="number"]{ width: 42px; border-bottom: solid 1px #aaa; } .wh-trv-alarm-stop-hide{ display:none; } `); document.body.append(wh_trv_alarm_node); // 报错dom const error_node = wh_trv_alarm_node.querySelector('#wh-trv-error'); // jquery拖动 $(wh_trv_alarm_node).draggable({ containment: "body", distance: 5, handle: "#wh-trv-alarm-title", stop: () => { wh_trv_alarm.node_pos = [parseInt(wh_trv_alarm_node.style.left), parseInt(wh_trv_alarm_node.style.top)]; save_trv_settings(); }, scroll: false, }); // 剩余时间dom const remaining_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-remaining'); // 设定闹钟响的按钮 const set_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[0]; // 落地前响铃时长 const cd_time = wh_trv_alarm_node.querySelector('input[type="number"]'); let count_down_notify = {}; set_node.onclick = () => { try { wh_trv_alarm.alert_time = parseInt(cd_time.value); } catch { wh_trv_alarm.alert_time = 30; } save_trv_settings(); set_node.value = wh_trv_alarm.alert_time; if (count_down_notify.del) count_down_notify.del(); count_down_notify = WHNotify('设置已更新'); }; // 停止响铃按钮 const stop_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[1]; stop_node.onclick = () => { user_stop_alert = true; stop_node.innerText = '本次已关闭'; stop_node.disabled = true; } // 开启闹钟勾选 const enable_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-cont input[type="checkbox"]'); let on_off_notify = {}; enable_node.onchange = ev => { wh_trv_alarm.enable = ev.target.checked; save_trv_settings(); if (on_off_notify.del) on_off_notify.del(); on_off_notify = WHNotify(wh_trv_alarm.enable ? '闹钟已开启' : '闹钟已关闭'); }; // 剩余时间 秒 const remaining_sec = parseInt(remaining_arr[0]) * 3600 + parseInt(remaining_arr[1]) * 60 + parseInt(remaining_arr[2]); // 落地时timestamp const land_timestamp = Date.now() + remaining_sec * 1000; // 音频dom const audio = document.createElement('audio'); audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3'; audio.play() .catch(() => { error_node.style.display = 'table'; const func = () => { error_node.remove(); document.body.removeEventListener('click', func); }; document.body.addEventListener('click', func); }) .then(() => audio.pause()); // 是否正在响铃 let audio_play_flag = false; // 用户是否停止当前响铃 let user_stop_alert = false; // 响铃循环id let audio_play_id = null; // 响铃的方法 let audio_play_handle = () => { if (user_stop_alert) { clearInterval(audio_play_id); audio_play_id = null; return; } if (!audio_play_flag || !wh_trv_alarm.enable) return; audio.play().then(); }; // 飞机小动画字符 const flying_arr = [ '✈ ', '  ✈ ', '    ✈ ', '      ✈ ', '        ✈ ', '          ✈ ', '            ✈ ', '              ✈ ', '                ✈ ', '                  ✈ ', ]; // 飞行的状态dom const flying_status = wh_trv_alarm_node.querySelector('#wh-trv-status'); // 飞机的小动画dom const flying_ani = flying_status.nextElementSibling; // 飞机的计数 let flying_index = 0; const id = window.setInterval(() => { const remaining_time = (land_timestamp - Date.now()) / 1000 | 0; remaining_node.innerText = `${remaining_time / 3600 | 0}时${remaining_time % 3600 / 60 | 0}分${remaining_time % 60}秒`; if (remaining_time < wh_trv_alarm.alert_time) { // flying_status.innerHTML = `即将落地...`; if (wh_trv_alarm.enable) { // 播放提示音 audio_play_flag = true; if (audio_play_id === null && !user_stop_alert) audio_play_id = window.setInterval(audio_play_handle, 750); stop_node.parentElement.classList.remove('wh-trv-alarm-stop-hide'); } } else { // flying_status.innerHTML = `飞行中...`; if (wh_trv_alarm.enable) { clearInterval(audio_play_id); audio_play_id = null; stop_node.parentElement.classList.add('wh-trv-alarm-stop-hide'); } } flying_ani.innerHTML = `${flying_arr[flying_index]}`; flying_index = (flying_index + 1) % flying_arr.length; }, 1000); }); // 落地转跳 if (getWhSettingObj()['landedRedirect'] && document.querySelector('#tcLogo[title]') === null) { window.addEventListener('beforeunload', () => { let obj = {url: getWhSettingObj()['landedRedirect'], timestamp: Date.now()}; sessionStorage['wh-landed-redirect'] = JSON.stringify(obj); }); } } // 海外落地页面 if (href.includes('index.php') && document.querySelector('#travel-home') !== null) { // 添加回城按钮 addActionBtn('直接回城', getHome, $zhongNode); // 海外警告 if (getWhSettingObj()['abroadWarning']) { let c = 1; setInterval(() => WHNotify(`警告:您已海外落地${c++ * 30}秒`, {timeout: 30, sysNotify: true}), 30000); } // 解毒提醒 if (getSidebarData()['rehabilitation']) { let page_title = document.querySelector('h4#skip-to-content'); let msg = document.createElement('div'); msg.innerHTML = `
`; msg.classList.add('info-msg-cont', 'green', 'border-round', 'm-bottom10'); page_title.before(msg); } } // 落地转跳 else if (href.includes('index.php') && getSidebarData()['home'] && sessionStorage['wh-landed-redirect']) { let {url, timestamp} = JSON.parse(sessionStorage['wh-landed-redirect']); if (Date.now() - timestamp < 30000) { sessionStorage.removeItem('wh-landed-redirect'); location.href = url; } } // 起飞提醒 if (href.contains(/travelagency\.php/) && getWhSettingObj()['energyAlert']) { 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 trans = () => { // 当前能量e const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim(); const [curE, maxE] = energyBarStr.split('/').length === 2 ? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])] : [NaN, NaN]; const incTime = maxE === 150 ? 10 : 15; const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime + (incTime - new Date().getMinutes() % incTime) : NaN; // 起飞前提示 $('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => { if (isNaN(fullEnergyTime)) return; const spl = e.innerText.trim().split(' '); const [hours, minutes] = spl.length === 5 ? [parseInt(spl[0]), parseInt(spl[3])] : [0, parseInt(spl[0])]; if (fullEnergyTime < (hours * 60 + minutes) * 2) { if (!$(e).parent().hasClass('wh-translated')) { $(e).parent() .prepend(`
警告:该次飞行往返时间大于体力回复时间,将会爆体!
`) .addClass('wh-translated'); } } }); }; trans(); OB.observe($$.get(0), { characterData: true, attributes: true, subtree: true, childList: true }); } // 一键起飞 if (sessionStorage['wh-quick-fly'] && href.includes('travelagency.php')) { doQuickFly(); } // 攻击页面 if (href.contains(/loader\.php\?sid=attack/)) { let stop_reload = false; const {quickAttIndex, quickFinishAtt, attReload} = getWhSettingObj(); // 光速刷新按钮 addActionBtn('光速刷新', doAttackReload, $zhongNode); // 自刷新 let audio_played_flag; if (attReload !== 6 && stop_reload !== true) { const selector_device_map = { 'pc': '#defender div[class^="modal___"]', 'mobile': '#attacker div[class^="modal___"]', 'tablet': '', }; const selector = selector_device_map[device]; elementReady(selector).then(elem => { if (!elem.querySelector('button')) { if (getWhSettingObj().attReload === 0 && stop_reload !== true) { // window.location.reload(); doAttackReload(); } else { let reload_flag; const timeout = getWhSettingObj().attReload * 1000 + getRandomInt(-500, 500); log(`[WH] ${timeout / 1000}s 后自动刷新`); window.setInterval(() => { if (reload_flag === undefined) { reload_flag = true; } else if (stop_reload !== true) { // window.location.reload(); doAttackReload(); } }, timeout); } } else if (audio_played_flag === undefined) { audio_played_flag = true; let play_time = 0; const audio_play_id = window.setInterval(() => { const $audio = document.createElement('audio'); $audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3'; $audio.play().then(); play_time++; if (play_time === 3) clearInterval(audio_play_id); }, 600); } }); } // 光速拔刀 if (quickAttIndex !== 6) { // const selectedId = ['weapon_main', 'weapon_second', 'weapon_melee', 'weapon_temp', 'weapon_fists', 'weapon_boots'] // [getWhSettingObj().quickAttIndex]; const btn = await elementReady('div[class^="modal___"] button');//.then(btn => { log(btn) if (!btn.innerText.toLowerCase().includes('fight')) return; // 判断是否存在脚踢 const hasKick = !!document.querySelector('#weapon_boots'); // modal层 const modal = document.querySelector('div[class^="modal___"]'); log(`当前设备类型是${device}`); // 区分设备 switch (device) { case Device.PC: { log(`开始调整按钮位置`); // 隐藏modal层 modal.style.display = 'none'; // 根据选择的武器调整css let css_top = '0'; switch (getWhSettingObj()['quickAttIndex']) { case 1: { // weapon_second css_top = '97px'; break; } case 2: { // weapon_melee css_top = '194px'; break; } case 3: { // weapon_temp css_top = '291px'; break; } case 4: // weapon_fists case 5: { // weapon_boots css_top = '375px'; break; } } const css_rule = ` .wh-move-btn #defender div[class^="modal___"]{display: block;width: 0 !important;top: ${css_top};left: -169px !important;} .wh-move-btn #defender div[class^="dialog___"]{border:0;width:159px;height:96px;} .wh-move-btn #defender div[class^="colored___"]{display:block;padding:0;} .wh-move-btn #defender div[class^="title___"]{height:0;} .wh-move-btn #defender button{width: 100%;margin:17px 0;height: 60px;} `; addStyle(css_rule); document.body.classList.add('wh-move-btn'); // 绑定点击事件 联动【光速跑路】 btn.onclick = () => { if (quickFinishAtt !== 3) { btn.remove(); // 停止自动刷新 stop_reload = true; } else { document.body.classList.remove('wh-move-btn'); } }; break; } case Device.MOBILE: { log(`开始调整按钮位置`); // 加入css let css_top = '0'; let slot_height = '76px'; // 判断有没有脚踢 if (hasKick) { // 根据选择的武器调整 switch (getWhSettingObj()['quickAttIndex']) { case 1: { // weapon_second css_top = '76px'; break; } case 2: { // weapon_melee css_top = '152px'; break; } case 3: { // weapon_temp css_top = '228px'; break; } case 4: { // weapon_fists css_top = '304px'; break; } case 5: { // weapon_boots css_top = '380px'; break; } } } else { const slot = document.querySelector('#weapon_main'); const height = slot.offsetHeight + 1; slot_height = height; // 根据选择的武器调整 switch (getWhSettingObj().quickAttIndex) { case 1: { // weapon_second css_top = `${height}px`; break; } case 2: { // weapon_melee css_top = `${height * 2}px`; break; } case 3: { // weapon_temp css_top = `${height * 3}px`; break; } case 4: { // weapon_fists css_top = `${height * 4}px`; break; } case 5: { // weapon_boots css_top = `${height * 5}px`; break; } } } const css_rule = ` .wh-move-btn #attacker div[class^="modal___"]{display: block;width: 0;top: ${css_top};left:0;height:0;} .wh-move-btn #attacker div[class^="dialog___"]{border:0;width:80px;height:${slot_height};} .wh-move-btn #attacker div[class^="colored___"]{display:block;padding:0;} .wh-move-btn #attacker div[class^="title___"]{height:0;} .wh-move-btn #attacker button{width:100%;margin:0;height:63px;white-space:normal;} `; addStyle(css_rule); document.body.classList.toggle('wh-move-btn'); btn.onclick = () => { if (getWhSettingObj().quickFinishAtt !== 3) { btn.remove(); // 停止自动刷新 stop_reload = true; } else { document.body.classList.toggle('wh-move-btn'); } }; break; } case Device.TABLET: { break; } } // 自动开打 if (getWhSettingObj()['autoStartFinish'] === true) { if (btn.innerText.includes('(')) { let interval_id = window.setInterval(() => { if (!btn) { clearInterval(interval_id); return; } try { btn.click(); } catch { } }, 100); } else { btn.click(); } } } // 光速跑路 if (quickFinishAtt !== 3) { const user_btn_select = ['leave', 'mug', 'hosp'][getWhSettingObj()['quickFinishAtt']]; const wrap = document.querySelector('#react-root'); log('光速跑路选项选中:', user_btn_select); new MutationObserver(() => { const btn_arr = document.querySelectorAll('div[class^="dialogButtons___"] button'); if (btn_arr.length > 1) btn_arr.forEach(btn => { const flag = btn.innerText.toLowerCase().includes(user_btn_select); log('按钮内容:', btn.innerText, ',是否包含选中:', flag); if (!flag) btn.style.display = 'none'; // 自动结束 else if (getWhSettingObj()['autoStartFinish'] === true) { try { btn.click(); } catch { } } }); }).observe(wrap, {subtree: true, attributes: true, childList: true}); } return; } // 错误的攻击页面 if (getWhSettingObj()['attRelocate'] && href.includes('loader2.php')) { const spl = window.location.href.trim().split('='); const uid = spl[spl.length - 1]; if (!/^\d+$/.test(uid)) return; window.location.href = `https://www.torn.com/loader.php?sid=attack&user2ID=${uid}`; return; } // 捡垃圾助手 if (getWhSettingObj()['cityFinder'] && href.includes('city.php')) { addStyle(` .wh-city-finds .leaflet-marker-pane img[src*="torn.com/images/items/"]{ display: block !important; box-sizing: border-box; width: 40px !important; height: 40px !important; left: -20px !important; top: -20px !important; padding: 10px 0; border: none; border-radius: 100%; background-color:#d2d2d28c; box-shadow:0 0 10px 5px #000; z-index: 999 !important; } .wh-city-finds .leaflet-marker-pane.leaflet-marker-icon.user-item-pinpoint.leaflet-clickable{display: none !important;} #wh-city-finder{ box-shadow: 0 0 3px 0px #696969; border-radius: 4px; } #wh-city-finder-header{ background-color: #3f51b5; color: white; padding: 8px; font-size: 15px; border-radius: 4px 4px 0 0; text-shadow: 0 0 2px black; background-image: linear-gradient(90deg,transparent 50%,rgba(0,0,0,.07) 0); background-size: 4px; } #wh-city-finder-cont{ background: #616161; padding: 8px; color: #c7c7c7; border-radius: 0 0 4px 4px; font-size: 13px; } #wh-city-finder-cont span{ margin:2px 4px 2px 0; padding:2px; border-radius:2px; background:green; color:white; display:inline-block; } `); // 物品名与价格 let items = null; const base = document.createElement('div'); base.id = 'wh-city-finder'; const container = document.createElement('div'); container.id = 'wh-city-finder-cont'; const header = document.createElement('div'); header.id = 'wh-city-finder-header'; header.innerHTML = '捡垃圾助手'; const info = document.createElement('div'); info.innerHTML = '已找到物品:'; container.append(info); base.append(header); base.append(container); COFetch('https://jjins.github.io/item_price_raw.json') .catch(err => { log(err) items = undefined }) .then(r => items = JSON.parse(r)); elementReady('div.leaflet-marker-pane').then(elem => { document.querySelector('#map').classList.add('wh-city-finds'); document.querySelector('.content-wrapper').prepend(base); // 发现的物品id与map img node const founds = []; elem.querySelectorAll('img.map-user-item-icon').forEach(node => { const item_id = node.src.split('/')[5]; const finder_item = document.createElement('span'); finder_item.id = 'wh-city-finder-item' + item_id; finder_item.innerHTML = item_id; founds.push({'id': item_id, 'node': finder_item, 'map_item': node}); container.append(finder_item); }); // 未发现物品 返回 if (founds.length === 0) { // header.innerHTML = '捡垃圾助手'; info.innerHTML = '空空如也,请大佬明天再来'; return; } // 将id显示为物品名与价格的函数 const displayNamePrice = () => { // 总价 let total = 0; founds.forEach(el => { const value = items[el.id]['price']; el.node.innerHTML = `${items[el.id]['name']} ($${toThousands(value)})`; // 灰色 100k以下 if (value < 100000) el.node.style.backgroundColor = '#9e9e9e'; // 绿色 1m以下 else if (value < 1000000) el.node.style.backgroundColor = '#4caf50'; // 蓝色 25m以下 else if (value < 25000000) el.node.style.backgroundColor = '#03a9f4'; // 橙色 500m以下 else if (value < 500000000) el.node.style.backgroundColor = '#ffc107'; // 红色 >500m else if (value >= 500000000) el.node.style.backgroundColor = '#f44336'; total += items[el.id]['price']; }); header.innerHTML = `捡垃圾助手 - ${founds.length} 个物品,总价值 $${toThousands(total)}`; }; // 未取到数据时添加循环来调用函数 if (items === null) { // 15s超时 let timeout = 30; const interval = window.setInterval(() => { timeout--; if (items !== null) { displayNamePrice(); clearInterval(interval); } if (0 === timeout) { log('获取物品名称与价格信息超时') clearInterval(interval) } }, 500); } // 无法跨域获取数据时 else if (items === undefined) { info.innerHTML += '(当前平台暂不支持查询价格)'; } // 调用函数 else { displayNamePrice(); } }) } // pt一键购买 if (getWhSettingObj()['ptQuickBuy'] && href.includes('pmarket.php')) { WHNotify('一键购买已开启'); // 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) } } }).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 => { cont.classList.toggle('wh-display-none'); setWhSetting('SEProtect', e.target.checked); }; 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({xhr, settings}); let {data} = settings, {responseText} = xhr; let response = JSON.parse(responseText); if (data.includes('step=buyShopItem') && data.includes('ID=180') && response['success']) { WHNotify('已检测成功购买啤酒') beer.skip_today(); } }); } // 快速crime if (href.contains(/crimes\.php/) && getWhSettingObj()['quickCrime']) { if (isIframe) { 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 }); } // 任务助手 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'); const $btn = $wh_loot_container.querySelector('#wh-loot-btn button'); const $clear_btn = $wh_loot_container.querySelector('#wh-hist-clear button'); 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'); const $sound = $wh_loot_container.querySelector('#wh-loot-setting-sound'); const $chest = $wh_loot_container.querySelector('#wh-loot-setting-chest'); const $audio = $wh_loot_container.querySelector('audio'); $btn.onclick = e => { e.target.innerText = e.target.innerText === '设置' ? '收起' : '设置'; $($ex).toggleClass('wh-hide'); e.target.blur(); }; $clear_btn.onclick = e => { e.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 = {}; 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'); const $sound = $wh_loot_container.querySelector('#wh-loot-setting-sound'); const $chest = $wh_loot_container.querySelector('#wh-loot-setting-chest'); 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')) { 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); await rw_raider(); } // 任何位置公司一键存钱 if (getWhSettingObj()['companyDepositAnywhere']) { addActionBtn('公司存钱', companyDepositAnywhere, $zhongNode); } if (getPlayerInfo()['userID'] === 2687093) { let item = document.getElementById('nav-items'); if (item) { let copy = item.cloneNode(true); copy.firstChild.style.backgroundColor = '#ff5722'; let a = copy.firstChild.firstChild; a.href = '/item.php?temp=1'; let span = a.lastChild; span.innerHTML = '物品'; span.style.color = 'white'; item.after(copy); } } // 通知翻译 function eventsTrans(events = $('span.mail-link')) { // if (!wh_trans_settings.transEnable) return; const index = window.location.href.indexOf('events.php#/step=received') >= 0 ? 1 : 0; const isReceived = index === 1; // 通知的类型选择栏 $('ul.mailbox-action-wrapper a').contents().each((i, e) => { if (e.nodeValue) if (eventsDict[e.nodeValue.trim()]) e.nodeValue = eventsDict[e.nodeValue.trim()]; }); // 桌面版右边按钮浮动提示消息 $('div.mailbox-container i[title]').each((i, e) => { if (eventsDict[$(e).attr('title')]) { $(e).attr('title', eventsDict[$(e).attr('title')]); } }); // 手机版底部按钮 $('.mobile-mail-actions-wrapper div:nth-child(2)').each((i, e) => { if (eventsDict[$(e).text().trim()]) $(e).text(eventsDict[$(e).text().trim()]); }); // 黑框标题 $('#events-main-wrapper .title-black').each((i, e) => { if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); } }); // 发送的两个按钮 + user id $('#events-main-wrapper div.send-to a.btn').each((i, e) => { if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); } }); $('#events-main-wrapper div.send-to span.cancel a').each((i, e) => { if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); } }); $('#events-main-wrapper div.send-to span.name').each((i, e) => { if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); } }); // 通知翻译的开关 if (!$('div#event-trans-msg').get(0) && !window.location.href.contains(/index\.php/)) { // msgBox(`
插件暂时不能翻译全部通知。
// 如发现问题请发送通知并联系 Woohoo[2687093]
// 可能会出现卡顿,默认开启
`); $('input#eventTransCheck').attr('checked', localStorage.getItem('wh_trans_event') === 'true'); $('input#eventTransCheck').change(function () { if ($(this).attr('checked') === undefined) { localStorage.setItem('wh_trans_event', 'false'); } else { localStorage.setItem('wh_trans_event', 'true'); } eventsTrans(); }); } if (localStorage.getItem('wh_trans_event') === 'false') return; if (events.length === 0) return; events.each((i, e) => { // todo “收到的信息” 暂时删除发送人节点 不影响显示 if (isReceived) { $(e).children('a.sender-name').remove(); } if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); return; } /** * 赛车 * You finished 5th in the Hammerhead race. Your best lap was 01:14.87. * You finished 1st in the Docks race. Your best lap was 04:01.33. * You finished 1st in the Hammerhead race and have received 3 racing points! Your best lap was 01:06.92. * You finished 4th in the Docks race. Your best lap was 03:29.27 beating your previous best lap record of 03:35.77 by 00:06.50. * You have crashed your Honda NSX on the Sewage race! The upgrades Paddle Shift Gearbox (Short Ratio) and Carbon Fiber Roof were lost. * You have crashed your Ford Mustang on the Docks race! Your car has been recovered. */ if ($(e).text().indexOf('finished') >= 0) { if ($(e).text().indexOf('crashed') >= 0) return; // todo 撞车 const isGainRacingPoint = $(e).text().indexOf('racing point'); let racingPoint = isGainRacingPoint >= 0 ? $(e).text()[isGainRacingPoint - 2] : null; const isBeat = $(e).text().indexOf('beating') >= 0; let record, bestBy; if (isBeat) { record = $(e).text().split('record of ')[1].split(' by ')[0]; bestBy = $(e).text().split('record of ')[1].split(' by ')[1].split('. ')[0]; } const pos = e.childNodes[1].firstChild.nodeValue.match(/[0-9]+/)[0]; const splitList = e.childNodes[2].nodeValue.split(' '); const bestLap = e.childNodes[2].nodeValue.split(' best lap was ')[1].slice(0, 8);//.split(' ')[0]; let map = splitList[3]; map = map === 'Two' ? 'Two Islands' : map; map = map === 'Stone' ? 'Stone Park' : map; e.firstChild.nodeValue = '你在赛车比赛 ' + map + ' 中获得第 '; e.childNodes[1].firstChild.nodeValue = pos; e.childNodes[2].nodeValue = ' 名,'; if (isGainRacingPoint >= 0) { e.childNodes[2].nodeValue += '获得' + racingPoint + '赛车点数 (Racing Points)。'; } e.childNodes[2].nodeValue += '你的最佳圈速是 ' + bestLap; if (isBeat) e.childNodes[2].nodeValue += ',比之前最佳 ' + record + ' 快 ' + bestBy; e.childNodes[2].nodeValue += '。' e.childNodes[2].nodeValue += '['; e.childNodes[3].firstChild.nodeValue = '查看'; return; } /** * 还贷 */ if ($(e).text().contains(/You have been charged \$[0-9,]+ for your loan/)) { const node1Value = e.firstChild.nodeValue; // You have been charged $29,000 for your loan. You can pay this by visiting the //e.childNodes[1].firstChild.nodeValue; // Loan Shark // const node3Value=e.childNodes[2].nodeValue; 内容是 ". " let charge = node1Value.split(' ')[4]; let replace; replace = '你需要支付 '; replace += charge; replace += ' 贷款利息,点此支付:'; e.firstChild.nodeValue = replace; e.childNodes[1].firstChild.nodeValue = '鲨客借贷'; e.childNodes[2].nodeValue = '。'; return; } /** * 收到钱物 * You were sent $21,000,000 from * JNZR * . * 附带信息: with the message: Manuscript fee OCT * e.firstChild.nodeValue * e.childNodes[1].firstChild.nodeValue * e.childNodes[2].nodeValue * * You were sent 4x Xanax from RaichuQ with the message: Manuscript fee OCT * You were sent $21,000,000 from JNZR. * You were sent some Xanax from runningowl * You were sent 1x Present from Duke with the message: Is it your birthday? * You were sent Duke's Safe from DUKE * You were sent a Diamond Bladed Knife from charapower */ if ($(e).text().contains(/You were sent .+ from/)) { // 数量 物品 信息 // spl = [You were sent 1x Birthday Present from] const spl = $(e).contents().get(0).nodeValue.trim().split(' '); const msgSpl = $(e).text().trim().split('with the message: '); const num = /^\$[0-9,]+\b/.test(spl[3]) ? '' : spl[3].numWordTrans(); const item = num === '' ? spl[3] : spl.slice(4, -1).join(' '); const msg = msgSpl[1] ? msgSpl[1] : null; e.childNodes[0].nodeValue = `你收到了 ${num} ${item},来自 `; if (e.childNodes[2]) { e.childNodes[2].nodeValue = `。`; } if (msg) { e.childNodes[2].nodeValue = `,附带信息:${msg}。`; } return; } /** * bazaar * Dewei3 bought 2 x Toyota MR2 from your bazaar for $56,590. * ['', 'bought', '2', 'x', 'Toyota', 'MR2', 'from', 'your', 'bazaar', 'for', '$56,590.\n'] * e.childNodes[1].nodeValue */ if ($(e).text().contains(/bought .+ from your bazaar for/)) { const bazEN = e.childNodes[1].nodeValue; const spl = bazEN.split(' '); const num = spl[2]; const item = spl.slice(4, spl.indexOf('from')).join(' '); const money = spl[spl.length - 1].replace('.', ''); e.childNodes[1].nodeValue = ' 花费 ' + money + ' 从你的店铺购买了 ' + num + ' 个 ' + ' ' + item + '。'; return; } /** * 交易 */ if ($(e).text().indexOf('trade') >= 0) { const PCHC = '点此继续'; if ($(e).text().indexOf('You must now accept') >= 0) { /** * 接受交易 * JNZR * has accepted the trade titled "g't". You must now accept to finalize it. * Please click here to continue. * JNZR已经接受了名为 "g't "的交易。你现在必须接受以完成它。 */ const firstWords = e.childNodes[1].nodeValue.split('. You must')[0]; const tradeName = firstWords.slice(31, firstWords.length); e.childNodes[1].nodeValue = ' 已经接受了名为 ' + tradeName + ' 的交易。你现在必须接受以完成它。'; e.childNodes[2].firstChild.nodeValue = PCHC; return; } if ($(e).text().indexOf('expired') >= 0) { /** * 交易过期 * The trade with * sabrina_devil * has expired * 与sabrina_devil的交易已经过期。 */ e.firstChild.nodeValue = '与 '; e.childNodes[2].nodeValue = ' 的交易已过期。'; return; } if ($(e).text().indexOf('initiated') >= 0) { /** * 交易发起 * sabrina_devil * has initiated a trade titled "gt". * Please click here to continue. * sabrina_devil发起了一项名为 "gt "的交易。 */ const node2 = e.childNodes[1].nodeValue; const tradeName = node2.slice(30, node2.length - 2); e.childNodes[1].nodeValue = ' 发起了标题为 ' + tradeName + ' 的交易。'; e.childNodes[2].firstChild.nodeValue = PCHC; return; } if ($(e).text().indexOf('now complete') >= 0) { /** * 交易完成 * Tmipimlie * has accepted the trade. The trade is now complete. * Tmipimlie已经接受交易。现在交易已经完成。 */ e.childNodes[1].nodeValue = ' 已经接受交易。该交易现已完成。'; return; } if ($(e).text().indexOf('canceled') >= 0) { /** * 交易完成 * WOW * has canceled the trade. * WOW已经取消了这项交易。 */ e.childNodes[1].nodeValue = ' 已经取消了这个交易。'; return; } if ($(e).text().indexOf('commented') >= 0) { /** * 交易评论 * QIJI * commented on your * pending trade * : "Thank you for trading with me! The total is $19,461,755 and you can view your receipt here: https://www.tornexchange.com/receipt/mhWuuL7hrE" */ e.childNodes[1].nodeValue = ' 对'; e.childNodes[2].firstChild.nodeValue = '进行中的交易'; e.childNodes[3].nodeValue = '添加了一条评论' + e.childNodes[3].nodeValue; return; } return; } /** * 被mug */ if ($(e).text().indexOf('mugged') >= 0) { const spl = $(e).text().trim().split(' '); if (spl.length > 7) return; // todo 多人运动暂时跳过 const money = spl[spl.length - 2]; if (spl[0] === 'Someone') { // 被匿名mug e.firstChild.nodeValue = '有人打劫你并抢走了 ' + money + ' ['; e.childNodes[1].firstChild.nodeValue = '查看'; } else { e.childNodes[1].nodeValue = ' 打劫你并抢走了 ' + money + ' ['; e.childNodes[2].firstChild.nodeValue = '查看'; } return; } /** * 被打 */ if ($(e).text().indexOf('attacked') >= 0) { // 被打 /** * 攻击方式 词数=spl.length * 匿名 4 Someone attacked you [view] * - hosp 6 Someone attacked and hospitalized you [view] * -- 有人袭击了你并安排你住院 * 实名 4 EternalSoulFire attacked you [view] * - lost 6 EternalSoulFire attacked you but lost [view] * - hosp 6 * - 逃跑esc 6 Dr_Bugsy_Siegel attacked you but escaped [view] * - 25回合平手stale 6 Tharizdun attacked you but stalemated [view] * - 起飞或bug 6 Mrew tried to attack you [view] * * You attacked Cherreh but timed out [view] * * 多人运动 todo * 10 Pual (and 2 others) attached you and hospitalized you [view] * 9 Argozdoc attacked you but Norm fought him off [view] */ const spl = $(e).text().trim().split(' '); if (spl.length > 6) { // 多人运动暂时跳过 /** * 超时自动失败 */ if (spl[4] === 'timed') { if (e.firstChild.firstChild) { // 由第一个节点是否有子节点判断 被攻击 e.childNodes[1].nodeValue = ' 袭击你但是超时了 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; } e.firstChild.nodeValue = '你袭击 '; e.childNodes[2].nodeValue = ' 但是超时了 ['; e.childNodes[3].firstChild.nodeValue = '查看'; return; } return; } if ($(e).find('a').text().toLowerCase().indexOf('someone') < 0 && // 避免玩家名带有someone字样 $(e).text().split(' ')[0].toLowerCase() === 'someone') { // 被匿名 if (spl.length === 6 && spl[3] === 'hospitalized') { // 匿名hos e.firstChild.nodeValue = '有人袭击你并将你强制住院 ['; e.childNodes[1].firstChild.nodeValue = '查看'; return; } e.firstChild.nodeValue = '有人袭击了你 ['; e.childNodes[1].firstChild.nodeValue = '查看'; return; } if (spl.length === 4) { // 实名leave e.childNodes[1].nodeValue = ' 袭击了你 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; } if (spl.length === 6) { // 实名的情况 switch (spl[4]) { case 'lost': e.childNodes[1].nodeValue = ' 袭击你但输了 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; case 'escaped': e.childNodes[1].nodeValue = ' 袭击你但逃跑了 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; case 'stalemated': e.childNodes[1].nodeValue = ' 袭击你但打成了平手 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; } switch (spl[3]) { case 'attack': // Mrew tried to attack you [view] e.childNodes[1].nodeValue = ' 尝试袭击你 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; case 'hospitalized': e.childNodes[1].nodeValue = ' 袭击你并将你强制住院 ['; e.childNodes[2].firstChild.nodeValue = '查看'; return; } } } /** * 每日彩票 * 有人在Lucky Shot彩票中赢得11,832,100,000美元! * zstorm won $5,574,200 in the Daily Dime lottery! */ if ($(e).text().indexOf('lottery') >= 0) { const split = e.childNodes[1].nodeValue.split(' '); const type = split[split.length - 3] + ' ' + split[split.length - 2]; const money = split[2]; e.childNodes[1].nodeValue = ' 在 ' + type + ' 彩票中赢得了 ' + money + '!'; return; } /** * 公司职位变更 */ if ($(e).text().contains(/, the director of .+, has/)) { $(e).contents().each((i, e) => { if (e.nodeType === 3) { if (eventsDict[e.nodeValue.trim()]) { e.nodeValue = eventsDict[e.nodeValue.trim()]; } else { // 工资改变 if (e.nodeValue.contains(/wage/)) { const money = e.nodeValue.trim().slice(27, -9); e.nodeValue = ` 的老板) 将你的每日工资改为 ${money}。`; return; } // 职位改变 if (e.nodeValue.contains(/rank/)) { const pos = e.nodeValue.trim().slice(27, -1); e.nodeValue = ` 的老板) 将你的公司职位改为 ${pos}。`; return; } if (e.nodeValue.contains(/assigned/)) { e.nodeValue = ` 的老板) 将你指派为新的公司老板。`; return; } // 火车 if (e.nodeValue.contains(/trained/)) { const spl = e.nodeValue.trim().split(' '); const pri = spl[10]; const sec = spl[13].slice(0, -1); e.nodeValue = ` 的老板) 从公司训练了你。你获得了 50 ${eventsDict[pri]} 和 25 ${eventsDict[sec]}。`; } } } }); return; } /** * 悬赏已被领取 */ if ($(e).text().contains(/bounty reward/)) { $(e).contents().each((i, e) => { if (e.nodeType === 3) { if (eventsDict[e.nodeValue.trim()]) { e.nodeValue = ` ${eventsDict[e.nodeValue.trim()]} `; } else { if (e.nodeValue.contains(/bounty reward/)) { const bountyAmount = e.nodeValue.trim().split(' ')[3]; if (eventsDict['and earned your'] && eventsDict['bounty reward']) { e.nodeValue = ` ${eventsDict['and earned your']} ${bountyAmount} ${eventsDict['bounty reward']}`; } } } } }); return; } /** * oc开启 * You have been selected by * endlessway * to participate in an organized crime. You, along with 2 others will make up the team to * make a bomb threat * in 72 hours. * * 你被endlessway选中参与一项有组织的犯罪活动。你和另外两个人将组成一个团队,在72小时内进行炸弹威胁。 */ if ($(e).text().indexOf('organized crime') >= 0) { const time = e.childNodes[4].nodeValue.split(' ')[2]; const OCName = e.childNodes[3].firstChild.nodeValue; let others = e.childNodes[2].nodeValue.split(' ')[10]; others = others === 'one' ? '1' : others; e.firstChild.nodeValue = '你被 '; e.childNodes[2].nodeValue = ` 选中参与一项组织犯罪(OC)。你和另外${others}人将组成一个团队,在${time}小时后进行 `; e.childNodes[3].firstChild.nodeValue = ocList[OCName] ? ocList[OCName] : OCName; e.childNodes[4].nodeValue = '。'; return; } /** * oc结束 * - You and your team tried to make a bomb threat but failed! View the details * - You and your team successfully blackmailed someone! View the details * here * ! */ if ($(e).text().indexOf('You and your team') >= 0) { let rs = '成功'; let OCName = e.firstChild.nodeValue.slice(31, -19); if ($(e).text().indexOf('fail') >= 0) { rs = '失败'; OCName = e.firstChild.nodeValue.slice(27, -30); } e.firstChild.nodeValue = `你和团队的组织犯罪(OC) ${ocList[OCName] ? ocList[OCName] : OCName} ${rs}了!`; e.childNodes[1].firstChild.nodeValue = '点此查看详情'; e.childNodes[2].nodeValue = '!'; return; } /** * bust * Spookyt * failed to bust you out of jail. */ if ($(e).text().indexOf('bust') >= 0) { if (e.childNodes[1].nodeValue[1] === 'f') { // 失败 e.childNodes[1].nodeValue = ' 没能把你从监狱救出来。'; return; } if (e.childNodes[1].nodeValue[1] === 'w') { // 失败被抓 e.childNodes[1].nodeValue = ' 在尝试救你出狱时被抓了。'; return; } if (e.childNodes[1].nodeValue[1] === 's') { e.childNodes[1].nodeValue = ' 成功把你从监狱里救了出来。'; return; } } /** * 保释 */ if ($(e).text().indexOf('bailed') >= 0) { const cost = e.childNodes[1].nodeValue.trim().slice(27, -1); e.childNodes[1].nodeValue = ' 花费 ' + cost + ' 保释了你。'; return; } /** * 收到帮派的钱 */ if ($(e).text().contains(/You were given \$[0-9,]+ from your faction/)) { const money = e.firstChild.nodeValue.split(' ')[3]; let isNamed = e.childNodes.length > 1; if (isNamed) { e.firstChild.nodeValue = ''; e.childNodes[2].nodeValue = ' 为你从帮派取了 ' + money + '。'; } else { e.firstChild.nodeValue = '你得到了从帮派取出的 ' + money + '。'; } return; } /** * 被下悬赏 */ if ($(e).text().contains(/has placed .+ bount.+ on you/)) { // 是否匿名 悬赏个数 悬赏单价 原因 const spl = $(e).text().trim().split(' '); const reasonSpl = $(e).text().trim().split(' and the reason: '); const someone = !e.children.length; const num = spl[3] === 'a' ? '1' : spl[3]; const price = reasonSpl[0].split(' ').slice(-1)[0]; const reason = reasonSpl[1] ? reasonSpl[1] : null; const trans = `${someone ? '某人' : ' '}对你进行了 ${num} 次赏金为 ${price} 的悬赏${reason ? ',原因:' + reason : ''}`; // 匿名悬赏 if (someone) { $(e).text(trans); } // 实名悬赏 else { $(e).contents().get(1).nodeValue = trans; } return; } /** * 成功复活 */ if ($(e).text().contains(/successfully revived you/)) { if (e.children.length !== 1) return; if (eventsDict[$(e).contents().get(1).nodeValue.trim()]) { $(e).contents().get(1).nodeValue = eventsDict[$(e).contents().get(1).nodeValue.trim()] } return; } /** * 失败复活 */ if ($(e).text().contains(/failed to revive you/)) { if (e.children.length !== 1) return; if (eventsDict[$(e).contents().get(1).nodeValue.trim()]) { $(e).contents().get(1).nodeValue = eventsDict[$(e).contents().get(1).nodeValue.trim()] } return; } /** * 收到帮派的pt */ if ($(e).text().contains(/You were given [0-9,]+ points? from your faction/)) { const pt = e.firstChild.nodeValue.split(' ')[3]; e.firstChild.nodeValue = '你得到了从帮派取出的 ' + pt + ' PT。' return; } /** * 帮派借东西 */ if ($(e).text().contains(/loaned you .+ from the faction armory/)) { const [num, item] = (() => { const spl = e.lastChild.nodeValue.trim().slice().slice(11, -25).split(' '); return spl.length === 1 ? [spl[0], null] : [spl[0], spl.slice(1).join(' ')]; })(); if (num && item) { e.lastChild.nodeValue = ` 从帮派军械库中借给你 ${num.numWordTrans()} ${item}。`; } return; } /** * 教育完成 * The education course you were taking has ended. Please click here. */ if ($(e).text().indexOf('edu') >= 0) { if ($(e).text().trim().split(' ')) e.firstChild.firstChild.nodeValue = '你的课程已学习结束,请点此继续。'; return; } /** * LSD od */ if ($(e).text().contains(/LSD .+ overdosed/)) { if (eventsDict[$(e).text().trim()]) $(e).text(eventsDict[$(e).text().trim()]); return; } /** * 公司申请 */ if ($(e).text().contains(/Your application to join the company .+ has been/)) { $(e).contents().each((i, e) => { if (e.nodeType === 3) { if (eventsDict[e.nodeValue.trim()]) { e.nodeValue = eventsDict[e.nodeValue.trim()]; } } }); return; } /** * 银行完成 */ if ($(e).text().contains(/Your bank investment has ended/)) { $(e).children().text('你的银行投资已经结束。请点击这里领取你的资金。'); return; } /** * 人物升级 * Congratulations! You upgraded your level to 31! */ if ($(e).text().indexOf('upgraded') >= 0) { const level = e.firstChild.nodeValue.slice(44, -2); e.firstChild.nodeValue = '恭喜!你已升至' + level + '级!'; return; } /** * 开新健身房 * You have successfully purchased membership in Deep Burn. * 你已成功购买Deep Burn的健身房会员卡。 */ if ($(e).text().contains(/You have successfully purchased membership in/)) { const gymName = e.firstChild.nodeValue.trim().slice(46, -1); e.firstChild.nodeValue = `你已购买【${gymList[gymName]}】健身房会员卡。`; return; } /** * 人物称号 */ if ($(e).text().contains(/You are now known in the city as a/)) { const trans = '现在你在这个城市中被称为'; const title = $(e).text().trim().split(' ').slice(9).join(' ').slice(0, -1); $(e).text(`${trans} ${title}。`); return; } /** * 收下线 */ if ($(e).text().contains(/You have successfully referred/)) { $(e).contents().each((i, e) => { // 文字 if (e.nodeType === 3) { if (eventsDict[e.nodeValue.trim()]) { e.nodeValue = eventsDict[e.nodeValue.trim()]; } } // referral list else if (e.nodeType === 1) { if (eventsDict[$(e).text().trim()]) { $(e).text(eventsDict[$(e).text().trim()]); } } }); return; } /** * new virus病毒 * You completed the Simple Virus which is now in your inventory. You can begin programming a new virus * here * . * * 你完成了 "简单病毒",它现在在你的库存中。你可以【点此】开始编程一个新的病毒。 */ if ($(e).text().indexOf('new virus') >= 0) { const virusName = e.firstChild.nodeValue.split(' ').slice(3, 5).join(' '); e.firstChild.nodeValue = `你完成了 ${virusName},它现在在你的物品库存中。你可以`; e.childNodes[1].firstChild.nodeValue = '点此'; e.childNodes[2].nodeValue = '开始编程一个新的病毒。'; return; } /** * 每月蓝星奖励 */ if ($(e).text().contains(/You found .+ and .+ on your doorstep/)) { const [item1, item2] = $(e).text().trim().slice(10, -18).split(' and '); const bookTitle = item2.contains(/a book titled/) ? item2.slice(15, -1) : null; if (bookTitle) { $(e).text(`你在家门口发现了 ${item1.numWordTrans()} 和《${bookTitle}》。`); } else { $(e).text(`你在家门口发现了 ${item1.numWordTrans()} 和 ${item2.numWordTrans()}。`); } return; } /** * 季度邮件奖励 if ($(e).text().contains(/used the reward bonus code/)) { const code = $(e).text().trim().split(' ')[7]; if (eventsDict[$(e).text().trim().replace(code, '{$}')]) $(e).text(eventsDict[$(e).text().trim().replace(code, '{$}')] .replace('{$}', code)); return; } /** * 求婚 */ if ($(e).text().contains(/accepted your proposal, you are now engaged/)) { const spouse = $(e).children(':first').text().trim(); if (e.childNodes[1]) { e.childNodes[1].nodeValue = ` 接受了你的求婚,你现在和 ${spouse} 订婚了!前往`; } if (e.childNodes[2] && e.childNodes[2].firstChild) { e.childNodes[2].firstChild.nodeValue = `这里`; } if (e.childNodes[3]) { e.childNodes[3].nodeValue = `完成仪式。`; } return; } /** * 帮派职位变更 * Your position in * Silver Hand * changed from Recruit to Knight. */ if ($(e).text().indexOf('position') >= 0) { let prePos, curPos; const node3Spl = e.childNodes[2].nodeValue.split(' to '); if (node3Spl.length === 2) { prePos = node3Spl[0].slice(14, node3Spl[0].length); curPos = node3Spl[1].slice(0, node3Spl[1].length - 2); } else { log('职位出现" to "');// todo return; } e.firstChild.nodeValue = '你在 '; e.childNodes[2].nodeValue = ` 的职位从 ${prePos} 变为 ${curPos}。`; return; } /** * 加入帮派结果 */ if ($(e).text().indexOf('join the faction') >= 0) { const rsName = e.childNodes[2].nodeValue.trim().split(' ')[2]; const rsDict = {'accepted': '通过', 'declined': '拒绝',}; e.firstChild.nodeValue = '加入帮派 '; e.childNodes[2].nodeValue = ` 的申请已${rsDict[rsName]}。`; return; } }); } // 页标题右侧按钮 function contentTitleLinksTrans() { const $links_default = document.querySelectorAll('div.content-title span:nth-child(2)'); const $links = $links_default.length === 0 ? document.querySelectorAll('div[class^="topSection"] span[class*="Title"]') : $links_default; $links.forEach(e => { if (titleLinksDict[e.innerText.trim()]) { e.innerText = titleLinksDict[e.innerText.trim()]; } else if (e.id === 'events') { if (titleLinksDict[e.innerText.trim().split(' ')[0]]) e.innerText = e.innerText.trim() .replace( e.innerText.trim().split(' ')[0], titleLinksDict[e.innerText.trim().split(' ')[0]] ); } }); } function contentTitleLinksTransReact(dom = document.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]')) { dom.forEach(e => { const links_trans = titleLinksDict[e.innerText.trim()]; if (links_trans) e.innerText = links_trans; }); } /** * 页标题翻译 */ function titleTrans() { const $title = $('h4#skip-to-content').length === 0 ? $('h4[class^="title"]') : $('h4#skip-to-content'); const title = titleDict[$title.text().trim()] || cityDict[$title.text().trim()]; if (title && $title.css('display') !== 'none') $title.after($title.clone().text(title)).css('display', 'none'); } function titleTransReact(dom = document.querySelectorAll('h4[class^="title___"]')) { dom.forEach(e => { const title_trans = titleDict[e.innerText.trim()]; if (title_trans) e.innerText = title_trans; }); } /** * 任务助手 */ function getTaskHint(task_name) { task_name = task_name .toLowerCase() .replaceAll(' ', '_') .replaceAll('-', '_') .replaceAll(',', ''); if (!missionDict._taskHint[task_name]) return '暂无,请联系开发者'; const task = missionDict._taskHint[task_name].task || null; const hint = missionDict._taskHint[task_name].hint || null; return `${task ? '任务要求:' + task : '暂无,请联系Woohoo'}${hint ? '
提示:' + hint : ''}`; } /* 展开物品详情 */ function showItemInfoTrans(dom = document.querySelector('.show-item-info')) { if (dom) { const $item_info = dom.querySelector('span.info-msg'); if ($item_info) { // tt插件 const is_tt_modified = !!$item_info.querySelector('.tt-modified'); if (is_tt_modified) { console.warn(is_tt_modified) } // 物品名 const $item_name = $item_info.querySelector('span.bold'); // 去除物品名的the const the_removed = $item_name.innerText.trim().slice(4); // 物品的类别 const $item_type = $item_name.nextSibling; // 绿字 物品效果 const $item_effect = $item_info.querySelector('div.item-effect'); if (itemNameDict[the_removed]) { $item_name.innerText = `${itemNameDict[the_removed]}(${the_removed})`; } if (itemTypeDict[$item_type.nodeValue.trim()]) { $item_type.nodeValue = itemTypeDict[$item_type.nodeValue.trim()]; } if ($item_effect && itemEffectDict[$item_effect.innerText.trim()]) { $item_effect.innerText = itemEffectDict[$item_effect.innerText.trim()]; } } // 下方的表格 const $info_table_title = dom.querySelectorAll('div.title'); $info_table_title.forEach((e) => { if (itemPageDict[e.innerText.trim()]) { e.innerText = itemPageDict[e.innerText.trim()]; } }); } } /* ob */ function initOB(dom = document, opt = {}, func = doNothing, dev = false, once = false) { //let count = -1; if (dev) { const mo = new MutationObserver((mutation) => { //count++; log(mutation) mo.disconnect(); func(); if (!once) { mo.observe(dom, opt) } }); func(); mo.observe(dom, opt); } else { //count++; const mo = new MutationObserver(() => { mo.disconnect(); func(); if (!once) mo.observe(dom, opt) }); func(); mo.observe(dom, opt) } } /** * 添加全局style * @param {CSSRule.cssText|String} css CSS规则 */ function addStyle(css) { let wh_gStyle = document.querySelector('style#wh-trans-gStyle'); if (wh_gStyle) { wh_gStyle.innerHTML += css; } else { wh_gStyle = document.createElement("style"); wh_gStyle.id = 'wh-trans-gStyle'; wh_gStyle.innerHTML = css; document.head.append(wh_gStyle); } log('CSS规则已添加', wh_gStyle); } /* 添加左侧图标 */ function initIcon(settings) { if (isIframe || !!document.querySelector('div#wh-trans-icon')) return; const zhong_node = document.createElement('div'); zhong_node.id = 'wh-trans-icon'; zhong_node.classList.add('cont-gray'); zhong_node.innerHTML = `
芜湖助手

当前版本: ${version.slice(-1) === '$' ? 'DEV' : version}

最新版本:

`; // 助手菜单 const menu_cont = zhong_node.querySelector('#wh-gSettings'); // 设置选项 zhong_node.setting_root = document.createElement('div'); zhong_node.setting_root.classList.add('gSetting'); // 遍历菜单node设置 settings.forEach(setting => { // if (!setting['isHide']) { elemGenerator(setting, menu_cont); // 最后移动节点 // zhong_node.setting_root.appendChild(new_node); // setting['isHide'] ? zhong_node.setting_root.appendChild(new_node) : menu_cont.appendChild(new_node); // } }); // 计时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 => { // e.stopImmediatePropagation(); log(e.target); if (e.target === zhong_node.querySelector('#wh-trans-icon-btn')) return; if (!zhong_node.contains(e.target)) { log('移除事件监听器'); document.body.removeEventListener('click', click_func); zhong_node.classList.remove('wh-icon-expanded'); } }; if (zhong_node.classList.contains('wh-icon-expanded')) { log('添加事件监听器'); document.body.addEventListener('click', click_func); } else { log('移除事件监听器'); document.body.removeEventListener('click', click_func); } }; // 更新按钮点击事件 zhong_node.querySelector('#wh-update-btn').onclick = e => { e.target.blur(); const innerHtml = `

电脑

通常电脑浏览器装有油猴等用户脚本扩展时可以使用链接安装(自动更新):点此安装

这些扩展长这样:tm.pngvm.png

手机

安卓 KIWI 等可以用油猴脚本的浏览器也可以点上面的链接安装👆

Torn PDA app 或 Alook 用户可打开这个网页快捷复制粘贴。

直接复制

加载脚本然后直接复制粘贴到用户脚本处。

`; const node = popupMsg(innerHtml, '如何更新'); // 直接复制的按钮 node.querySelector('button').onclick = async (e) => { e.target.innerHTML = '加载中'; const js_text = await COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${performance.now()}`); e.target.innerHTML = '点击复制到剪切板'; e.target.onclick = () => { const textarea_node = document.createElement('textarea'); textarea_node.innerHTML = js_text; e.target.parentElement.append(textarea_node); textarea_node.focus(); textarea_node.select(); document.execCommand('Copy'); textarea_node.remove(); e.target.innerHTML = '已复制'; e.target.onclick = null; WHNotify('脚本已复制,请前往粘贴'); }; }; }; // 节日 zhong_node.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0 ? el.addEventListener('click', () => { let html = ''; menu_list.fest_date_list.sort().forEach(date => html += ``); popupMsg(html += '
${1 + (date.slice(0, 2) | 0)}月${date.slice(2)}日${menu_list.fest_date_dict[date].name}${menu_list.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 = ''; menu_list.events.forEach(el => html += ``); popupMsg(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自带浮动提示 (window['initializeTooltip']) && (window['initializeTooltip']('.wh-container', 'white-tooltip')); // 加载torn mini profile initMiniProf('#wh-trans-icon'); return zhong_node; } // bool 返回当前是否dev状态 function isDev() { try { return getWhSettingObj()['isDev'] || false; } catch (e) { console.error(`[wh] dev状态错误 ${e}`); return false; } } /** * 弹出窗口 * @param {String} innerHTML 内容html string * @param {String} title 弹窗标题 * @returns {null|Element} */ function popupMsg(innerHTML, title = '芜湖助手') { if (popup_node) popup_node.close(); const chatRoot = document.querySelector('#chatRoot'); chatRoot.classList.add('wh-hide'); const popup = document.createElement('div'); popup.id = 'wh-popup'; popup.innerHTML = `

${title}

${innerHTML}
`; document.body.append(popup); const rt = popup.querySelector('#wh-popup-cont'); rt.close = function () { popup.remove(); chatRoot.classList.remove('wh-hide'); } popup.addEventListener('click', e => { e.stopImmediatePropagation(); if (e.target === popup) rt.close(); }); popup_node = rt; return rt; } /** * 通过 mutation.observe 方法异步返回元素 * @param {String} selector - CSS规则的HTML元素选择器 * @param {Document} content - 上下文 * @returns {Promise} */ function elementReady(selector, content = document) { return new Promise((resolve, reject) => { let el = content.querySelector(selector); if (el) { resolve(el); return } new MutationObserver((mutationRecords, observer) => { // Query for elements matching the specified selector Array.from(content.querySelectorAll(selector)).forEach((element) => { resolve(element); //Once we have resolved we don't need the observer anymore. observer.disconnect(); }); }) .observe(content.documentElement, {childList: true, subtree: true}); }); } // 得到一个两数之间的随机整数 function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值 } // 用户脚本平台类型 function getScriptEngine() { return UWCopy ? UserScriptEngine.GM : PDA_APIKey.slice(-1) !== '#' ? UserScriptEngine.PDA : UserScriptEngine.RAW; } // 用户设备类型 对应PC MOBILE TABLET function getDeviceType() { return window.innerWidth >= 1000 ? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET; } // 跨域get请求 返回text function COFetch(url, method = 'get', body = null) { const engine = getScriptEngine(); switch (engine) { case UserScriptEngine.RAW: { return new Promise((_, reject) => { console.error(`[wh] 跨域请求错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`); reject(`错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`); }); } case UserScriptEngine.PDA: { const {PDA_httpGet, PDA_httpPost} = window; return method === 'get' ? // get new Promise((resolve, reject) => { if (typeof PDA_httpGet !== 'function') { console.error('[wh] 跨域请求错误:PDA版本不支持'); reject('错误:PDA版本不支持'); } PDA_httpGet(url) .catch(e => { console.error('[wh] 网络错误', e); reject(`[wh] 网络错误 ${e}`); }) .then(res => resolve(res.responseText)); }) : // post new Promise((resolve, reject) => { if (typeof PDA_httpPost !== 'function') { console.error('[wh] 跨域请求错误:PDA版本不支持'); reject('错误:PDA版本不支持'); } PDA_httpPost(url, {'content-type': 'application/json'}, body) .catch(e => { console.error('[wh] 网络错误', e); reject(`[wh] 网络错误 ${e}`); }) .then(res => resolve(res.responseText)); }); } case UserScriptEngine.GM: { return new Promise((resolve, reject) => { if (typeof GM_xmlhttpRequest !== 'function') { console.error('[wh] 跨域请求错误:用户脚本扩展API错误'); reject('错误:用户脚本扩展API错误'); } GM_xmlhttpRequest({ method: method, url: url, data: method === 'get' ? null : body, headers: method === 'get' ? null : {'content-type': 'application/json'}, onload: res => resolve(res.response), onerror: res => reject(`连接错误 ${JSON.stringify(res)}`), ontimeout: res => reject(`连接超时 ${JSON.stringify(res)}`), }); }); } } } // 简单 object 转字符串 function Obj2Str(obj) { return JSON.stringify(obj); } // console.log改写 function log(...o) { if (isDev()) console.log('[WH]', ...o) } /** * 通知方法 * @param {string} msg - 通知内容 * @param {Object} [options] - 通知选项 * @param {number} [options.timeout] - 通知超时时间 * @param {function} [options.callback] - 通知回调 * @param {boolean} [options.sysNotify] - 是否开启系统通知 * @param {string} [options.sysNotifyTag] - 系统通知标记 * @param {function} [options.sysNotifyClick] - 系统通知点击事件 * @return {HTMLElement} */ function WHNotify(msg, options = {}) { let { timeout = 3, callback = doNothing, sysNotify = false, sysNotifyTag = '芜湖助手', sysNotifyClick = () => window.focus() } = options; if (!isWindowActive() || isIframe) return null; const date = new Date(); // 通知的唯一id const uid = `${date.getHours()}${date.getSeconds()}${date.getMilliseconds()}${getRandomInt(1000, 9999)}`; // 通知容器id const node_id = 'wh-notify'; // 通知的容器 let notify_contain = document.querySelector(`#${node_id}`); // 添加通知到容器 const add_notify = () => { // 每条通知 const new_node = document.createElement('div'); new_node.id = `wh-notify-${uid}`; new_node.classList.add('wh-notify-item'); new_node.innerHTML = `

${msg}

`; notify_contain.append(new_node); notify_contain.msgInnerText = new_node.querySelector('.wh-notify-msg').innerText; // 进度条node const progressBar = new_node.querySelector('.wh-notify-bar'); // 是否hover let mouse_enter = false; new_node.addEventListener('mouseenter', () => mouse_enter = true, true); new_node.addEventListener('mouseleave', () => mouse_enter = false); // 通知进度条 let progressCount = 101; // 删除通知 new_node.close = () => { clearInterval(intervalID); new_node.remove(); callback(); }; // 计时器 let intervalID = window.setInterval(() => { if (mouse_enter) { progressCount = 101; progressBar.style.width = '100%'; return; } progressCount--; progressBar.style.width = `${progressCount}%`; if (progressCount === 0) new_node.remove(); }, timeout * 1000 / 100); new_node.querySelector('.wh-notify-close').addEventListener('click', new_node.close); return new_node; }; // 不存在容器 创建 if (!notify_contain) { notify_contain = document.createElement('div'); notify_contain.id = node_id; addStyle(` #${node_id} { display: inline-block; position: fixed; top: 0; left: calc(50% - 180px); width: 360px; z-index: 9999990; color:#333; } #${node_id} a{ color:red; text-decoration:none; } #${node_id} .wh-notify-item { /*height: 50px;*/ background: rgb(239 249 255 / 90%); border-radius: 2px; margin: 0.5em 0 0 0; box-shadow: 0 0 5px 0px #959595; } #${node_id} .wh-notify-item:hover { background: rgb(239 249 255 / 98%); } #${node_id} .wh-notify-item .wh-notify-bar { height:2px; background:#2196f3; } #${node_id} .wh-notify-item .wh-notify-close { float:right; padding:0; width:16px;height:16px; background:url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%201024%201024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M923%20571H130.7c-27.6%200-50-22.4-50-50s22.4-50%2050-50H923c27.6%200%2050%2022.4%2050%2050s-22.4%2050-50%2050z%22%20fill%3D%22%232196f3%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E') no-repeat center; background-size:100%; margin: 6px 6px 0 0; cursor: pointer; } #${node_id} .wh-notify-item .wh-notify-msg { padding:12px; } `); document.body.append(notify_contain); } const notify_obj = add_notify(); // 浏览器通知 if (window.Notification && Notification.permission === 'granted' && sysNotify) { const date_local_string = `[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}]\r`; notify_obj.sys_notify = new Notification('芜湖助手', { body: date_local_string + notify_contain.msgInnerText, requireInteraction: true, renotify: true, tag: sysNotifyTag + getRandomInt(0, 99), }); notify_obj.sys_notify.onclick = sysNotifyClick; notify_obj.sys_notify.onshow = () => setTimeout(() => notify_obj.sys_notify.close(), timeout * 1000); notify_obj.sys_notify.id = notifies.count++; notifies[notify_obj.sys_notify.id] = notify_obj.sys_notify; notify_obj.sys_notify.addEventListener('close', () => notifies[notify_obj.sys_notify.id] = null); } return notify_obj; } // gs loader function loadGS(use) { if (use === UserScriptEngine.PDA) { let ifr = document.querySelector('#wh-gs-loader-ifr'); if (ifr) { WHNotify('飞贼小助手已经加载了'); return; } const container = document.createElement('div'); container.id = 'wh-gs-loader'; ifr = document.createElement('iframe'); ifr.id = 'wh-gs-loader-ifr'; ifr.src = 'https://www.torn.com/crimes.php'; container.append(ifr); document.body.append(container); addStyle(` #wh-gs-loader { position:fixed; top:0; left:0; z-index:100001; } `); let notify = WHNotify('加载中'); ifr.onload = () => { notify.del(); const _window = ifr.contentWindow; const _docu = _window.document; _docu.head.innerHTML = ''; _docu.body.innerHTML = ''; notify = WHNotify('加载依赖'); COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js') .then(vuejs => { notify.del(); _window.eval(vuejs) _window.GM_getValue = (k, v = undefined) => { const objV = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}')[k]; return objV || v; }; _window.GM_setValue = (k, v) => { const obj = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}'); obj[k] = v; _window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj)); }; _window.GM_xmlhttpRequest = function (opt) { // 暂不适配pda post if (opt.method.toLowerCase() === 'post') return; COFetch(opt.url).then(res => { const obj = {}; obj.responseText = res; opt.onload(obj); }); }; notify = WHNotify('加载飞贼小助手'); COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${performance.now()}`) .then(res => { _window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`)); _window.GM_setValue("gsp_x", 10); _window.GM_setValue("gsp_y", 10); notify.del(); notify = WHNotify('飞贼小助手已加载', {timeout: 1}); const gsp = _docu.querySelector('#gsp'); const init = () => { ifr.style.height = `${gsp.offsetHeight + 10}px`; ifr.style.width = `${gsp.offsetWidth + 20}px`; gsp.style.top = '10px'; gsp.style.left = '10px'; }; new MutationObserver(init).observe(gsp, {childList: true, subtree: true}); init(); if (isDev()) _window.GM_setValue("gsp_showContent", true) }); }); }; return; } if (use === UserScriptEngine.GM) { if (typeof window.Vue !== 'function') { let notify = WHNotify('正在加载依赖'); COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js') .catch(err => WHNotify(Obj2Str(err))) .then(VueJS => { window.eval(VueJS); notify.del(); notify = WHNotify('已载入依赖'); window.GM_getValue = (k, v = undefined) => { const objV = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}')[k]; return objV || v; }; window.GM_setValue = (k, v) => { const obj = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}'); obj[k] = v; window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj)); }; window.GM_xmlhttpRequest = GM_xmlhttpRequest; COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${performance.now()}`) .then(GSJS => { window.eval(GSJS); if (isDev()) window.GM_setValue("gsp_showContent", true); notify.del(); notify = WHNotify('已载入飞贼助手'); }) .catch(err => WHNotify(`PDA API错误。${Obj2Str(err)}`)); }); } else { WHNotify('飞贼助手已经加载了'); } return; } WHNotify('暂不支持'); } /** * 播放音频 * @param {string} url 播放的音频URL * @returns {undefined} */ function audioPlay(url = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3') { const audio = new Audio(url); audio.addEventListener("canplaythrough", () => { audio.play() .catch(err => log(err)) .then(); }); } // 格式化金额数字 function toThousands(num) { num = (num || 0).toString(); let result = ''; while (num.length > 3) { result = ',' + num.slice(-3) + result; num = num.slice(0, num.length - 3); } if (num) { result = num + result; } return result; } // 插件的配置 getter function getWhSettingObj() { return JSON.parse(localStorage.getItem('wh_trans_settings')) || {} } // 插件的配置 setter function setWhSetting(key, value, notify = true) { const obj = getWhSettingObj() obj[key] = value localStorage.setItem('wh_trans_settings', JSON.stringify(obj)) // 通知 if (notify) WHNotify('已保存设置') } // 价格监视handle function priceWatcherHandle() { setInterval(() => { const price_conf = getWhSettingObj()['priceWatcher']; const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey'); if (!apikey) { log('无法获取APIKey') return; } if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt']).then(); if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then(); }, 10000) return {status: true}; } // pt价格监视 async function priceWatcherPt(apikey, lower_price) { if (!priceWatcher['watch-pt-lower-id']) priceWatcher['watch-pt-lower-id'] = []; const res = await fetch('https://api.torn.com/market/?selections=pointsmarket&key=' + apikey); const obj = await res.json(); if (obj['pointsmarket']) { // 过滤低于价格的物品出售id const lower_arr = []; let low = Infinity; Object.keys(obj['pointsmarket']).forEach(key => { if (obj['pointsmarket'][key]['cost'] <= lower_price) { lower_arr.push(key); if (obj['pointsmarket'][key]['cost'] < low) low = obj['pointsmarket'][key]['cost']; } }); if (lower_arr.length === 0) return; // 将id与之前存在的比较,不相同时发送通知 if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) { priceWatcher['watch-pt-lower-id'] = lower_arr; WHNotify(`PT新低价:$${toThousands(low)}( < $${toThousands(lower_price)}) - 点击转跳`, { timeout: 6, sysNotify: true, sysNotifyClick: () => window.open('https://www.torn.com/pmarket.php'), }); } } else { // 查询出错了 log('pt查询出错了') } } // xan价格监视 async function priceWatcherXan(apikey, lower_price) { // 初始化记录上一个条目的id,避免重复发送通知 if (!priceWatcher['watch-xan-lower-id']) priceWatcher['watch-xan-lower-id'] = ''; const res = await fetch('https://api.torn.com/market/206?selections=bazaar&key=' + apikey); const obj = await res.json(); if (obj['bazaar']) { const lowest_item = obj['bazaar'][0] if (lowest_item['cost'] <= lower_price) { if (priceWatcher['watch-xan-lower-id'] !== lowest_item['ID']) { priceWatcher['watch-xan-lower-id'] = lowest_item['ID']; WHNotify(`XAN新低价:$${toThousands(lowest_item['cost'])}( < $${toThousands(lower_price)}) - 点击转跳`, { timeout: 6, sysNotify: true, sysNotifyClick: () => window.open('https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax') }); } } } else { // 查询出错了 log('xan查询出错了') } } // 空函数 function doNothing() { } // 返回UUID function uuidv4() { if (crypto.randomUUID) return crypto.randomUUID(); return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } // 返回一个可用查询当前窗口是否激活的函数 function getWindowActiveState() { if (isIframe) return false; const uuid = uuidv4(); let isFocus = false; localStorage.setItem('whuuid', uuid); document.addEventListener('visibilitychange', () => (document.visibilityState !== 'hidden') && (localStorage.setItem('whuuid', uuid)) ); addEventListener('focus', () => isFocus = true) addEventListener('blur', () => isFocus = false) return function () { // 当前窗口获得了焦点 优先级最高 if (isFocus) return true; // 可视性 if (!document.hidden) return true; // 全部在后台,使用唯一id判断 return uuid === localStorage.getItem('whuuid') }; } // 翻译 function transToZhCN(href, onoff) { if (!onoff) return; // 时分秒转换 String.prototype.replaceHMS = function replaceHMS() { return this.replace('and', '') .replace('days', '天') .replace('days', '天') .replace('hours', '小时') .replace('hour', '小时') .replace('minutes', '分钟') .replace('minute', '分钟') .replace('seconds', '秒钟') .replace('second', '秒钟'); }; // 数词转换 a an some String.prototype.numWordTrans = function numWordTrans() { return this.replace(/\ban\b/, '1 个') .replace(/\ba\b/, '1 个') .replace(/\bsome\b/, '1 个') .replace(/([0-9])x\b/, '$1 个'); }; // 边栏 let sidebarTimeOut = 60; const sidebarInterval = setInterval(() => { // 60秒后取消定时 if ($('div[class^="sidebar"]').length === 0) { sidebarTimeOut--; if (sidebarTimeOut < 0) { clearInterval(sidebarInterval); } return; } // 边栏块标题 $('h2[class^="header"]').each((i, e) => { if (!sidebarDict[e.firstChild.nodeValue]) return; e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; }); // 边栏人物名字 $('span[class^="menu-name"]').each((i, e) => { e.firstChild.nodeValue = '名字:'; }); // 钱 等级 pt 天赋点 $('p[class^="point-block"]').each((i, e) => { if (sidebarDict[e.firstChild.firstChild.nodeValue]) e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue]; }); // 4条 状态条 $('p[class^="bar-name"]').each((i, e) => { if (sidebarDict[e.firstChild.nodeValue]) e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; }); // 边栏菜单 $('span[class^="linkName"]').each((i, e) => { if (sidebarDict[e.firstChild.nodeValue]) e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; }); // [use]按钮 if (document.querySelector('#pointsMerits')) $('#pointsMerits')[0].firstChild.nodeValue = '[使用]'; if (document.querySelector('#pointsPoints')) $('#pointsPoints')[0].firstChild.nodeValue = '[使用]'; if (document.querySelector('#pointsLevel')) $('#pointsLevel')[0].firstChild.nodeValue = '[升级]'; // 手机 区域菜单 $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => { //log(e); if (sidebarDict[e.nodeValue]) e.nodeValue = sidebarDict[e.nodeValue]; }); clearInterval(sidebarInterval); }, 1000); // header if (document.querySelector('div#header-root')) { const headerOB = new MutationObserver(_ => { headerOB.disconnect(); headerTrans(); headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); }); const headerTrans = function headerTrans() { // 搜索内容下拉框中的文字 已选中 if (headerDict[$('div.find button.toggler.down').text()]) $('div.find button.toggler.down').text(headerDict[$('div.find button.toggler.down').text()]); // pc端 搜索下拉框点击后的搜索类型文字 $('div.find li.item').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // 手机端 搜索下拉框点击后的搜索类型文字 $('li[class^="search-type-"] label').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // 搜索框placeholder if (headerDict[$('input[class^="searchInput"]').attr('placeholder')]) $('input[class^="searchInput"]').attr('placeholder', headerDict[$('input[class^="searchInput"]').attr('placeholder')]); // 高级搜索框 search by if (headerDict[document.querySelector('div#header-root legend.title').innerText]) $('div#header-root legend.title').text(headerDict[$('div#header-root legend.title').text()]); // 高级搜索框的条件 左 键 $('ul.advancedSearchFormBody label.label').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // 高级搜索框的已选中 $('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => { // log($(e).text()) if (headerDict[$(e).text().trim()]) $(e).text(headerDict[$(e).text().trim()]); else if (propertyDict[$(e).text().trim()]) $(e).text(propertyDict[$(e).text().trim()]); }); // 高级搜索的下拉选项 $('ul.advancedSearchFormBody li.item').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); else if (propertyDict[$(e).text()]) $(e).text(propertyDict[$(e).text()]); }); // 高级搜索的"Not" $('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // 高级搜索的"to" $('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // 高级搜索的reset search按钮 $('form.form-search-extend div.bottom button').each((i, e) => { if (headerDict[$(e).text()]) $(e).text(headerDict[$(e).text()]); }); // log按钮“view log” const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]') if (headerDict[$view_log.text().trim()]) $view_log .text(headerDict[$view_log.text().trim()]); // 点击头像打开的菜单 $('ul.settings-menu span').each((i, e) => { if (headerDict[$(e).text()] && e.childNodes.length === 1) $(e).text(headerDict[$(e).text()]); else if (e.childNodes.length === 3) if (headerDict[e.firstChild.nodeValue]) e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue]; }); }; headerTrans(); headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); } // chatbox if (document.querySelector('div#chatRoot')) { const chatOB = new MutationObserver(_ => { chatOB.disconnect(); chatTrans(); chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); }); const chatTrans = function chatTrans() { // 聊天框的标题 $('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => { if (chatDict[$(e).text().trim()]) $(e).text(chatDict[$(e).text().trim()]); }); // 聊天设置的左边label $('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => { if ($(e).next().children('div.rc-slider').length > 0) { // 高度和宽度有响应式的% if (chatDict[$(e).text().split(' ')[0]]) { $(e).text($(e).text().replace($(e).text().split(' ')[0], chatDict[$(e).text().split(' ')[0]])); } return; } if (chatDict[$(e).text().trim()]) $(e).text(chatDict[$(e).text().trim()]); }); // 选项下拉栏 $('div[class^="dropdown-root"]').find('*').contents().each((i, e) => { if (e.nodeType !== 3) return; if (chatDict[e.nodeValue]) e.nodeValue = chatDict[e.nodeValue]; }); // 设置的两个选项 $('label[class^="privacy-label"]').each((i, e) => { if (chatDict[$(e).text().trim()]) $(e).text(chatDict[$(e).text().trim()]); }); // people中的5个分类 faction friend... $('ul[class^="type-list"] li a').each((i, e) => { if (chatDict[$(e).text().trim()]) $(e).text(chatDict[$(e).text().trim()]); }); // people中的列表添加框placeholder $('div.ac-wrapper input.ac-search').each((i, e) => { if (chatDict[$(e).attr('placeholder')]) $(e).attr('placeholder', chatDict[$(e).attr('placeholder')]); }); // if (eventsDict[$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').text().trim()]) { $('div#chatRoot div[class^="overview"] > div > div:nth-child(2)') .text( eventsDict[document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').innerText.trim()] ); } }; chatTrans(); chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); } // 搜索玩家的4个分类按钮 const playerSearchBoxTrans = function playerSearchBoxTrans() { const opt = { childList: true, subtree: true, }; const psbtOB = new MutationObserver(mutation => { const $people_cat = $('ul.ac-options li a'); psbtOB.disconnect(); mutation.forEach((e) => { if (e.target.className === 'ac-wrapper') { $people_cat.each((i, e) => { if (chatDict[$(e).text().trim()]) $(e).text(chatDict[$(e).text().trim()]); }); } }) psbtOB.observe(document.body, opt); }); psbtOB.observe(document.body, opt); } playerSearchBoxTrans(); // 飞行页面 if (href.includes('index.php') && !!document.querySelector('div.travelling h4')) { const travelOB = new MutationObserver(travelOBInit); function travelOBInit() { travelOB.disconnect(); travelTrans(); travelOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); } function travelTrans() { titleTrans(); contentTitleLinksTrans(); // 气泡 if (tipsDict[document.querySelector('div.inner-popup').innerText.trim()]) $('div.inner-popup').text(tipsDict[$('div.inner-popup').text().trim()]); // Remaining Flight Time - $('div.destination-title span').contents().each((i, e) => { if (e.childNodes.length !== 0) return; if (!e.nodeValue) return; if (travelingDict[e.nodeValue.trim()]) e.nodeValue = travelingDict[e.nodeValue.trim()]; }); // torntools扩展插件落地时间 if (document.querySelector('div.tt-landing-time span.description').innerText.split(' ')[0] === 'Landing') { const landingTime = $('div.tt-landing-time span.description').text().slice(11, 19); $('div.tt-landing-time span.description').text('于 ' + landingTime + ' 降落'); } } travelTrans(); travelOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); } // 主页 if (href.contains(/index\.php/) && document.querySelector('h4#skip-to-content').innerText.contains(/Home/)) { titleTrans(); contentTitleLinksTrans(); // 主页黑框标题文字翻译 $('h5.box-title').each((i, e) => { if (!homeDict[e.firstChild.nodeValue]) return; // 翻译最近5条通知 if (e.firstChild.nodeValue === 'Latest Events') { //homeEvents = $(e).parent().next().find('span'); eventsTrans($(e).parent().next().find('span')); } // 翻译最近5个攻击 else if (e.firstChild.nodeValue === 'Latest Attacks') { $(e).parent().next().find('span').each(function () { let nodes = $(this)[0].childNodes; nodes.forEach((v, i) => { if (v.nodeValue !== null) { let waitToTsf = v.nodeValue.toString().indexOf(" "); let words = v.nodeValue.replace("\n", "").toString().split(" "); words.forEach((word, j) => { if (attackDict.hasOwnProperty(word)) { if (word === "Someone") { $(this)[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", ""); } let change = $(this)[0].childNodes[i].nodeValue.replace(word, attackDict[word]); $(this)[0].childNodes[i].nodeValue = change; } }) } }, this); }); } //e.firstChild.nodeValue = homeDict[e.firstChild.nodeValue]; // 隐藏原dom元素避免与torntools发生冲突 if ($(e).css('display') !== 'none') $(e).css('display', 'none').after(`
` + homeDict[e.firstChild.nodeValue] + `
`); }); // 各表格左边的键 $('span.divider span').each((i, e) => { if (homeDict[$(e).text()]) $(e).text(homeDict[$(e).text()]); }); return; } // city if (href.includes('city.php')) { const cityOB = new MutationObserver(cityOBInit); function cityOBInit() { cityOB.disconnect(); cityTrans(); cityOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); } function cityTrans() { titleTrans(); contentTitleLinksTrans(); // Map or Quick Links $('a.ui-tabs-anchor span').each((i, e) => { if (cityDict[$(e).text()]) $(e).text(cityDict[$(e).text()]); }); // 标志建筑 标题 if (cityDict[$('div.title-black').text()]) $('div.title-black').text(cityDict[$('div.title-black').text()]); // 标志建筑 6个分类 $('ul.map-symbols span').each((i, e) => { if (cityDict[$(e).text()]) $(e).text(cityDict[$(e).text()]); }); // 地图显示模式 // 不完全显示 文字 $('span.inactive-mode').html(cityDict['inactive-mode1'] + `
` + cityDict['inactive-mode2']); // 完全显示 文字 $('span.active-mode').text(cityDict['active-mode']); // 开关 $('div.on-label').text('已开启'); $('div.off-label').text('已关闭'); // 快速链接中的分类标题 $('li.title').each((i, e) => { if (cityDict[$(e).text()]) $(e).text(cityDict[$(e).text()]); }); // 快速链接中的区域 $('li a[class^="font-num-"] span').each((i, e) => { // log($(e).prev().attr('class')==='cql-gym') if (cityDict[$(e).text()]) { $(e).text(cityDict[$(e).text()]); } else if ($(e).prev().attr('class') === 'cql-your-property') { if (propertyDict[$(e).text().trim().slice(5)]) { $(e).text('你的' + propertyDict[$(e).text().trim().slice(5)]); } } else if ($(e).prev().attr('class') === 'cql-gym') { if (gymList[$(e).text().trim()]) { $(e).text(gymList[$(e).text()]); } else if (gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]) { $(e).text(gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]); } } }); // 快速链接中的分类选择 $('div.sort-by label.marker-css').each((i, e) => { if (cityDict[$(e).text()]) $(e).text(cityDict[$(e).text()]); }); // 快速链接中的sort by $('span#wai-sort-by').each((i, e) => { if (cityDict[$(e).text()]) $(e).text(cityDict[$(e).text()]); }); } cityTrans(); cityOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); return; } // gym健身房页面 if (href.includes('gym.php')) { const gymOB = new MutationObserver(gymOBInit); function gymOBInit() { gymOB.disconnect(); gymTrans(); gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); } function gymTrans() { titleTrans(); contentTitleLinksTrans(); const gymName = $('div[class^="notificationText"] b').text(); // 顶部提示信息 $('div[class^="notificationText"] p').contents().each((i, e) => { if (e.nodeName === 'B' && gymList[$(e).text().trim()]) { $(e).text(gymList[$(e).text().trim()]); return; } if (e.childNodes.length === 0 && gymDict[e.nodeValue.trim()]) e.nodeValue = gymDict[e.nodeValue.trim()]; }); // 4属性标题 $('h3[class^="title"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 4属性的介绍 与冰蛙冲突 $('div[class^="description"] p:nth-child(1)').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 每次锻炼的花销 $('div[class^="description"] p:nth-child(2)').each((i, e) => { if (e.childNodes.length === 1) { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); } else if (e.childNodes.length === 2) { if (gymDict[e.lastChild.nodeValue.trim()]) { e.lastChild.nodeValue = gymDict[e.lastChild.nodeValue.trim()]; } } }); // 锻炼页面所有按钮 $('button[class^="button"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // cancel按钮 $('button[class^="cancel"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 锻炼的提示信息 $('div[class^="messageWrapper"] p').each((i, e) => { /** * todo *

You dug deep and completed 15 minutes of incline sprints

* */ if (gymDict[$(e).text()]) $(e).text(gymDict[$(e).text()]); }); // 健身房信息 标题 $('div[class^="gymTitle"] h3').each((i, e) => { if (gymDict[$(e).text()]) $(e).text(gymDict[$(e).text()]); else if (gymList[$(e).text().trim()]) $(e).text(gymList[$(e).text().trim()]); }); // 健身房信息 属性名 $('ul[class^="gymInfo"] b').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 健身房状态信息 // $('div[class^="gymStats"] b').each((i, e) => { // log(e) // if (gymDict[$(e).text().trim()]) // $(e).text(gymDict[$(e).text().trim()]); // }); // // // 健身房状态值 // $('div[class^="gymStats"] span[class^=value]').each((i, e) => { // if ($(e).text().indexOf("per train") > 0) // $(e).text($(e).text().split(" ")[0] + gymDict["per train"]); // else if (gymDict[$(e).text().trim()]) // $(e).text(gymDict[$(e).text().trim()]); // }); // 健身房信息 属性值 $('ul[class^="gymInfo"] span[class^="value"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 健身房信息 具体锻炼项目 $('span[class^="exerciseName"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); // 购买提示信息 $('div[class^="confirmMessage"] p[role="alert"]').each((i, e) => { if (gymDict[$(e).text().trim()]) $(e).text(gymDict[$(e).text().trim()]); }); } gymTrans(); gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); return; } // 物品页面 if (href.contains(/item\.php/)) { if (href.includes('item.php?temp=')) return; // 标题和右边的链接 initOB(document.querySelector('.content-title'), {childList: true}, () => { titleTrans(); contentTitleLinksTrans(); }); // 套装预览中间的文字 const $loadouts_root = document.getElementById('loadoutsRoot'); if ($loadouts_root) { initOB($loadouts_root, {subtree: true, attributes: true}, () => { const el = $loadouts_root.querySelector('div[class^="type___"]'); if (el && itemPageDict[el.innerText.trim()]) { el.innerText = itemPageDict[el.innerText.trim()]; } }); } // 手机选项按钮 物品名 物品详情 const options = { attributes: true, subtree: true, attributeFilter: ["aria-hidden",] }; const translated = {cat: '', count: -1}; const translatedOnce = {item_opt: -1, opt_icon_count: -1}; initOB(document.getElementById('category-wrap'), options, () => { // 手机操作选项 const $item_opt = document.querySelectorAll(`ul.itemsList span.opt-name`); if (translatedOnce.item_opt !== $item_opt.length - 1) { let count = -1; $item_opt.forEach((e, i) => { if (itemPageDict[e.firstChild.nodeValue.trim()]) { e.firstChild.nodeValue = itemPageDict[e.firstChild.nodeValue.trim()]; } count = i; }); translatedOnce.item_opt = count !== -1 ? count : -1; } // 物品名 const $active_tab = document.querySelector('ul.itemsList[aria-expanded="true"]'); if (!$active_tab) return; const $active_item_list = $active_tab.querySelectorAll('span.name'); const itemCat = $active_tab.id; if ($active_item_list.length - 1 !== translated.count || itemCat !== translated.cat) { let count = -1; // 物品名 $active_item_list.forEach((e, i) => { if (!e.classList.contains('wh-translated')) { if (itemNameDict[e.innerText.trim()]) { e.classList.add('wh-translated'); const trans_dom = document.createElement('span'); trans_dom.classList.add('wh-translate'); trans_dom.setAttribute('style', 'margin: 0 0 0 1em'); trans_dom.append(itemNameDict[e.innerText.trim()]); e.after(trans_dom); // .after(`${itemNameDict[$(e).text().trim()]}`); } } count = i; }); if (count !== -1) { translated.cat = itemCat; translated.count = count; } } // 物品详情 const $show_item_info = $active_tab.querySelector('li.show-item-info'); showItemInfoTrans($show_item_info); // 物品右操作按钮 const $opt_icon_tooltip = $('ul.actions-wrap span.icon-h'); if (translatedOnce.opt_icon_count !== $opt_icon_tooltip.length - 1) { let count = -1 $opt_icon_tooltip.each((i, e) => { if (itemPageDict[e.attributes.title.nodeValue]) { e.attributes.title.nodeValue = itemPageDict[e.attributes.title.nodeValue]; } count = i; }); if (count !== -1) { translatedOnce.opt_icon_count = count; } } }); // 黑框 const $title_black = document.querySelector('div.title-black'); if ($title_black) { const $your_items = $title_black.querySelector('span.m-hide'); if (itemPageDict[$your_items.innerText.trim()]) { $your_items.innerText = itemPageDict[$your_items.innerText.trim()]; } // 黑框分类标题 const $items_type_name = $title_black.querySelector('span.items-name'); initOB($items_type_name, {childList: true}, () => { if (itemPageDict[$items_type_name.innerText.trim()]) { $items_type_name.innerText = itemPageDict[$items_type_name.innerText.trim()]; } }); } // 分类浮动文字 const $data_type = document.querySelectorAll('li#categoriesItem a'); $data_type.forEach((e) => { if (itemPageDict[e.getAttribute('title')]) { e.setAttribute('title', itemPageDict[e.attributes.title.nodeValue]); } }); return; } // npc商店 if (href.contains(/(shops|bigalgunshop)\.php/)) { // 标题和右边的链接 const $cont_title = document.querySelector('.content-title'); initOB($cont_title, {childList: true, subtree: true}, () => { titleTrans(); contentTitleLinksTrans(); }); const $wrapper = document.querySelector('.content-wrapper'); // [购买部分] const $buy_items_wrapper = $wrapper.querySelector('.buy-items-wrap'); if ($buy_items_wrapper) { // 黑框标题 const $buy_black_title = $buy_items_wrapper.querySelector('.title-black'); if ($buy_black_title && npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]) { $buy_black_title.firstChild.nodeValue = npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]; } // 各个物品 const $items = $buy_items_wrapper.querySelectorAll('ul.items-list > li.torn-divider'); $items.forEach(e => { // 物品名 const $item_name = e.querySelector('span.desc span.name.bold'); if ($item_name && itemNameDict[$item_name.innerText.trim()]) { $item_name.innerText = `${itemNameDict[$item_name.innerText.trim()]}(${$item_name.innerText.trim()})`; } // 类型和存货 const $item_stock = e.querySelector('span.desc span.stock'); if ($item_stock) $item_stock.childNodes.forEach(e => { if (e.nodeType === 1) { if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; } else { if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; } }); // buy按钮 const $buy_btn = e.querySelector('button.wai-support'); if ($buy_btn && npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]) { $buy_btn.childNodes[0].nodeValue = npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]; } // 买前确认 const $confirm = e.querySelector('span.confirm'); const $confirm_msg = $confirm.querySelector('span'); if ($confirm_msg && npcShopDict[$confirm_msg.innerText.trim()]) { $confirm_msg.innerText = npcShopDict[$confirm_msg.innerText.trim()]; } const $amount_item_name = $confirm.querySelector('span.count').nextSibling; if ($amount_item_name && !$amount_item_name.nodeValue.contains(CC_set)) { const item_name = $amount_item_name.nodeValue.trim().split(' ').slice(1, -1).join(' '); const item_name_trans = itemNameDict[item_name] || item_name; $amount_item_name.nodeValue = `个[${item_name_trans}],总计$`; } const $confirm_a = $confirm.querySelectorAll('span.confirm-act a'); $confirm_a.forEach(e => { if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; }); }); // 展开的物品详情 initOB($wrapper, {childList: true, subtree: true}, () => { const $item_desc = $wrapper.querySelector('.show-item-info') || $wrapper.querySelector('.view-item-info'); showItemInfoTrans($item_desc); }); } // [卖出部分] const $sell_items_wrapper = $wrapper.querySelector('.sell-items-wrap'); if ($sell_items_wrapper) { // 黑框标题 const $title = $sell_items_wrapper.querySelectorAll('ul.title li'); $title.forEach(el => { el.childNodes.forEach(e => { if (e.nodeType === 1) { if (npcShopDict[e.innerText.trim()]) { e.innerText = npcShopDict[e.innerText.trim()]; return; } const spl = e.innerText.trim().split(' '); if (spl.length > 3) { const shop_name = spl[2] === 'the' ? spl.slice(3).join(' ') : spl.slice(2).join(' '); const shop_name_trans = npcShopDict[shop_name] || titleDict[shop_name] || cityDict[shop_name] || null; e.innerText = `物品给${shop_name_trans || shop_name}`; } } else { if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; } }); }); // 物品名 const $items_name = $sell_items_wrapper.querySelectorAll('span.name'); $items_name.forEach(el => { if (itemNameDict[el.innerText.trim()]) el.innerText += ` ${itemNameDict[el.innerText.trim()]}`; }); // 按钮 const $btn = $sell_items_wrapper.querySelectorAll('button'); $btn.forEach(e => { if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; }); // select btn const $select_btn = $sell_items_wrapper.querySelector('li.select button.wai-btn'); if ($select_btn) { initOB($select_btn, {childList: true}, () => { if ($select_btn && npcShopDict[$select_btn.innerText.trim()]) { $select_btn.innerText = npcShopDict[$select_btn.innerText.trim()]; } }); } // 取消按钮 const $cancel = $sell_items_wrapper.querySelector('span.cancel a'); if ($cancel && npcShopDict[$cancel.innerText.trim()]) { $cancel.innerText = npcShopDict[$cancel.innerText.trim()]; } // 卖出确认文字 const $sell_confirm = $sell_items_wrapper.querySelector('div.sell-confirm'); if ($sell_confirm) { const $msg = $sell_confirm.childNodes[0]; if (npcShopDict[$msg.nodeValue.trim()]) $msg.nodeValue = npcShopDict[$msg.nodeValue.trim()]; const $total_value = $sell_confirm.querySelector('span.profit').childNodes[0]; if (npcShopDict[$total_value.nodeValue.trim()]) $total_value.nodeValue = npcShopDict[$total_value.nodeValue.trim()]; } } // [出售PT部分] const $sell_pt_wrapper = $wrapper.querySelector('.sell-points-wrap'); if ($sell_pt_wrapper) { // 黑框 const $title_black = $sell_pt_wrapper.querySelector('.title-black'); if (npcShopDict[$title_black.innerText.trim()]) { $title_black.innerText = npcShopDict[$title_black.innerText.trim()]; } } return; } // 股票 if (href.contains(/page\.php\?sid=stocks/)) { const stockOB = new MutationObserver(() => { stockOB.disconnect(); titleTrans(); contentTitleLinksTrans(); stockTrans(); stockOB.observe($('.content-wrapper').get(0), { characterData: true, attributes: true, subtree: true, childList: true }); }); const stockTrans = function stockTrans() { // 表头 $('ul.title-black').find('*').contents().each((i, e) => { if (e.nodeType === 3 && stockDict[e.nodeValue.trim()]) { e.nodeValue = stockDict[e.nodeValue.trim()]; } }); // 名称 $('div[class^="nameContainer"]').each((i, e) => { if (e.childNodes[0].nodeValue && stockDict[e.childNodes[0].nodeValue.trim()]) { e.childNodes[0].nodeValue = stockDict[e.childNodes[0].nodeValue.trim()]; } }); // 右侧bb名 $('div[class^="dividendInfo"] p').each((i, e) => { const spl = $(e).text().trim().split(' '); if (stockDict[$(e).text().trim()]) { $(e).text(stockDict[$(e).text().trim()]); } else if (/[0-9]x$/.test(spl[0])) { const itemName = spl.slice(1).join(' '); const num = spl[0].slice(0, -1); $(e).text(`${num}个${itemNameDict[itemName] ? itemNameDict[itemName] : itemName}`); } }); // 股价详情 $('#panel-priceTab ul[role="tablist"] label span:last-child').each((i, e) => { if (stockDict[$(e).text()]) { $(e).text(stockDict[$(e).text()]); } }); $('ul[class^="priceInfoList___"] li').contents().each((i, e) => { if (e.nodeType === 3) { if (stockDict[e.nodeValue.trim()]) { e.nodeValue = stockDict[e.nodeValue.trim()]; } } }); // 点开购买后 $('div#panel-ownedTab div[class^="manageBlock"] *').contents().each((i, e) => { if (e.nodeType === 1) { if (stockDict[$(e).text().trim()]) { $(e).text(stockDict[$(e).text().trim()]); } } else if (e.nodeType === 3) { if (stockDict[e.nodeValue.trim()]) e.nodeValue = stockDict[e.nodeValue.trim()]; else if (/\$[0-9]+ after the 0\.1% fee of \$[0-9]+$/.test(e.nodeValue.trim())) { e.nodeValue = e.nodeValue.trim() .replace('after the', stockDict['after the']) .replace('fee of', stockDict['fee of']); } } }); // 点开购买后的历史栏 $('div#panel-ownedTab div[class^="transactionsContainer"] li').each((i, e) => { e = e.childElementCount === 0 ? e : e.children[0]; if (stockDict[$(e).text().trim()]) { $(e).text(stockDict[$(e).text().trim()]); } }); // 历史购买show more const $show_more = document.querySelector('li[class^="showMore___"] button'); if ($show_more && $show_more.innerText.trim().contains(/^Show [0-9]+ more$/)) { const number = $show_more.innerText.trim().split(' ')[1]; $show_more.innerText = `显示另外${number}条`; } // 点开bb后 $('div#panel-dividendTab div[class^="message"] *').contents().each((i, e) => { if (e.nodeType !== 3) return; if (!e.nodeValue.trim()) return; if (stockDict[e.nodeValue.trim()]) { e.nodeValue = stockDict[e.nodeValue.trim()]; } // 第n个increment 1st 2nd 3rd 4th else if (/[0-9][snrt][tdh]$/.test(e.nodeValue.trim())) { e.nodeValue = `第${e.nodeValue.trim().slice(0, -2)}个`; } // 物品 else if (/[0-9]x$/.test(e.nodeValue.trim().split(' ')[0])) { const spl = e.nodeValue.trim().split(' '); const itemName = spl.slice(1).join(' '); e.nodeValue = ` ${spl[0].replace('x', '个') } ${itemNameDict[itemName] ? itemNameDict[itemName] : itemName }`; } else { if (/[\u4e00-\u9fa5]/.test(e.nodeValue)) return; if (/\b\$?[0-9,]+$/.test(e.nodeValue)) return; log(`未找到翻译:[${e.nodeValue.trim()}]`); } }); }; stockTrans(); stockOB.observe($('.content-wrapper').get(0), { characterData: true, attributes: true, subtree: true, childList: true }); return; } // 教育页面 if (href.indexOf('education.php') >= 0) { const eduOB = new MutationObserver(eduOBInit); function eduOBInit() { eduOB.disconnect(); eduTrans(); eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); } function eduTrans() { titleTrans(); contentTitleLinksTrans(); // 大科目、学院标题 $('div.content-wrapper div.title').each((i, e) => { if (eduDict[$(e).text().trim()]) e.firstChild.nodeValue = eduDict[$(e).text().trim()]; }); // 教育主页提示内容 和 学院详情 小课程提示信息 $('div.content-wrapper div[class^="msg"]').find('*').contents().each((i, e) => { if (e.nodeValue === null) return; if (eduDict[e.nodeValue.trim()]) { e.nodeValue = eduDict[e.nodeValue.trim()]; } else if (e.nodeValue.indexOf('second') >= 0 || e.nodeValue.indexOf('minute') >= 0 || e.nodeValue.indexOf('hour') >= 0 || e.nodeValue.indexOf('day') >= 0) { e.nodeValue = e.nodeValue .replace('days', '天') .replace('day', '天') .replace('hours', '时') .replace('hour', '时') .replace('minutes', '分') .replace('minute', '分') .replace('and', '和') .replace('seconds', '秒') .replace('second', '秒'); } }); // 学院详情标题 $('div.content-wrapper div.title-black').each((i, e) => { if (e.childNodes.length === 3) if (eduDict[e.lastChild.nodeValue.trim()]) e.lastChild.nodeValue = ' ' + eduDict[e.lastChild.nodeValue.trim()]; if (eduDict[$(e).text().trim()]) $(e).text(eduDict[$(e).text().trim()]); }); // 学院详情 小课程标题 $('div.content-wrapper span.module-name').each((i, e) => { if (eduDict[$(e).text().trim()]) $(e).text(eduDict[$(e).text().trim()]); }); // 学院详情 课程的描述 $('div.content-wrapper p.desc').each((i, e) => { if (eduDict[$(e).text().trim()]) $(e).text(eduDict[$(e).text().trim()]); }); // 课程详情 7 标题 $('div.module-desc p.title').each((i, e) => { if (eduDict[$(e).text().trim()]) $(e).text(eduDict[$(e).text().trim()]); }); // 课程介绍中的所有li元素 $('div.module-desc ul.info').find('*').contents().each((i, e) => { if (e.nodeValue === null) return; if (eduDict[e.nodeValue.trim()]) e.nodeValue = eduDict[e.nodeValue.trim()]; else if (e.nodeValue.indexOf('Length') >= 0) { e.nodeValue = e.nodeValue.replace('Length', eduDict['Length']) .replace('d ', '日') .replace('h ', '时') .replace('m ', '分'); } else if (e.nodeValue.indexOf('Cost') >= 0) { e.nodeValue = e.nodeValue.replace('Cost', eduDict['Cost']); } else if (e.nodeValue.indexOf('manual labor') >= 0) { e.nodeValue = e.nodeValue.replace('manual labor', eduDict['manual labor']) .replace('Gain', eduDict['Gain']) .replace('upon completion', eduDict['upon completion']); } else if (e.nodeValue.indexOf('endurance') >= 0) { e.nodeValue = e.nodeValue.replace('endurance', eduDict['endurance']) .replace('Gain', '获得') .replace('upon completion', eduDict['upon completion']); } else if (e.nodeValue.indexOf('intelligence') >= 0) { e.nodeValue = e.nodeValue.replace('intelligence', eduDict['intelligence']) .replace('Gain', '获得') .replace('upon completion', eduDict['upon completion']); } }); } eduTrans(); eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); return; } // profile 玩家资料页面 if (href.contains(/profiles\.php\?XID=\d+/)) { const $wrapper = document.querySelector('.content-wrapper'); const profileOB = new MutationObserver(() => { profileOB.disconnect(); titleTrans(); contentTitleLinksTrans(); profileTrans(); profileOB.observe($wrapper, { characterData: true, attributes: true, subtree: true, childList: true }); }); const profileTrans = function profileTrans() { const playerName = document.title.trim().contains(/('s |s' )/) ? document.title.trim().split(/('s |s' )/)[0] : null; if (!playerName) { console.error('翻译助手错误:获取用户名失败。'); try { profileOB.disconnect() } catch { } return; } // 黑框标题 $('.content-wrapper .title-black').each((i, e) => { if (i === 1) { if (profileDict[e.firstChild.nodeValue.trim().replace(playerName, '{$}')]) { e.firstChild.nodeValue = ( profileDict[$(e).text().trim().replace(playerName, '{$}')] .replace('{$}', playerName) ); } return; } if (profileDict[$(e).text().trim()]) { $(e).text(profileDict[$(e).text().trim()]); } }); // level rank age $('.profile-information-wrapper .box-info .box-name').each((i, e) => { if (profileDict[e.innerText.trim()]) e.innerText = profileDict[e.innerText.trim()]; }); // todo player title // todo player rank title // 行动框的描述 const action_desc = $('#profile-container-description.profile-container-description'); if (profileDict[action_desc.text().trim()]) { action_desc.html(`${profileDict[action_desc.text().trim()]}`); } else if (profileDict[action_desc.text().trim().replace(playerName, '{$}')]) { action_desc.html( `${profileDict[action_desc.text().trim().replace(playerName, '{$}')] .replace('{$}', playerName)}` ); } else if (action_desc.text().contains(/is on your (friend|enemy) list/)) { const spl = action_desc.text().trim().split(' '); const mark = spl.length === 6 ? null : spl.slice(7).join(' '); switch (spl[4]) { case 'friend': if (profileDict['{$} is on your friend list']) { action_desc.html( `${profileDict['{$} is on your friend list'] .replace('{$}', playerName) }${mark ? ' : ' + mark : '' }` ); } break; case 'enemy': if (profileDict['{$} is on your enemy list']) { action_desc.html( `${profileDict['{$} is on your enemy list'] .replace('{$}', playerName) }${mark ? ' : ' + mark : '' }` ); } break; } } else { if ($('.wh-translated').length <= 0) { log(`未找到翻译: “${action_desc.text().trim()}”`); } } // 添加敌人或朋友的界面 $('.add-user .reason-wrapper').find('*').contents().each((i, e) => { if (e.nodeType === 3) { if (profileDict[e.nodeValue.trim()]) { e.nodeValue = profileDict[e.nodeValue.trim()]; } else if (/\b[1-4]?[0-9]\b/.test(e.nodeValue.trim().slice(0, 2))) { const left = e.nodeValue.trim().slice(0, 2); if (profileDict['{$} characters left']) { e.nodeValue = profileDict['{$} characters left'].replace('{$}', left); } } } }); // 状态 playerStatusTrans($('.profile-status .profile-container span')); // 表格 $('ul.info-table li div').each((i, e) => { const $e = $(e); // 左 if ($e.attr('class').contains(/user-information-section/)) { const elem = e.children[0]; const $elem = $(elem); if (profileDict[$elem.text().trim()]) $elem.text(profileDict[$elem.text().trim()]); } // 右 值 else { if (profileDict[$e.text().trim()]) { $e.children().text(profileDict[$e.text().trim()]); return; } switch (i) { case 5: // 帮派 case 7: { // 公司 if ($e.text().contains(CC_set)) return; const $span = e.children[0].children[0]; const pos = $span.firstChild.nodeValue.trim().split(' ').slice(0, -1).join(' '); $span.firstChild.nodeValue = ''; $($span).append(` 的 ${pos}`); return; } case 11: { // 住宅 $e.find('span *').contents().each((i, el) => { if (el.nodeType === 3) { if (profileDict[el.nodeValue.trim()]) { el.nodeValue = profileDict[el.nodeValue.trim()] } else if (propertyDict[el.nodeValue.trim()]) { el.nodeValue = propertyDict[el.nodeValue.trim()] } } }); return; } case 13: { // 结婚状态 if ($e.text().contains(CC_set)) return; const days = $e.text().contains(/ [0-9]+ /) ? $e.text().trim().split(' ')[4] : null; if (days) { e.children[0].children[0].childNodes[0].nodeValue = '与 '; e.children[0].children[0].childNodes[2].nodeValue = ` 结婚${days}天`; } else { $e.find('span *').contents().each((i, el) => { if (el.nodeType === 3) { if (profileDict[el.nodeValue.trim()]) { el.nodeValue = profileDict[el.nodeValue.trim()] } } }); } return; } case 23: { // 39 minutes ago if ($e.text().contains(/ago/)) { $e.children().text($e.text() .replace('ago', '前') .replace('and', '') .replace('seconds', '秒') .replace('second', '秒') .replace('minutes', '分') .replace('minute', '分') .replace('hours', '时') .replace('hour', '时') .replace('days', '日') .replace('day', '日') .replaceAll(' ', '') ); } return; } } /** 1 'Woohoo [2687093]' 3 'Civilian' 5 'Knight of Silver Hand' 7 'Director of -- FaFaFa --' 9 '1567 / 1567' 11 'Private Island (With Spouse)' 13 'Married to Sabrina_Devil for 42 days' 15 '153' 17 '4' 19 '4\n  好人\n  坏比指数: 1\n ' 21 '2 (0 karma)' 23 '52 minutes ago' */ } }); // doesnt wish to share const $nShare = $('.personal-info p'); $nShare.contents().each((i, e) => { if (e.nodeType === 3) { if (profileDict[e.nodeValue.trim()]) e.nodeValue = profileDict[e.nodeValue.trim()]; } }); // 活动状态 const $cmpSt = $('.profile-container.competition-wrap span') $cmpSt.text(profileDict[$cmpSt.text().trim()] || $cmpSt.text()); sendCashTrans('.content-wrapper'); }; profileTrans(); profileOB.observe($wrapper, { characterData: true, attributes: true, subtree: true, childList: true }); return; } // 报纸 if (href.contains(/(newspaper|joblist|freebies|newspaper_class|personals|bounties|comics)\.php/)) { const newspaperOB = new MutationObserver(() => { newspaperOB.disconnect(); newspaperTrans(); newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); }); function newspaperTrans() { titleTrans(); contentTitleLinksTrans(); if ($('a.newspaper-link').length === 0) return; // 导航菜单 $('a.newspaper-link').contents().each((i, e) => { if (newspaperDict[e.nodeValue]) e.nodeValue = newspaperDict[e.nodeValue]; }); // 公众号广告 $('div.price.left').contents()[2].nodeValue = '文章翻译请关注中文公众号Torncity'; // 日期翻译 const $date_label = document.querySelector('span.date-label'); const date_reg = /^[FMSTW][adehinorstuy]+, [ADFJMNOS][abceglnoprtuvy]+ [1-3]?[0-9], 20[0-9][0-9]$/; if ($date_label && $date_label.innerText.trim().contains(date_reg)) { const date_format = $date_label.innerText.trim().replaceAll(',', ''); const date_spl = date_format.split(' '); const date = {w: date_spl[0], m: date_spl[1], d: date_spl[2], y: date_spl[3]}; const month_trans = { 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 }; $date_label.innerText = `${date.y}年${month_trans[date.m] || date.m}月${date.d}日`; } // 菜单下的信息 工作 壁纸 广告 悬赏 $('div.help-message').find('*').contents().each((i, e) => { if (!e.nodeValue || e.nodeValue.trim() === '') return; if (newspaperDict[e.nodeValue.trim()]) e.nodeValue = newspaperDict[e.nodeValue.trim()]; else if (newspaperDict[e.nodeValue.trim().slice(0, 50)]) e.nodeValue = newspaperDict[e.nodeValue.trim().slice(0, 50)]; }); // 右边栏 $('div[class^="sideCont"] [class^="title"]').contents().each((i, e) => { if (newspaperDict[e.nodeValue]) e.nodeValue = newspaperDict[e.nodeValue]; }); // 彩票信息 $('span[class^="winner"]').each((i, e) => { }); // 底部链接 // Why not visit our sponsor? if (newspaperDict[$('div.link-left').text().trim()]) $('div.link-left').text(newspaperDict[$('div.link-left').text().trim()]); // View all | Advertise here $('div.link-right a').contents().each((i, e) => { if (newspaperDict[e.nodeValue.trim()]) e.nodeValue = newspaperDict[e.nodeValue.trim()]; }) $('.bounties-list-title li').each((i, e) => { if (newspaperDict[$(e).text().trim()]) { $(e).text(newspaperDict[$(e).text().trim()]); } }); // 交友 if (window.location.href.contains(/personals/)) { $('div.personals-wrap span.msg').find('*').contents().each((i, e) => { if (!e.nodeValue || e.nodeValue.trim() === '') return; if (newspaperDict[e.nodeValue.trim()]) e.nodeValue = newspaperDict[e.nodeValue.trim()]; }); } // 漫画 if (window.location.href.contains(/freebies/)) { if (newspaperDict[$('div.bonus-wrap a').text().trim()]) $('div.bonus-wrap a').text(newspaperDict[$('div.bonus-wrap a').text().trim()]); } // 悬赏 if (window.location.href.contains(/bounties/)) { // 列表前的总数 const $total = $('.bounties-total'); if ($total.text().contains(/A total of [0-9]+ listings were found/)) { const num = $total.text().trim().split(' ')[3]; if (newspaperDict['A total of {$} listings were found.']) { $total.text(newspaperDict['A total of {$} listings were found.'] .replace('{$}', num)); } } // 列表 $('.user-info-wrap div *').contents().each((i, e) => { if (e.nodeType === 3) { if (newspaperDict[e.nodeValue.trim()]) { e.nodeValue = newspaperDict[e.nodeValue.trim()]; } } }); // claim $('ul.bounties-list div.claim button').each((i, e) => { if (newspaperDict[$(e).text().trim()]) { $(e).text(newspaperDict[$(e).text().trim()]); } }); $('ul.bounties-list div.claim a').each((i, e) => { if (newspaperDict[$(e).text().trim()]) { $(e).text(newspaperDict[$(e).text().trim()]); } }); // 3选项框 $('.add-bounties-wrap .name').contents().each((i, e) => { if (e.nodeType === 3) { if (newspaperDict[e.nodeValue.trim()]) { e.nodeValue = newspaperDict[e.nodeValue.trim()]; } } else if (e.nodeType === 1) { if (newspaperDict[$(e).text().trim()]) { $(e).text(newspaperDict[$(e).text().trim()]); } } }); // 匿名选项 const $anony = $('.choice-container label'); if (newspaperDict[$anony.text().trim()]) { $anony.text(newspaperDict[$anony.text().trim()]); } // 发钱按钮 const $$symbol = $('span.input-money-symbol'); if (sendCashDict[$$symbol.attr('title')]) { $$symbol.attr('title', sendCashDict[$$symbol.attr('title')]) } // 10/10滑动 const $slider_title = $('.slider-title'); if ($slider_title.text().contains(/Quantity:/)) { $slider_title.text($slider_title.text().replace('Quantity', '数量')); } // 价钱信息 $('.confirm-bounties *').contents().each((i, e) => { if (e.nodeType === 3) { if (newspaperDict[e.nodeValue.trim()]) { e.nodeValue = newspaperDict[e.nodeValue.trim()]; } } }); // 下单前确认对话 $('.confirm-buttons *').contents().each((i, e) => { if (e.nodeType === 3) { if (newspaperDict[e.nodeValue.trim()]) { e.nodeValue = newspaperDict[e.nodeValue.trim()]; return; } switch (i) { case 7: case 10: { if (e.nodeValue.contains(/[0-9] bounties/)) { e.nodeValue = e.nodeValue.replace('bounties', '次') } else if (e.nodeValue.contains(/with the reason: .+\?/)) { e.nodeValue = e.nodeValue.replace('with the reason', '吗,悬赏原因') } break; } } } }); // place const $place = $('.place-buttons input'); if (newspaperDict[$place.attr('value')]) { $place.attr('value', newspaperDict[$place.attr('value')]); } // cancel const $cancel = $('.place-buttons a.cancel'); if (newspaperDict[$cancel.text().trim()]) { $cancel.text(newspaperDict[$cancel.text().trim()]); } } } newspaperTrans(); newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); return; } // npc买房 estateagents if (href.includes('estateagents.php')) { titleTrans(); contentTitleLinksTrans(); $('div.estate-info div.title').each((i, e) => { if (propertyDict[e.firstChild.nodeValue]) e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; }); return; } // properties房屋页面 if (href.includes('properties.php')) { const isRent = window.location.href.indexOf('rent') >= 0; // const isRentOrSell = isRent || window.location.href.indexOf('sell') >= 0; // const isOption = window.location.href.indexOf('p=options') >= 0; // const isExtension = window.location.href.indexOf('step=viewOfferExtension') >= 0; const propertyOB = new MutationObserver(() => { propertyOB.disconnect(); titleTrans(); contentTitleLinksTrans(); propertyTrans(); propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); }); const propertyTrans = function propertyTrans() { // 从玩家处租或买 if (isRent || window.location.href.indexOf('sell') >= 0) { // 黑框标题 $('div.title-black span').each((i, e) => { e.firstChild.nodeValue = '您想查看哪些房产?'; }); // 房屋汉化 $('ul.info-cont label.marker-css').contents().each((i, e) => { if (propertyDict[e.nodeValue]) e.nodeValue = propertyDict[e.nodeValue]; }); //搜索按钮 $('div.btn-search button').text('搜索'); $('div.search-text a').text('搜索'); // 表头信息 $('div.users-list-title div').each((i, e) => { if (propertyDict[$(e).text()]) $(e).text(propertyDict[$(e).text()]); }); // 确认购买提示 $('div[class="confirm-text"] span.question').each((i, e) => { const propName = e.firstElementChild.innerText.trim().split(' ').slice(8).join(' '); const hasAnother = $(e).text().indexOf('another') > 0; if (hasAnother) { e.firstElementChild.firstChild.nodeValue = '你确定要'; e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; e.firstElementChild.childNodes[1].firstChild.nodeValue = '另一个'; e.firstElementChild.childNodes[2].nodeValue = propertyDict[propName]; } else { e.firstElementChild.firstChild.nodeValue = '你确定要'; e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; e.firstElementChild.firstChild.nodeValue += propertyDict[propName]; } e.children[1].firstChild.nodeValue = '花费 '; e.children[1].childNodes[2].nodeValue = isRent ? ' 租期 ' : '?'; if (isRent) e.children[1].childNodes[4].nodeValue = ' 天?'; }); // 房屋详情表格 $('div.info-block span.bold').each((i, e) => { if (e.childElementCount === 2) { /** * On "Market" Price ":" */ e.firstElementChild.firstChild.nodeValue = ''; e.childNodes[2].nodeValue = '市场价'; e.childNodes[3].firstChild.nodeValue = ''; e.childNodes[4].nodeValue = ':'; } else { if (propertyDict[e.firstChild.nodeValue.trim()]) e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; } }); $('div.rental-period span.bold').each((i, e) => { if (propertyDict[e.firstChild.nodeValue.trim()]) e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; }); // 窄边 cost happy $('span.title-laptop.bold').each((i, e) => { if (propertyDict[$(e).text().trim()]) $(e).text(propertyDict[$(e).text().trim()]); }); // modification $('div.title.bold.left').each((i, e) => { if (propertyDict[e.firstChild.nodeValue]) e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; }); return; } // 房屋选项 if (window.location.href.indexOf('p=options') >= 0) { // 页面的黑框标题 $('div.content-wrapper div.title-black').each((i, e) => { if (propertyDict[$(e).text().trim()]) $(e).text(propertyDict[$(e).text().trim()]); }); // 所有li内容 // $('div.content-wrapper div.customize-opt li').find('*') // .contents().each((i,e)=>{ // if(e.nodeType!==3)return;log(e) // }); return; } // 房屋详情 if (window.location.href.indexOf('p=propertyinfo') >= 0) { return; } // 延期、合同 if (window.location.href.indexOf('step=viewOfferExtension') >= 0) { return; } // 自己的所有房产 页面 { // 顶部3标题 $('ul.property-tabs a.ui-tabs-anchor div').contents().each((i, e) => { if (propertyDict[e.nodeValue]) { e.nodeValue = propertyDict[e.nodeValue]; } }); // 图片下的描述部分 $('ul.properties-list div.image-description').find('*') .contents().each((i, e) => { if (e.nodeType !== 3) return; if (!propertyDict[e.nodeValue.trim()]) return; e.nodeValue = propertyDict[e.nodeValue.trim()]; }); // 图片下的按钮的title浮动框文字 $('div#properties-page-wrap a[title]').each((i, e) => { if (propertyDict[$(e).attr('title')]) $(e).attr('title', propertyDict[$(e).attr('title')]); }); } }; propertyTrans(); propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); return; } // 通知页面 if (href.includes('events.php')) { const ob = new MutationObserver(() => { ob.disconnect(); titleTrans(); contentTitleLinksTrans(); eventsTrans(); ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); }); eventsTrans(); ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); return; // let events; // const eventMutation = new MutationObserver(() => { // eventMutation.disconnect(); // // events = $('span.mail-link'); // // eventsTrans(events); // eventsTrans(); // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); // }); // // //初始化中内容未加载 // let eventInterval = setInterval(() => { // // events = $('span.mail-link'); // // if (events.length === 0) { // // return; // // } // clearInterval(eventInterval); // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); // eventsTrans(events); // }, 1000); } // awards.php if (href.includes('awards.php')) { const awOB = new MutationObserver(() => { awOB.disconnect(); awTrans(); awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); }); const awTrans = function awTrans() { titleTrans(); contentTitleLinksTrans(); // 顶部的3个分类 Honors (106) Medals (44) Merits (3) $('div.content-wrapper a.ui-tabs-anchor span.bold').contents().each((i, e) => { if (e.nodeType !== 3) return; if (awDict[e.nodeValue.trim()]) e.nodeValue = awDict[e.nodeValue.trim()]; }); // 分类标题下的描述 $('div.awards-msg').contents().each((i, e) => { // 文字节点 if (e.nodeType === 3) { if (awDict[e.nodeValue.trim()]) e.nodeValue = awDict[e.nodeValue.trim()]; } // 子节点 else if (e.nodeType === 1) { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); else if ($(e).text().indexOf('medals') >= 0) $(e).text($(e).text().replace('medals', awDict['medals'])); else if ($(e).text().indexOf('honors') >= 0) $(e).text($(e).text().replace('honors', awDict['honors'])); } }); // 荣誉的描述 $('div#awards-tab-menu a[data-title]').each((i, e) => { const desc = $(e).attr('data-title').split(' ')[0]; if (awDict[desc]) $(e).attr('data-title', $(e).attr('data-title').replace(desc, awDict[desc])); }); // 改变荣誉条时的提示 $('div#honors div.msg').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); // 改变荣誉条时的提示按钮 change $('div#honors div.confirm-msg button').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); // 改变荣誉条时的提示按钮 cancel $('div#honors div.confirm-msg a.cancel').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); // 天赋页面 Available Merits: x Merits Used: x $('div.awards-msg p').contents().each((i, e) => { if (e.nodeType === 3) if (awDict[e.nodeValue.trim()]) e.nodeValue = e.nodeValue.replace(e.nodeValue.trim(), awDict[e.nodeValue.trim()]); }); // 勋章下 即将解锁的勋章框标题 天赋加点的表头标题 $('div.title-black').contents().each((i, e) => { // 勋章下 即将解锁的勋章框标题 if (e.nodeType === 1) { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); } // 天赋加点的表头标题 else if (e.nodeType === 3) { if (awDict[e.nodeValue.trim()]) e.nodeValue = awDict[e.nodeValue.trim()]; } }); // 荣誉和勋章的左边栏分类选择菜单 $('div.tab-menu-cont li.ui-state-default a').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); // 天赋点名字 $('ul#merits-list span.name').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); // 天赋点短描述 $('ul#merits-list span.desc span[class^="t-"]').each((i, e) => { // const slash = $(e).attr('class') === 't-show' ? '- ' : ''; const isShow = $(e).attr('class') === 't-hide'; const key = isShow ? $(e).text().slice(2) : $(e).text(); if (awDict[key]) $(e).text((isShow ? '- ' : '') + awDict[key]); }); // 天赋点展开详细描述与确认 $('ul#merits-list div.msg').contents().each((i, e) => { // x merit(s) if (e.nodeType === 1) { const spl = $(e).text().split(' '); if (awDict[spl[1]]) $(e).text(spl[0] + ' ' + awDict[spl[1]]); } // 文字片段 else if (e.nodeType === 3) { if (awDict[e.nodeValue.trim()]) { e.nodeValue = awDict[e.nodeValue.trim()] + ''; return; } const spl = e.nodeValue.trim().split('\n'); // 未升级完成 if (spl.length === 3) { const upgradeName = spl[1].slice(5, -9); const on = spl[0]; const upgrade = spl[1].slice(-8); const desc = spl[2]; if (awDict[on] && awDict[upgrade] && awDict[upgradeName] && awDict[desc]) e.nodeValue = ' ' + awDict[on] + awDict[upgradeName] + awDict[upgrade] + awDict[desc]; } // 升级完成 else if (spl.length === 1) { const upgraded = e.nodeValue.trim().slice(0, 60); const desc = e.nodeValue.trim().slice(61); if (awDict[upgraded]) e.nodeValue = awDict[upgraded]; if (awDict[desc]) e.nodeValue += awDict[desc]; } } }); // spend cancel按钮 $('ul#merits-list div.confirm-cont a').each((i, e) => { if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); }); }; awTrans(); awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); return; } // preferences设置 if (href.contains(/preferences\.php/)) { 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 trans = () => { // 黑框标题 const $black_title = $('.title-black'); if (tornSettingsDict[$black_title.text().trim()]) { $black_title.text(tornSettingsDict[$black_title.text().trim()]); } // 电脑版左边导航菜单 const $nav = $('.content-wrapper a.ui-tabs-anchor'); $nav.each((i, e) => { if (tornSettingsDict[$(e).text().trim()]) { $(e).text(tornSettingsDict[$(e).text().trim()]); } }); if (window.location.href.contains(/tab=api/)) { // 描述 const $api_desc = $('.content-wrapper p[class^="apiDescription___"]'); if (tornSettingsDict[$api_desc.text().slice(0, 50)]) { $api_desc.text(tornSettingsDict[$api_desc.text().slice(0, 50)]); } // 添加按钮 const $add_btn = $('button[class^="addKey___"] span'); if (tornSettingsDict[$add_btn.text().trim()]) { $add_btn.text(tornSettingsDict[$add_btn.text().trim()]); } // new keys name const $new_keys_name = $('input[placeholder="New key\'s name"]'); if (tornSettingsDict[$new_keys_name.attr('placeholder')]) { $new_keys_name.attr('placeholder', tornSettingsDict[$new_keys_name.attr('placeholder')]); } // api类型 const $key_type = $('div[class*="typesDropdown___"] button.down'); if (tornSettingsDict[$key_type.text().trim()]) { $key_type.text(tornSettingsDict[$key_type.text().trim()]); } // api类型选择框 const $type_down = $('div[class*="typesDropdown___"] div.down li'); $type_down.each((i, e) => { if (tornSettingsDict[$(e).text().trim()]) { $(e).text(tornSettingsDict[$(e).text().trim()]); } }); // return; } }; trans(); OB.observe($$.get(0), { characterData: true, attributes: true, subtree: true, childList: true }); return; } // 展柜 if (href.contains(/displaycase\.php/)) { const $page_wrapper = document.querySelector('#display-page-wrap'); initOB($page_wrapper, { subtree: true, attributes: true, childList: true }, () => { // 标题和右边的链接 titleTrans(); // 右上角返回按钮 const $back_to_profile = $page_wrapper.querySelector('#back'); if ($back_to_profile) { const spl = $back_to_profile.innerText.split(/('s |s' )/); if (spl.length === 3 && spl[2] === 'Profile') { $back_to_profile.innerText = `${spl[0]}的个人资料`; } } const $display_cabinet = $page_wrapper.querySelector('.display-cabinet'); if ($display_cabinet) { // 物品名 const $item_name = $display_cabinet.querySelectorAll('div.b-item-name span:nth-of-type(2)'); $item_name.forEach((e) => { if (itemNameDict[e.innerText]) { e.innerText = itemNameDict[e.innerText]; } }); // 展开详细框 const $show_item_info = $display_cabinet.querySelector('.show-item-info'); showItemInfoTrans($show_item_info); } }); return; } // 升级页面 if (href.includes('level2.php')) { } // 医院页面 if (href.includes("hospitalview.php")) { const hospitalOB = new MutationObserver(hosOBInit); function hosOBInit() { hospitalOB.disconnect(); hospTrans(); hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); } function hospTrans() { titleTrans(); contentTitleLinksTrans(); // 顶部提示信息 $('div[class^="msg right-round"]').contents().each((i, e) => (hosDict[e.nodeValue.trim()]) && (e.nodeValue = hosDict[e.nodeValue.trim()])); //玩家列表标题 $('div[class^="users-list-title title-black top-round m-top10"] span').contents().each((i, e) => { if (e.nodeValue && hosDict[e.nodeValue.trim()]) { e.nodeValue = e.nodeValue.replace(e.nodeValue, hosDict[e.nodeValue.trim()]); } }) //玩家列表住院理由 $('ul[class^="user-info-list-wrap"] span[class^="reason"]').each((i, e) => { let reasonStr = $(e).get(0).childNodes[1].nodeValue.trim(); if (hosDict[reasonStr]) { $(e)[0].childNodes[1].nodeValue = hosDict[reasonStr]; } else if (reasonStr.indexOf("Crashed") >= 0) { $(e)[0].childNodes[1].nodeValue = reasonStr .replace("Crashed her", hosDict["Crashed her"]) .replace("Crashed his", hosDict["Crashed his"]); } else { switch (reasonStr) { case "Attacked by": $(e)[0].childNodes[1].nodeValue = hosDict["general"]; $(e).append(" 攻击"); break; case "Hospitalized by": $(e)[0].childNodes[1].nodeValue = hosDict["general"]; $(e).append(" 殴打并送入医院"); break; case "Mugged by": $(e)[0].childNodes[1].nodeValue = hosDict["general"]; $(e).append(" 抢劫"); break; } } }) } hospTrans(); hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); return; } // 帮派页面 if (href.includes("actions.php")) { const factionOB = new MutationObserver(factionOBInit); function factionOBInit() { factionOB.disconnect(); factionTrans(); factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); } const factionDict = { "INFO": "信息", "TERRITORY": "地盘", "RANK": "名次", "CRIMES": "组织犯罪", "UPGRADES": "升级", "ARMORY": "军械库", "CONTROLS": "控制面板", "FACTION": "帮派", "YOUR FACTION IS NOT IN A WAR": "你的帮派没有处于战争状态", "TIER": "级别", "RESPECT": "声望", "No active chain": "暂无攻击链", "Main News": "主要消息", "Attacking": "攻击", "Funds": "资金流动", "Armory": "军械库", "Crimes": "组织犯罪", "Membership": "成员资格", "has claimed sovereignty of": "", "has abandoned": "放弃了地盘", "Achieved a chain of": "达成了连击链值", "and": "和", "respect [": "点声望 [", "deposited ${$1}": "存放了${$1}", "Leadership was transferred to": "帮派领导权被移交给了 ", "Someone mugged": "有人抢劫了 ", "hospitalized": " 暴打了 ", "mugged": " 抢劫了 ", "attacked": " 攻击了 ", "but lost": " 但是输了", "Someone attacked": "有人攻击了 ", "Someone hospitalized": "有人暴打了 " } function factionTrans() { titleTrans(); contentTitleLinksTrans(); //帮派大标题 $('span[class^="tab-name"]').each((i, e) => { if (factionDict[$(e).text().trim()]) { $(e).text(factionDict[$(e).text().trim()]); } }) //帮派战争状态 $('div[class^="f-msg"]').contents().each((i, e) => { let word2Trans = $(e).text().trim().split(":")[0]; if (word2Trans && factionDict[word2Trans]) { $(e).text($(e).text().replace(word2Trans, factionDict[word2Trans])); } }) //攻击链盒 $('div[class^="chain-box"]').contents().each((i, e) => { if (factionDict[$(e).text().trim()]) { $(e).text(factionDict[$(e).text().trim()]); } }) //帮派消息类别 $('div[class^="newsHeader"]').contents().each((i, e) => { if (factionDict[$(e).text().trim()]) { $(e).text(factionDict[$(e).text().trim()]); } }) //帮派主要消息日志 $('button[class^="tab"] ').each((i, e) => { if ($(e).attr('class').indexOf("active") >= 0) { log($(e).text()); switch ($(e).text().trim()) { case "主要消息": $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { if (factionDict[$(u).text().trim()]) { u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]); } }) break; case "攻击": $('ul[class^="news-list"] span[class^="info"]').find('*').contents().each((i, u) => { log($(u).text().trim()) if (factionDict[$(u).text().trim()]) { u.nodeValue = factionDict[$(u).text().trim()]; } }) break; case "资金流动": $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { if (u.nodeValue) { u.nodeValue = u.nodeValue.replace("deposited", "存放了"); } }) break; } } }) // //帮派主要消息日志 // $('ul[class^="news-list"] span[class^="info"]').contents().each((i, e) => { // if (factionDict[$(e).text().trim()]) { // e.nodeValue = e.nodeValue.replace($(e).text().trim(), factionDict[$(e).text().trim()]); // } // }) } factionTrans(); factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); return; } // pc电脑 if (href.contains(/pc\.php/)) { 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 trans = () => { // 黑框 const $black_title = $('div.title-black'); if (pcDict[$black_title.text().trim()]) { $black_title.text(pcDict[$black_title.text().trim()]); } }; trans(); OB.observe($$.get(0), { characterData: true, attributes: true, subtree: true, childList: true }); return; } // 日历 if (href.contains(/calendar\.php/)) { const $root = document.querySelectorAll('#calendar-root'); $root.forEach(el => { initOB(el, {childList: true, subtree: true}, () => { // 页标题 const $h4_title = el.querySelectorAll('h4[class^="title___"]'); titleTransReact($h4_title); // 页标题右侧链接 const $link_title = el.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]'); contentTitleLinksTransReact($link_title); // 月标题 const $month_title = el.querySelectorAll('div[class^="monthName___"]'); $month_title.forEach(e => { if (calDict[e.innerText.trim()]) e.innerText = calDict[e.innerText.trim()]; }); }); }); return; } // itemuseparcel.php // 圣诞小镇 if (href.contains(/christmas_town\.php/)) { let $root = document.querySelector('#christmastownroot'); const $title_wrapper = $root.querySelector('div[class^="appHeaderWrapper___"]'); // 标题和右边的链接 initOB($title_wrapper, {childList: true, subtree: true}, () => { titleTransReact(); contentTitleLinksTransReact(); }); } } // mini profile 翻译 function miniprofTrans() { // 迷你资料卡状态 playerStatusTrans($('div.profile-mini-root div.description span')); // 转钱 sendCashTrans('div.profile-mini-root'); } // 起飞目的地id function getDestId(dest) { // 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南 return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest]; } // 引入torn miniprofile function initMiniProf(selector) { let profileMini = { timeout: 0, clickable: false, rootElement: null, targetElement: null, rootId: 'profile-mini-root', rootSelector: '#profile-mini-root', userNameSelector: "a[href*='profiles.php?XID=']", // contentWrapper: '#wh-trans-icon', contentWrapper: selector, setClickable: function (value) { this.clickable = value }, setRootElement: function () { if (!document.getElementById(this.rootId)) { this.rootElement = document.createElement('div'); this.rootElement.classList.add(this.rootId); this.rootElement.id = this.rootId; $('body').append(this.rootElement); } else { ReactDOM.unmountComponentAtNode($(this.rootSelector).get(0)); this.rootElement = document.getElementById(this.rootId); } }, subscribeForHideListeners: function () { const that = this; let width = $(window).width(); function handleResize(e) { if ($(this).width() !== width) { width = $(this).width(); hideMiniProfile.call(that, e); } } function handleScroll(e) { if (!document.activeElement.classList.contains('send-cash-input')) { hideMiniProfile.call(that, e); } } function hideMiniProfile(e) { if ($(e.target).closest(this.rootSelector).length === 0 || ['resize', 'scroll'].includes(e.type)) { that.targetElement = null ReactDOM.unmountComponentAtNode($(this.rootSelector).get(0)); $(this.userNameSelector).off('click', this.handleUserNameClick); $(this.userNameSelector).unbind('contextmenu'); $(document).off('click', hideMiniProfile); $(window).off('hashchange', hideMiniProfile); $(window).off('resize', handleResize); $(window).off('scroll', handleScroll); } } $(document).on('click', hideMiniProfile.bind(this)); $(window).on('hashchange', hideMiniProfile.bind(this)); $(window).on('resize', handleResize); if (that.targetElement.closest('#chatRoot')) { $(window).on('scroll', handleScroll); } }, subscribeForUserNameClick: function () { $(this.userNameSelector).click(this.handleUserNameClick.bind(this)) }, handleUserNameClick: function () { if (!this.clickable) { this.setClickable(true); return false; } }, subscribeForContextMenu: function (element) { $(element).on('contextmenu', function (e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); return false; }) }, handleMouseDown: function () { const that = this; $(this.contentWrapper).on('mousedown touchstart', this.userNameSelector, function (e) { if (e.which !== 1 && e.type !== 'touchstart') { return false; } that.targetElement = e.currentTarget; that.subscribeForContextMenu(that.targetElement); that.handleFocusLost(e.currentTarget); that.timeout = setTimeout(function () { if (e.type !== 'touchstart') { that.setClickable(false); that.subscribeForUserNameClick(); } else { $(e.currentTarget).off('touchmove mouseleave'); } that.subscribeForHideListeners(); that.setRootElement(); const userID = e.currentTarget.search.slice('?XID='.length); const props = { userID: userID, event: e.originalEvent }; window.renderMiniProfile(that.rootElement, props); }, 500); if (e.type !== 'touchstart') { return false; } }) }, handleMouseUp: function () { const that = this; $(this.contentWrapper).on('mouseup touchend', this.userNameSelector, function () { that.timeout && clearTimeout(that.timeout); }) }, handleFocusLost: function (element) { const that = this; $(element).on('touchmove mouseleave', function unsubscribe() { that.timeout && clearTimeout(that.timeout); $(this).off('touchmove mouseleave', unsubscribe) }) }, init: function () { this.handleMouseDown(); this.handleMouseUp(); } }; profileMini.init(); } // 海外库存 async function forStock() { if (getScriptEngine() === UserScriptEngine.RAW) { const insert = `stock.png`; popupMsg(insert, '飞花库存'); } else { const popup = popupMsg(`请稍后${loading_gif_html()}`, '飞花库存'); let table = ``; const dest = [ { name: 'mex', show: '墨西哥', stocks: {'Dahlia': '花', 'Jaguar Plushie': '偶'} }, { name: 'cay', show: '开曼', stocks: {'Banana Orchid': '花', 'Stingray Plushie': '偶'} }, { name: 'can', show: '加拿大', stocks: {'Crocus': '花', 'Wolverine Plushie': '偶'} }, { name: 'haw', show: '夏威夷', stocks: {'Orchid': '花', 'Large Suitcase': '大箱'} }, { name: 'uni', show: '嘤国', stocks: {'Heather': '花', 'Red Fox Plushie': '赤狐', 'Nessie Plushie': '水怪'} }, { name: 'arg', show: '阿根廷', stocks: {'Ceibo Flower': '花', 'Monkey Plushie': '偶', 'Tear Gas': '催泪弹'}, }, { name: 'swi', show: '瑞士', stocks: {'Edelweiss': '花', 'Chamois Plushie': '偶'}, }, { name: 'jap', show: '日本', stocks: {'Cherry Blossom': '花'}, }, { name: 'chi', show: '祖国', stocks: {'Peony': '花', 'Panda Plushie': '偶'}, }, { name: 'uae', show: '迪拜', stocks: {'Tribulus Omanense': '花', 'Camel Plushie': '偶'}, }, { name: 'sou', show: '南非', stocks: {'African Violet': '花', 'Lion Plushie': '偶', 'Xanax': 'XAN'}, }]; const now = new Date(); const res = await fstock.get(); if (!res['stocks']) return; dest.forEach(el => { const update = (now - new Date(res.stocks[el.name]['update'] * 1000)) / 1000 | 0 table += ``; let count = 0; res.stocks[el.name]['stocks'].forEach(stock => { if (el.stocks[stock.name]) { table += `${el.stocks[stock.name]} (${stock['quantity']})`; count++; } }); while (count < 3) { count++; table += ''; } table += ''; }); table += '
目的地 - 更新时间库存
${el.show}${update / 60 | 0}分${update % 60 | 0}秒前
'; popup.innerHTML = table; } } // 药cd function getYaoCD() { if (document.querySelector("#icon49-sidebar")) { // 0-10min return '<10分' } else if (document.querySelector("#icon50-sidebar")) { // 10min-1h return '<1时' } else if (document.querySelector("#icon51-sidebar")) { // 1h-2h return '1~2时' } else if (document.querySelector("#icon52-sidebar")) { // 2h-5h return '2~5时' } else if (document.querySelector("#icon53-sidebar")) { // 5h+ return '>5时' } else { return '无效' } } // 元素生成器 function elemGenerator(setting, root_node) { let {tip, domType} = setting; let new_node = null; switch (domType) { case 'checkbox': { new_node = document.createElement('div'); let {domId, dictName, domText} = setting; let label = document.createElement('label'); (tip) && (label.setAttribute('title', tip)); let input = document.createElement('input'); input.type = 'checkbox'; input.id = domId; input.checked = getWhSettingObj()[dictName]; input.onchange = e => { setWhSetting(dictName, e.target.checked); if (setting.changeEv) setting.changeEv(e); }; label.innerHTML = domText; label.prepend(input); new_node.appendChild(label); 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.onclick = 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 === getWhSettingObj()[dictName]; option.innerHTML = domText; select.appendChild(option); }); select.onchange = e => setWhSetting(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; } } // 移动节点 return root_node.appendChild(new_node); } // 啤酒 function buyBeer() { // 正在通知 let is_notified = false; let time = getWhSettingObj()['_15AlarmTime'] || 50; let loop = {}; // 循环id let started = null; loop.start = () => { if (started) { log('啤酒助手已在运行'); return; } started = setInterval(() => { // 海外取消提醒 let {isTravelling, isAbroad} = getUserState(); if (isTravelling || isAbroad) { loop.stop(); return; } let dt = new Date(); // 已选当天不提醒 const now = [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate()]; const ignore_date = getWhSettingObj()['_15_alarm_ignore'] || '{}'; if (JSON.stringify(now) === JSON.stringify(ignore_date)) return; // 正常提醒 let m = 14 - (dt.getMinutes() % 15); let s = 60 - dt.getSeconds(); if (m === 0 && s < time) { // 如从通知点开,则本次通知跳过 if (location.href.includes('#clickfromnotify')) { is_notified = true; location.hash = ''; return; } // 本次已通知 if (is_notified) return; is_notified = true; // 发送通知 const notify = WHNotify(notify_html, { timeout: 30, sysNotify: true, }); notify.querySelector('.wh-notify-msg button').addEventListener('click', loop.skip_today); notify.addEventListener('click', ev => { if (ev.target.tagName.toLowerCase() === 'a') { notify.sys_notify.close(); notify.close(); } }); window.setTimeout(audioPlay, 800); window.setTimeout(audioPlay, 800 * 2); window.setTimeout(audioPlay, 800 * 3); } else { is_notified = false; } }, 1000); }; loop.stop = () => { if (started) { clearInterval(started); started = null; } }; loop.set_time = (t) => time = t; loop.status = () => started ? '已启动' : '未启动'; loop.is_running = () => !!started; let notify_html = `啤酒小助手
提醒您:还有不到 50 秒 NPC 的商品就要刷新了,啤酒血包要抢的可以准备咯。
【啤酒店】 【血包店】` loop.skip_today = () => { const date = new Date(); setWhSetting('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false); // 通知 const notify = WHNotify(`明早8点前将不再提醒 `); // 通知中的取消按钮 notify.querySelector('.wh-notify-msg button').addEventListener('click', () => setWhSetting('_15_alarm_ignore', undefined)); }; return loop; } // 战斗页面快速刷新 function doAttackReload() { if (!window.ReactDOM) return; let react_root = document.querySelector('#react-root'); if (!react_root.querySelector('#attacker')) return; let script = document.querySelector('script[src*="/builds/attack/"]'); let url = script.src; if (!url.contains('app.js')) return; ReactDOM.unmountComponentAtNode(react_root); script.remove(); let node = document.createElement('script'); node.src = url; node.type = 'text/javascript'; document.head.appendChild(node); } // 玩家状态 function getUserState() { let obj = {}; let hdd = sessionStorage['headerData']; if (hdd) obj = JSON.parse(hdd)['user']['state']; return obj; } // 一键起飞 function doQuickFly() { // [id: dest, _type: (1...4), ts: timestamp] const [_id, _type, ts] = sessionStorage['wh-quick-fly'].trim().split(' '); if (new Date().getTime() - ts > 20000) { WHNotify('超时,一键起飞计划已取消'); return; } const keynode = document.querySelector('div[data-id][data-key]'); if (!keynode) { WHNotify('出错了,无法起飞,已取消'); return; } const _key = keynode.getAttribute('data-key'); getAction({ type: 'post', data: { step: 'travel', id: getDestId(_id), key: _key, type: ['standard', 'airstrip', 'private', 'business'][_type] }, success: function (str) { WHNotify(str) if (str.includes('err')) { WHNotify('起飞出错了'); return; } window.location.href = 'https://www.torn.com/index.php' }, before: function () { } }); delete sessionStorage['wh-quick-fly']; } // 传单助手 function adHelper() { let popup = popupMsg('', '传单助手'); document.querySelector('#chatRoot').classList.remove('wh-hide'); let info = document.createElement('p'); let ad_input = document.createElement('textarea'); let place_button = document.createElement('button'); let clear_button = document.createElement('button'); let paste_button = document.createElement('button'); let style = document.createElement('style'); info.innerHTML = '打开多个聊天框后,点击填写传单将自动粘贴文本框中的内容进入所有已打开的聊天框。页面外的聊天框同样有效。'; ad_input.placeholder = '此处输入广告语'; ad_input.style.width = '100%'; ad_input.style.minHeight = '80px'; place_button.innerText = '填写传单'; clear_button.innerText = '清空所有聊天框'; paste_button.innerText = '粘贴剪切板'; style.innerHTML = '#chatRoot > div{z-index:199999 !important;}'; place_button.addEventListener('click', () => { let chats = document.querySelectorAll('#chatRoot textarea[name="chatbox2"]'); chats.forEach(chat => chat.value = ad_input.value); }); clear_button.addEventListener('click', () => { let chats = document.querySelectorAll('#chatRoot textarea[name="chatbox2"]'); chats.forEach(chat => chat.value = ''); }); paste_button.addEventListener('click', async () => { ad_input.focus(); ad_input.value = await navigator.clipboard.readText(); }); popup.appendChild(style); popup.appendChild(info); popup.appendChild(ad_input); popup.appendChild(document.createElement('br')); popup.appendChild(place_button); popup.appendChild(clear_button); popup.appendChild(paste_button); } // 公司一键存钱 async function companyDeposit() { if (!location.href.contains('option=funds')) { WHNotify('请先打开公司金库'); return; } if (typeof addRFC !== 'function') return; let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction'); let money = await jQueryAjax(url, 'GET'); if (money === '0') return; let form = document.querySelector('#funds .deposit form'); let funds_input = form.querySelectorAll('input.input-money'); funds_input.forEach(input => { input.value = money; input.attributes['data-money'].value = money; }); $(form).trigger('submit'); WHNotify('存钱成功'); } // 帮派一键存钱 async function factionDeposit() { let form = document.querySelector('#armoury-donate form'); if (!location.hash.includes('tab=armoury') || !form) { WHNotify('请先打开金库'); return; } if (typeof addRFC !== 'function') return; let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction'); let money = await jQueryAjax(url, 'POST'); if (money === '0') return; let funds_input = form.querySelectorAll('input.input-money'); funds_input.forEach(input => { input.value = money; input.attributes['data-money'].value = money; }); $(form).trigger('submit'); let dataStr = `ajax=true&step=armouryDonate&type=cash&amount=${money}`; let res = await (await fetch(addRFC('https://www.torn.com/factions.php'), { method: 'POST', body: dataStr, headers: {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} })).json(); if (res.success === true) { WHNotify('存钱成功'); WHNotify(`${res.text}`); } } // 任何位置公司一键存钱 async function companyDepositAnywhere() { if (typeof addRFC !== 'function') return; let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction'); let money = await jQueryAjax(url, 'GET'); if (money === '0') return; let res = await (await fetch(addRFC('https://www.torn.com/companies.php?step=funds'), { method: 'POST', referrer: 'companies.php', body: 'deposit=' + money, headers: {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} })).text(); log(res); let node = document.createElement('div'); node.innerHTML = res; let success = node.querySelector('.success-message'); if (success) WHNotify(success.innerHTML); } // 包装jquery ajax异步 返回string function jQueryAjax(url, method) { return new Promise((res, rej) => { $.ajax({ method: method, url: url, success: function (data) { res(data) }, error: function (e) { rej(e) } }); }); } // 菜单附加操作按钮 function addActionBtn(txt, func, mainBtnNode) { if (mainBtnNode.querySelector('#wh-trans-icon-btn').nextSibling !== null) return; let btn = document.createElement('button'); btn.style.padding = '8px 13px 8px 0'; btn.style.verticalAlign = 'bottom'; btn.style.color = '#4CAF50'; btn.innerHTML = txt; btn.addEventListener('click', func); mainBtnNode.querySelector('button').after(btn); addActionBtn = function () { log('错误:附加按钮已存在') }; } // 守望者 function safeKeeper() { let url = `https://www.torn.com/loader.php?sid=attackData&mode=json&step=poll&user2ID=`; let popup = popupMsg('

监测目标ID玩家的防御状态,找出隐身攻击者

', '守望者 (测试中)'); let p = document.createElement('p'); let uid = document.createElement('input'); let start = document.createElement('button'); let stop = document.createElement('button'); let self_target = document.createElement('button'); let attackers = document.createElement('div'); attackers.obj = {}; let records = document.createElement('div'); records.list = []; records.details = {}; // interval loop_id let loop_id = null; let updateAttackersDOM = function () { let html = '进攻者:
'; Object.keys(attackers.obj).forEach(id => html += `[${id}]
`); attackers.innerHTML = html; }; let updateRecordsDOM = function () { let html = '战斗记录:
'; records.list.forEach(rid => { let {TimeCreated, attackID, attackerID, attackerItemID, result, text} = records.details[rid]; html += `[${TimeCreated}] [${attackerID}] [${attackerItemID}] ${result} ${text}
`; }); records.innerHTML = html; }; uid.type = 'text'; uid.placeholder = '目标ID'; start.innerHTML = '开启'; stop.innerHTML = '关闭'; stop.disabled = true; self_target.innerHTML = '填入自己'; // 弹出窗口关闭时结束 let popup_close = popup.close; popup.close = () => { if (loop_id === null) popup_close(); else WHNotify('守望者运行中,请先停止', {timeout: 2}); } popup.appendChild(p); popup.appendChild(uid); popup.appendChild(start); popup.appendChild(stop); popup.appendChild(self_target); popup.appendChild(attackers); popup.appendChild(records); start.addEventListener('click', () => { if (loop_id !== null || !uid.value) return; start.disabled = true; stop.disabled = false; uid.readOnly = true; p.innerHTML = '状态:已开 ✅'; let count = 0; loop_id = setInterval(async () => { // 记录当前循环的id let that_id = loop_id; let res = await (await fetch(url + uid.value, { headers: {'X-Requested-With': 'XMLHttpRequest'}, referrer: "loader.php?sid=attack&user2ID=" + uid.value })).text(); if (loop_id !== that_id) return; let data = JSON.parse(res.split(' { if (id === uid.value) return; if (!attackers.obj[id]) { attackers.obj[id] = true; updateAttackersDOM(); } }); // 攻击历史 (DB['currentFightHistory'] || []).forEach(record => { if (records.list.includes(record['ID'])) return; let {ID, TimeCreated, attackID, attackerID, attackerItemID, result, text} = record; records.list.push(ID); records.details[ID] = {TimeCreated, attackID, attackerID, attackerItemID, result, text}; updateRecordsDOM(); }); // 攻击历史日志 if (histLog && histLog[uid.value]) histLog[uid.value].forEach(log => { if (records.list.includes(log['ID'])) return; let {ID, TimeCreated, attackID, attackResult, userID} = log; records.list.push(ID); records.details[ID] = { TimeCreated, attackID, attackerID: userID, attackerItemID: 0, result: attackResult, text: '' }; updateRecordsDOM(); }); }, 900); }); stop.addEventListener('click', () => { if (loop_id === null) return; start.disabled = false; stop.disabled = true; uid.readOnly = false; clearInterval(loop_id); loop_id = null; p.innerHTML = '状态:已关 ❎'; }); self_target.addEventListener('click', () => uid.value = getPlayerInfo()['userID']); } // 更新词库 function updateTransDict() { WHNotify('计划中'); } // 直接回城 async function getHome() { if (typeof window['getAction'] !== 'function') return; let backHomeAction = function () { return new Promise(resolve => { window['getAction']({ type: "post", action: 'travelagency.php', data: { step: 'backHomeAction' }, success: function (msg) { resolve(msg); } }); }); }; let res = await backHomeAction(); WHNotify(res); if (!res.includes('error')) { WHNotify('成功,即将刷新'); setTimeout(() => location.reload(), 3000); } else { WHNotify('出错了'); } } // 边栏信息 function getSidebarData() { return JSON.parse(document.querySelector('#sidebar_data').innerHTML) } /** * 遍历所有子节点 * @param {Node} node 需要遍历的容器父元素 * @param {Function} handler 调用的方法 */ function walkNode(node, handler) { let list = node.childNodes; if (list.length === 0) handler(node); else list.forEach(n => walkNode(n, handler)); } // 落地转跳 function landedRedirect() { let p = document.createElement('p'); let input = document.createElement('input'); let buttonSave = document.createElement('button'); let buttonCmp = document.createElement('button'); let buttonFct = document.createElement('button'); let buttonTest = document.createElement('button'); let br = document.createElement('br'); p.innerHTML = '飞机落地后转跳的页面,关闭功能请置空:'; input.placeholder = 'URL'; input.value = getWhSettingObj()['landedRedirect'] || ''; input.style.display = 'block'; input.style.textAlign = 'left'; input.style.width = '100%'; input.style.padding = '8px'; input.style.margin = '8px -8px'; buttonSave.innerHTML = '保存'; buttonCmp.innerHTML = '填入公司金库'; buttonFct.innerHTML = '填入帮派金库金库'; buttonTest.innerHTML = '测试链接'; buttonSave.addEventListener('click', () => setWhSetting('landedRedirect', input.value)); buttonCmp.addEventListener('click', () => input.value = 'https://www.torn.com/companies.php#/option=funds'); buttonFct.addEventListener('click', () => input.value = 'https://www.torn.com/factions.php?step=your#/tab=armoury'); buttonTest.addEventListener('click', () => window.open(input.value)); let node = popupMsg('', '落地转跳'); node.append(p, input, buttonSave, br, buttonCmp, buttonFct, buttonTest); } /** * fetch ajax包装 * @param {Object} opt * @param {String} opt.url * @param {String} opt.referrer * @param {String} opt.method * @param {String} [opt.body] * @returns {Promise} */ function ajaxFetch(opt) { let {url, referrer, method, body = null} = opt; let req_params = { headers: {'X-Requested-With': 'XMLHttpRequest'}, referrer, method, }; if (method === 'POST') { req_params.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; req_params.body = body; } return fetch(url, req_params); } $zhongNode.initTimer.innerHTML = `助手加载时间 ${Date.now() - start_timestamp}ms`; } // export userscript;