wuhu-torn-helper/src/class/ZhongIcon.ts
2022-10-19 18:05:12 +08:00

1351 lines
56 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import doQuickFly from "../func/module/doQuickFly";
import loadGS from "../func/module/loadGS";
import adHelper from "../func/module/adHelper";
import safeKeeper from "../func/module/safeKeeper";
import updateTransDict from "../func/translate/updateTransDict";
import landedRedirect from "../func/module/landedRedirect";
import initMiniProf from "../func/utils/initMiniProf";
import WuhuBase from "./WuhuBase";
import Log from "./Log";
import CommonUtils from "./utils/CommonUtils";
import WuhuConfig from "./WuhuConfig";
import Alert from "./utils/Alert";
import * as EVENTS from "../static/json/event.json";
import * as FEST from "../static/json/fest.json";
import Popup from "./utils/Popup";
import TravelItem from "./action/TravelItem";
import QUICK_FLY_HTML from "../static/html/quick_fly.html";
import NNB_INFO_HTML from "../static/html/nnb_info.html";
import PRICE_WATCHER_HTML from "../static/html/price_watcher.html";
import DANGER_ZONE_HTML from "../static/html/danger_zone.html";
import ZHONG_MENU_HTML from "../static/html/zhong/zhong_menu.html";
import ZHONG_UPDATE_HTML from "../static/html/zhong/zhong_update.html";
import ZHONG_LOOT_HTML from "../static/html/zhong/zhong_loot.html";
import QUICK_CRIMES_HTML from "../static/html/quick_crimes.html";
import QUICK_FLY_CSS from "../static/css/quick_fly.css";
import QUICK_LINK_CSS from "../static/css/quick_link.css";
import MDUtils from "./utils/MDUtils";
import Test from "../test/Test";
import TornStyleSwitch from "./utils/TornStyleSwitch";
import Global from "./Global";
import BuyBeerHelper from "./action/BuyBeerHelper";
import Timer from "./utils/Timer";
export default class ZhongIcon extends WuhuBase {
className = 'ZhongIcon';
public static ZhongNode: MyHTMLElement = null;
private menuItemList: MenuItemConfig[] = null;
private settingItemList: MenuItemConfig[] = null;
public constructor() {
Log.info('ZhongIcon初始化, 设置图标开始');
super();
this.setDefaultSettings()
.constructWuhuSettingList()
.constructMenuList()
.insert2Dom();
Log.info('设置图标结束, ZhongIcon初始化结束');
}
private elemGenerator(setting: MenuItemConfig, root_node: Element): HTMLElement {
let { tip, domType } = setting;
let new_node = null;
switch (domType) {
case 'checkbox': {
new_node = document.createElement('div');
let { domId, dictName, domText, changeEv } = setting;
let switcher = new TornStyleSwitch(domText);
let _input = switcher.getInput();
switcher.getBase().id = domId;
(tip) && (switcher.getBase().setAttribute('title', tip));
_input.checked = WuhuConfig.get(dictName);
_input.onchange = e => {
WuhuConfig.set(dictName, _input.checked, true);
if (changeEv) changeEv(e);
};
new_node.appendChild(switcher.getBase());
break;
}
case 'button': {
new_node = document.createElement('div');
let { domId, domText, clickFunc } = setting;
let btn = document.createElement('button');
(tip) && (btn.setAttribute('title', tip));
btn.id = domId;
btn.innerHTML = domText;
btn.addEventListener('click', clickFunc);
new_node.appendChild(btn);
break;
}
case 'select': {
new_node = document.createElement('div');
let { domSelectOpt, dictName, domId, domText } = setting;
let label = document.createElement('label');
(tip) && (label.setAttribute('title', tip));
let text = document.createTextNode(domText);
let select = document.createElement('select');
select.id = domId;
domSelectOpt.forEach((opt, i) => {
let { domVal, domText } = opt;
let option = document.createElement('option');
option.value = domVal;
option.innerHTML = domText;
option.selected = i === WuhuConfig.get(dictName);
option.innerHTML = domText;
select.appendChild(option);
});
select.onchange = e => WuhuConfig.set(dictName, (<HTMLSelectElement>e.target).selectedIndex);
label.appendChild(text);
label.appendChild(select);
new_node.appendChild(label);
break;
}
case 'plain': {
let tag = setting.tagName || 'div';
new_node = document.createElement(tag);
if (setting.domId) new_node.id = setting.domId;
new_node.innerHTML += setting['domHTML'];
break;
}
}
// 移动节点
// Log.info('创建node', new_node);
return root_node.appendChild(new_node);
}
/**
* 添加左侧图标
*/
private insert2Dom() {
let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon');
let settings = this.menuItemList;
let { version } = WuhuBase.glob;
if ((self !== top) || !!zhong_node) return null;
zhong_node = document.createElement('div');
zhong_node.id = 'wh-trans-icon';
zhong_node.classList.add('cont-gray');
zhong_node.innerHTML = ZHONG_MENU_HTML.replace('{{}}', version.slice(-1) === '$' ? 'DEV' : version);
// 助手菜单
const menu_cont = zhong_node.querySelector('#wh-gSettings');
// 遍历菜单node设置、生成node、插入dom
this.menuItemList.forEach(setting => this.elemGenerator(setting, menu_cont));
Log.info('生成元素插入完成');
// 计时node
zhong_node.initTimer = zhong_node.querySelector('#wh-inittimer');
// 芜湖助手图标点击事件
(<MyHTMLElement>zhong_node.querySelector('#wh-trans-icon-btn')).onclick = () => {
zhong_node.classList.toggle('wh-icon-expanded');
const click_func = e => {
Log.info(e.target);
if (e.target === zhong_node.querySelector('#wh-trans-icon-btn')) return;
if (!zhong_node.contains(e.target)) {
Log.info('移除事件监听器');
document.body.removeEventListener('click', click_func);
zhong_node.classList.remove('wh-icon-expanded');
}
};
if (zhong_node.classList.contains('wh-icon-expanded')) {
Log.info('添加事件监听器');
document.body.addEventListener('click', click_func);
} else {
Log.info('移除事件监听器');
document.body.removeEventListener('click', click_func);
}
};
// 更新按钮点击事件
(<MyHTMLElement>zhong_node.querySelector('#wh-update-btn')).onclick = e => {
(<HTMLButtonElement>e.target).blur();
const innerHtml = ZHONG_UPDATE_HTML;
// 直接复制的按钮
new Popup(innerHtml, '如何更新')
.getElement()
.querySelector('button').onclick = async (e) => {
let target = e.target as HTMLButtonElement;
target.innerHTML = '加载中';
const js_text = await CommonUtils.COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${ performance.now() }`);
target.innerHTML = '点击复制到剪切板';
target.onclick = () => {
const textarea_node = document.createElement('textarea');
textarea_node.innerHTML = js_text;
target.parentElement.append(textarea_node);
textarea_node.focus();
textarea_node.select();
document.execCommand('Copy');
textarea_node.remove();
target.innerHTML = '已复制';
target.onclick = null;
new Alert('脚本已复制,请前往粘贴');
};
};
};
// 节日
zhong_node.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0
? el.addEventListener('click', () => {
let html = '<table>';
settings.fest_date_list.sort().forEach(date =>
html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }${ date.slice(2) }日</td><td>${ settings.fest_date_dict[date].name }</td><td>${ settings.fest_date_dict[date].eff }</td></tr>`
);
new Popup(html += '</table>', '节日');
})
: el.addEventListener('click', null));
// 活动
zhong_node.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0
? el.addEventListener('click', () => {
let html = '<table>';
settings.events.forEach(el =>
html += `<tr><td><b>${ el.name }</b></td><td>${ el.start[0] + 1 }${ el.start[1] }${ el.start[2] }:00~${ el.end[0] + 1 }${ el.end[1] }${ el.end[2] }:00</td></tr><tr><td colspan="2">${ el.eff }</td></tr>`);
new Popup(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
})
: el.addEventListener('click', null));
document.body.append(zhong_node);
// 引入torn自带浮动提示
Log.info('引入torn自带浮动提示');
(window.initializeTooltip) && (window.initializeTooltip('.wh-container', 'white-tooltip'));
// 加载torn mini profile
Log.info('加载torn mini profile');
let miniProfileInterval = {
id: window.setInterval(() => {
miniProfileInterval.counter++;
if (window.$ || (window.unsafeWindow && window.unsafeWindow.$)) {
initMiniProf('#wh-trans-icon');
window.clearInterval(miniProfileInterval.id);
}
if (miniProfileInterval.counter > 30) window.clearInterval(miniProfileInterval.id);
}, 1000),
counter: 0
};
ZhongIcon.ZhongNode = zhong_node;
Log.info('图标加入文档树完成');
}
// 菜单
private constructMenuList(): ZhongIcon {
Log.info('构造展开菜单列表开始');
let timer = new Timer();
let glob = Global.getInstance();
const date = new Date();
let list: MenuItemConfig[] = [];
// 欢迎 显示玩家id
if (glob.player_info.userID !== 0) {
list.push({
domType: 'plain',
domId: 'wh-trans-welcome',
domHTML: `<span>欢迎 <a href="/profiles.php?XID=${ glob.player_info.userID }" target="_blank">${ glob.player_info.playername }</a>[${ glob.player_info.userID }] 大佬</span>`,
});
}
// 节日
let fest_date_html = '<button>节日</button>: ';
{
// 节日字典
const dict = FEST.val;
list.fest_date_dict = dict;
list.fest_date_list = Object.keys(dict);
const formatMMDD = (m, d) => {
const MM = m < 10 ? `0${ m }` : m.toString();
const DD = d < 10 ? `0${ d }` : d.toString();
return MM + DD;
}
const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate());
if (dict[fest_date_key]) fest_date_html += `今天 - ${ dict[fest_date_key]['name'] }(<button title="${ dict[fest_date_key]['eff'] }">效果</button>)`;
else {
// 月日列表
let list = Object.keys(dict);
list.push(fest_date_key);
// 下个节日的位置
const index: number = list.sort().indexOf(fest_date_key) + 1;
// 下个节日obj
const next_fest_date = dict[list[index] || list[0]];
// 下个节日的时间
let next = new Date(
index !== list.length ? date.getUTCFullYear() : date.getUTCFullYear() + 1,
(list[index !== list.length ? index : 0] as any).slice(0, 2) | 0,
(list[index !== list.length ? index : 0] as any).slice(2) | 0,
8
).getTime();
// 剩余天数
const left = (next - date.getTime()) / 86400000 | 0;
fest_date_html += `${ left }天后 - ${ next_fest_date.name }(<button title="${ next_fest_date.eff }">效果</button>)`;
}
}
list.push({
domType: 'plain',
domId: 'wh-trans-fest-date',
domHTML: fest_date_html,
});
// 活动
let eventObj: EventWrapper = {
onEv: false,
daysLeft: Infinity,
events: EVENTS.default,
};
list.events = eventObj.events;
eventObj.events.forEach((obj, index) => {
if (eventObj.onEv) return;
// 当前年份
const nowYear = date.getFullYear();
// 当前遍历的活动开始时间
const start = new Date(nowYear, obj.start[0], obj.start[1], obj.start[2]);
// 当前遍历的活动结束时间
const end = new Date(nowYear, obj.end[0], obj.end[1], obj.end[2]);
// 当前处于活动中
if (start < date && date < end) {
eventObj.onEv = true;
eventObj.daysLeft = (end.getTime() - date.getTime()) / 86400000 | 0;
eventObj.current = obj;
}
// 当前没有活动
else {
// 当前遍历的活动如果已经经过了,那么下次活动就是遍历的下一个活动对象,否则为当前活动。
// 如果本年度活动都经过了,那么下次活动是列表的第一个活动对象
const next = end < date ? eventObj.events[index + 1] || eventObj.events[0] : obj;
// 经过了最后一个活动所以下次活动开始时间是第二年
const start = new Date(next !== obj && index === eventObj.events.length - 1 ? nowYear + 1 : nowYear, next.start[0], next.start[1], next.start[2]);
const daysLeft = (start.getTime() - date.getTime()) / 86400000 | 0;
if (0 <= daysLeft && daysLeft < eventObj.daysLeft) {
eventObj.daysLeft = daysLeft;
eventObj.next = next;
}
}
});
eventObj.html = '<button>活动</button>: ';
eventObj.onEv
? eventObj.html += `${ eventObj.current.name }(<button title="${ eventObj.current.eff }">详情</button>) - 剩余${ eventObj.daysLeft }`
: eventObj.html += `${ eventObj.daysLeft }天后 - ${ eventObj.next.name }(<button title="${ eventObj.next.eff }">详情</button>)`;
list.push({
domType: 'plain',
domId: 'wh-trans-event-cont',
domHTML: eventObj.html,
});
// 飞花库存
list.push({
domType: 'button',
domId: 'wh-foreign-stock-btn',
domText: '🌸 飞花库存',
clickFunc: async function (e) {
e.target.blur();
// forStock().then();
TravelItem.getInstance().clickHandler().then();
},
});
// 一键起飞
list.push({
domType: 'button',
domId: 'wh-quick-fly-btn',
domText: '✈️ 一键起飞',
clickFunc: async function () {
if (window.hasWHQuickFlyOpt) return;
window.hasWHQuickFlyOpt = true;
// TODO
CommonUtils.addStyle(QUICK_FLY_CSS);
const node = document.createElement('div');
node.id = 'wh-quick-fly-opt';
node.innerHTML = QUICK_FLY_HTML;
const [dest_node, type_node] = node.querySelectorAll('select') as any as HTMLSelectElement[];
node.querySelector('button').addEventListener('click', () => {
sessionStorage['wh-quick-fly'] = `${ dest_node.selectedIndex } ${ type_node.selectedIndex } ${ new Date().getTime() }`;
if (!glob.href.contains('travelagency.php')) {
new Alert('正在转跳');
location.href = 'https://www.torn.com/travelagency.php';
} else {
doQuickFly();
}
});
node.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
// forStock();
TravelItem.getInstance().clickHandler();
});
node.querySelector('input').addEventListener('click', (e) => {
node.classList.toggle('wh-quick-fly-opt-hide');
const el = e.target as HTMLInputElement;
el.value = el.value === ' - ' ? ' + ' : ' - ';
});
const info_node = node.querySelector('info');
const time_predict = document.createElement('p');
const yaoCD = document.createElement('p');
info_node.append(time_predict);
info_node.append(yaoCD);
const predict = [
['~54分', '~36分', '~26分', '~16分',],
['~1时10分', '~50分', '~36分', '~22分',],
['~1时22分', '~58分', '~40分', '~24分',],
['~4时28分', '~3时8分', '~2时14分', '~1时20分',],
['~5时18分', '~3时42分', '~2时40分', '~1时36分',],
['~5时34分', '~3时54分', '~2时46分', '~1时40分',],
['~5时50分', '~4时6分', '~2时56分', '~1时46分',],
['~7时30分', '~5时16分', '~3时46分', '~2时16分',],
['~8时4分', '~5时38分', '~4时2分', '~2时24分',],
['~9时2分', '~6时20分', '~4时30分', '~2时42分',],
['~9时54分', '~6时56分', '~4时58分', '~2时58分',],
];
const showTime = function () {
time_predict.innerHTML = `往返时间:${ predict[dest_node.selectedIndex][type_node.selectedIndex] }`;
}
dest_node.addEventListener('change', showTime);
type_node.addEventListener('change', showTime);
document.body.append(node);
showTime();
yaoCD.innerHTML = `药CD剩余${ CommonUtils.getYaoCD() }`;
},
});
// NPC LOOT
list.push({
domType: 'button',
domId: 'wh-npc-loot-btn',
domText: '🔫 LOOT',
clickFunc: function (e) {
e.target.blur();
const insert = ZHONG_LOOT_HTML.replace('{{}}', performance.now().toString());
new Popup(insert, 'NPC LOOT');
},
tip: '显示5个可击杀NPC的开打时间',
});
// 查看NNB
list.push({
domType: 'button',
domId: 'wh-nnb-info',
domText: '👮‍ 查看NNB',
clickFunc: function (e) {
e.target.blur();
const insert = NNB_INFO_HTML
.replace('{{}}', localStorage.getItem('APIKey') || '不可用')
.replace('{{}}', glob.isPDA ? glob.PDA_APIKey : '不可用');
const popup = new Popup(insert, '查看NNB').getElement();
const select = popup.querySelector('input');
const node = popup.querySelector('p');
popup.querySelector('button').addEventListener('click', ev => {
let target = ev.target as HTMLInputElement;
target.style.display = 'none';
node.innerHTML = '加载中';
// API 计算
if (select.checked) {
const api_key = glob.isPDA ? glob.PDA_APIKey : window.localStorage.getItem('APIKey');
window.fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`)
.then(res => res.json())
.then(data => {
if (data['error']) {
node.innerHTML = `出错了 ${ JSON.stringify(data['error']) }`;
target.style.display = null;
return;
}
let nb = data['nerve']['maximum'];
let perks = 0;
Object.values(data).forEach(val => {
(val instanceof Array) && val.forEach(s => {
s = s.toLowerCase();
s.includes('maximum nerve') && (perks += (<any>new RegExp('[0-9].').exec(s))[0] | 0)
})
});
node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null;
});
}
// 主页计算
else {
if (window.location.href.includes('index.php') && document.title.includes('Home')) {
let nb = (<any>document.querySelector('#barNerve p[class^="bar-value___"]').innerText.split('/')[1]) | 0;
let perks = 0;
document.querySelectorAll('#personal-perks li').forEach(elem => {
const str = elem.innerText.toLowerCase();
str.includes('maximum nerve') && (perks += (/[0-9]./.exec(str) as any)[0] | 0)
});
node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null;
return;
}
node.innerHTML = '不在主页面,<a href="/index.php">点击前往</a>';
target.style.display = null;
}
});
},
});
// 常用链接
list.push({
domType: 'button',
domId: 'wh-link-collection',
domText: '🔗 常用链接',
clickFunc: function (e) {
if (!this.styleAdded) {
CommonUtils.addStyle(QUICK_LINK_CSS);
this.styleAdded = true;
}
e.target.blur();
const quick_link_dict = [];
// 生存手册
quick_link_dict.push({
name: '生存手册',
url: 'https://docs.qq.com/doc/DTVpmV2ZaRnB0RG56',
new_tab: true,
img: 'https://www.torn.com/images/items/293/medium.png',
});
// 买啤酒
quick_link_dict.push({
name: '抢啤酒',
url: 'https://www.torn.com/shops.php?step=bitsnbobs',
new_tab: true,
img: 'https://www.torn.com/images/items/180/medium.png',
});
// 买XAN
quick_link_dict.push({
name: '买XAN',
url: 'https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax',
new_tab: true,
img: 'https://www.torn.com/images/items/206/medium.png',
});
// 起飞
quick_link_dict.push({
name: '起飞',
url: 'https://www.torn.com/travelagency.php',
new_tab: true,
img: 'https://www.torn.com/images/items/396/medium.png',
});
// 买PT
quick_link_dict.push({
name: '买PT',
url: 'https://www.torn.com/pmarket.php',
new_tab: true,
img: 'https://www.torn.com/images/items/722/medium.png',
});
// 租PI
quick_link_dict.push({
name: '租PI',
url: 'https://www.torn.com/properties.php?step=rentalmarket#/property=13',
new_tab: false,
img: 'https://www.torn.com/images/v2/properties/350x230/350x230_default_private_island.png',
});
// 找工作
quick_link_dict.push({
name: '找工作',
url: 'https://www.torn.com/joblist.php#!p=main',
new_tab: false,
img: 'https://www.torn.com/images/items/421/medium.png',
});
// 下悬赏
quick_link_dict.push({
name: '下悬赏',
url: 'https://www.torn.com/bounties.php#/p=add',
new_tab: false,
img: 'https://www.torn.com/images/items/431/medium.png',
});
let insert = '<p>';
quick_link_dict.forEach(el => {
insert += `<a href="${ el.url }"${ el.new_tab ? ' target="_blank"' : '' }><span class="wh-link-collection-img" style="background: url(${ el.img })"></span><span>${ el.name }</span></a>`;
});
insert += '</p>'
let popup = new Popup(insert, '常用链接');
popup.getElement().classList.add('wh-link-collection-cont');
popup.getElement().addEventListener('click', ev => {
let target = ev.target as HTMLElement;
if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'span') {
popup.close();
}
});
},
});
// 飞贼
list.push({
domType: 'button',
domId: 'wh-gs-btn',
domText: '🐏 飞贼小助手',
clickFunc: function (e) {
e.target.blur();
loadGS(CommonUtils.getScriptEngine());
},
tip: '加载从PC端移植的伞佬的油猴版飞贼小助手',
});
// 物品价格监视
list.push({
domType: 'button',
domId: 'wh-price-watcher-btn',
domText: '💊 价格监视',
clickFunc: function () {
const watcher_conf = WuhuConfig.get('priceWatcher');
const pre_str = JSON.stringify(watcher_conf);
const html = PRICE_WATCHER_HTML
.replace('{{}}', localStorage.getItem('APIKey') || '不可用')
.replace('{{}}', glob.isPDA ? glob.PDA_APIKey : '不可用')
.replace('{{}}', watcher_conf['pt'] || -1)
.replace('{{}}', watcher_conf['xan'] || -1);
const popup = new Popup(html, '价格监视设置');
popup.getElement().querySelector('button').onclick = () => {
const [pt_node, xan_node] = Array.from(<NodeListOf<HTMLInputElement>>popup.getElement().querySelectorAll('input[type="number"]'));
watcher_conf.pt = (pt_node.value as any) | 0;
watcher_conf.xan = (xan_node.value as any) | 0;
if (JSON.stringify(watcher_conf) !== pre_str) WuhuConfig.set('priceWatcher', watcher_conf);
popup.close();
};
}
});
// 小窗犯罪
list.push({
domType: 'button',
domId: 'wh-crime-iframe-btn',
domText: '🤑 小窗犯罪',
clickFunc: function () {
// 弹出小窗口
const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`;
const popup_insert = `<p>加载中请稍后${ CommonUtils.loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
const $popup = new Popup(popup_insert, '小窗快速犯罪').getElement();
// 运行状态node
let loading_node = $popup.querySelector('p:first-of-type');
// if容器
const if_cont = $popup.querySelector('#wh-quick-crime-if-container');
if_cont.innerHTML = ifHTML;
// if内未加载脚本时插入的快捷crime node
const mobile_prepend_node = document.createElement('div');
mobile_prepend_node.classList.add('wh-translate');
mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML;
// if对象加载后运行
let cIframe = $popup.querySelector('iframe');
// 加载状态
const if_onload_func = () => {
// if内部文档对象
const ifDocu = cIframe.contentWindow.document;
// 内部插件运行flag
const ifWH = cIframe.contentWindow.WHTRANS;
// 文档加载完成后移除
if (!!loading_node) loading_node.remove();
// 文档加载完成后才显示if
cIframe.style.display = 'block';
// 验证码flag
const isValidate = ifDocu.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
// 如果iframe内部未运行脚本
if (ifWH === undefined) {
// 隐藏顶部
CommonUtils.elementReady('#header-root', ifDocu).then(e => e.style.display = 'none');
// 隐藏4条
CommonUtils.elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none');
// 隐藏聊天
CommonUtils.elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none');
// 非验证码页面隐藏滚动条
if (!isValidate) ifDocu.body.style.overflow = 'hidden';
// 调整容器位置
CommonUtils.elementReady('.content-wrapper', ifDocu).then(elem => {
// 加入
elem.prepend(mobile_prepend_node);
elem.style.margin = '0px';
elem.style.position = 'absolute';
elem.style.top = '-35px';
new MutationObserver((m, o) => {
o.disconnect();
if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
o.observe(elem, { childList: true, subtree: true });
})
.observe(elem, { childList: true, subtree: true });
});
// 隐藏返回顶部按钮
CommonUtils.elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
}
};
cIframe.onload = if_onload_func;
// 超时判断
let time_counter = 0;
let time_out_id = window.setInterval(() => {
loading_node = $popup.querySelector('p:first-of-type');
if (!loading_node) {
clearInterval(time_out_id);
time_out_id = undefined;
return;
}
time_counter++;
if (time_counter > 0 && !loading_node.querySelector('button')) {
const reload_btn = document.createElement('button');
reload_btn.innerHTML = '重新加载';
reload_btn.onclick = () => {
reload_btn.remove();
time_counter = 0;
if_cont.innerHTML = null;
if_cont.innerHTML = ifHTML;
cIframe = $popup.querySelector('iframe');
cIframe.onload = if_onload_func;
};
loading_node.append(reload_btn);
}
}, 1000);
}
});
// 危险行为开关⚠️
list.push({
domType: 'button',
domId: 'wh-danger-zone',
domText: '⚠️ 危险功能',
clickFunc: function (e) {
e.target.blur();
const insert = DANGER_ZONE_HTML.replace('{{}}', WuhuConfig.get('dangerZone') ? 'checked ' : ' ');
const popup = new Popup(insert, '⚠️警告');
const warning_check = popup.getElement().querySelector('input');
const ok_btn = popup.getElement().querySelector('button');
warning_check.onchange = () => ok_btn.disabled = false;
ok_btn.onclick = () => {
WuhuConfig.set('dangerZone', warning_check.checked);
popup.close();
window.location.reload();
};
},
});
// 传单助手
list.push({
domType: 'button',
domId: '',
domText: '📜️ 传单助手',
clickFunc: adHelper
});
// 守望者
list.push({
domType: 'button',
domId: '',
domText: '🛡️ 守望者',
clickFunc: function () {
safeKeeper();
},
});
// 寻找木桩
list.push({
domType: 'button',
domId: '',
domText: '🪵 寻找木桩',
clickFunc: () => window.location.href = 'https://www.torn.com/item.php?temp=4#xunzhaomuzhuang'
});
// 更新历史
list.push({
domType: 'button', domId: '', domText: '🐞 更新历史', clickFunc: async () => {
let popup = new Popup(
'更新历史:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a><br/>',
'更新历史'
).getElement();
popup.classList.add('wh-changeLog');
let progressBar = document.createElement('div');
progressBar.style.height = '2px';
progressBar.style.width = '1%';
progressBar.style.backgroundColor = 'red';
let progressText = document.createElement('p');
progressText.innerText = '加载更新文件……';
progressText.style.textAlign = 'center';
let style = document.createElement('style');
style.innerHTML = `.wh-changeLog h2,.wh-changeLog h3,.wh-changeLog h4 {margin:8px 0;}.wh-changeLog li{list-style: inside;}`;
popup.append(progressBar, progressText, style);
let update = await CommonUtils.COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + Date.now());
progressBar.style.width = '60%';
progressText.innerText = '解析中……';
let md = MDUtils.getInstance().parse(update);
popup.append(md);
progressBar.style.width = '100%';
progressText.innerText = '加载完成';
setTimeout(() => {
progressBar.remove();
progressText.remove()
}, 3000);
},
});
// 助手设置
list.push({
domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => {
let startTime = performance.now();
Log.info('构造设置开始');
let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置');
let tmp = document.createElement('div');
tmp.classList.add('gSetting');
this.settingItemList.forEach(set => this.elemGenerator(set, tmp));
pop.getElement().innerHTML = '';
pop.getElement().appendChild(tmp);
// 本日不提醒
pop.getElement().querySelector('#wh-qua-alarm-check-btn').addEventListener('click', () => Global.getInstance().beer.skip_today());
// 开发详情按钮
// if (Log.debug()) $zhongNode.setting_root.querySelector('button#wh-devInfo').onclick = () => {
// const date = new Date();
// let os = '未知';
// try {
// os = window.navigator.userAgentData.platform || window.navigator.platform
// } catch {
// }
//
// pop.close();
// new Popup(DEV_DETAILS_HTML, '开发者详情');
// };
(window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip'));
Log.info('构造设置结束,' + ((performance.now() - startTime) | 0) + 'ms');
},
});
// 测试
if (Log.debug()) list.push({
domType: 'button',
domId: '',
domText: '📐️ 测试',
clickFunc: async function () {
let startTime = performance.now();
Log.info('测试开始');
try {
Test.getInstance().test();
} catch (e) {
Log.error('测试异常,' + JSON.stringify(e));
}
Log.info('测试结束 ' + ((performance.now() - startTime) | 0) + 'ms');
},
});
this.menuItemList = list;
Log.info('构造展开菜单列表结束' + timer.getTimeMs());
return this;
}
// 设置
private constructWuhuSettingList(): ZhongIcon {
Log.info('构造设置列表开始');
let timer = new Timer();
const date = new Date();
let beer = BuyBeerHelper.getInstance();
let list: MenuItemConfig[] = [];
// 12月时加入圣诞小镇选项
if (date.getMonth() === 11) {
list.push({
domType: 'plain',
domId: '',
domHTML: '圣诞小镇',
tagName: 'h4',
})
list.push({
domType: 'checkbox',
domId: 'wh-xmastown-wt',
domText: ' 圣诞小镇攻略',
dictName: 'xmasTownWT',
isHide: true,
});
list.push({
domType: 'checkbox',
domId: 'wh-xmastown-notify',
domText: ' 圣诞小镇物品提示',
dictName: 'xmasTownNotify',
isHide: true,
});
}
// 翻译
list.push({
domType: 'plain',
domId: '',
domHTML: '翻译',
tagName: 'h4',
});
// 开启翻译
list.push({
domType: 'checkbox',
domId: 'wh-trans-enable',
domText: ' 开启翻译',
dictName: 'transEnable',
isHide: true,
});
// 更新翻译词库
list.push({
domType: 'button',
domId: '',
domText: '更新翻译词库',
clickFunc: updateTransDict
});
// 战斗优化
list.push({
domType: 'plain',
domId: '',
domHTML: '战斗优化',
tagName: 'h4',
});
// 光速拔刀
list.push({
domType: 'select',
domId: 'wh-quick-attack-index',
domText: '光速拔刀 ',
domSelectOpt: [
{
domVal: 'pri',
domText: '主手',
},
{
domVal: 'sec',
domText: '副手',
},
{
domVal: 'wea',
domText: '近战',
},
{
domVal: 'gre',
domText: '手雷',
},
{
domVal: 'fis',
domText: '拳头',
},
{
domVal: 'kic',
domText: '脚踢',
},
{
domVal: 'none',
domText: '关闭',
},
],
dictName: 'quickAttIndex',
isHide: true,
tip: '将Start Fight按钮移动到指定格子上',
});
// 光速跑路
list.push({
domType: 'select',
domId: 'wh-quick-mug',
domText: '光速跑路 ',
domSelectOpt: [
{
domVal: 'leave',
domText: '跑路(LEAVE)',
},
{
domVal: 'mug',
domText: '打劫(MUG)',
},
{
domVal: 'hosp',
domText: '住院(HOSP)',
},
{
domVal: 'none',
domText: '关闭',
},
],
dictName: 'quickFinishAtt',
isHide: true,
tip: '<del>将结束后指定按钮移动到上面指定的格子上</del>暂时关闭',
});
// 攻击链接转跳
list.push({
domType: 'checkbox',
domId: 'wh-attack-relocate',
domText: ' 真·攻击界面转跳',
dictName: 'attRelocate',
tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面',
isHide: true,
});
// 飞行
list.push({
domType: 'plain',
domId: '',
domHTML: '飞行',
tagName: 'h4',
});
// 起飞警告
list.push({
domType: 'checkbox',
domId: 'wh-energy-alert',
domText: ' 起飞爆E警告',
dictName: 'energyAlert',
tip: '起飞前计算来回是否会爆体,红字警告',
isHide: true,
});
// 飞行闹钟
list.push({
domType: 'checkbox',
domId: 'wh-trv-alarm-check',
domText: ' 飞行闹钟',
dictName: 'trvAlarm',
tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限',
isHide: true,
});
// 海外警告
list.push({
domType: 'checkbox',
domId: '',
domText: ' 海外警告',
dictName: 'abroadWarning',
tip: '海外落地后每30秒通知警告',
});
// 落地转跳
list.push({ domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect });
// 公司
list.push({
domType: 'plain',
domId: '',
domHTML: '公司',
tagName: 'h4',
});
// 浮动存钱框
list.push({
domType: 'checkbox',
domId: '',
domText: ' 浮动存钱框',
dictName: 'floatDepo',
tip: '打开公司或帮派的存钱页面后存钱框将浮动显示',
});
// 公司转跳存钱
list.push({
domType: 'checkbox',
domId: '',
domText: ' 公司转跳存钱',
dictName: 'companyRedirect',
tip: '打开公司页面时自动打开存钱选项卡',
});
// 收起公司冰蛙效率表
list.push({
domType: 'checkbox',
domId: '',
domText: ' 收起公司冰蛙效率表',
dictName: 'companyBWCollapse',
tip: '开启后可手动显示隐藏冰蛙公司表格',
});
// 任何位置一键存钱
list.push({
domType: 'checkbox',
domId: '',
domText: ' 任何位置一键存钱',
dictName: 'companyDepositAnywhere',
tip: '在所有页面显示一键存钱按钮Torn OK状态下可用此功能未完全测试无害使用请慎重',
});
// 啤酒
list.push({
domType: 'plain',
domId: '',
domHTML: '啤酒',
tagName: 'h4',
});
// 啤酒提醒
list.push({
domType: 'checkbox',
domId: 'wh-qua-alarm-check',
domText: '<span> 啤酒提醒 </span><button id="wh-qua-alarm-check-btn">今日不提醒</button>',
dictName: '_15Alarm',
tip: '每小时的整15分钟的倍数时通知提醒抢啤酒或者血包',
isHide: true,
changeEv: function (ev) {
ev.target.checked ? beer.start() : beer.stop();
},
});
// 啤酒提醒状态
list.push({
domType: 'button',
domId: '',
domText: '啤酒提醒状态',
clickFunc: function () {
new Alert(`啤酒提醒${ beer.status() }`);
}
});
// 啤酒提醒时间
list.push({
domType: 'button',
domId: '',
domText: '啤酒提醒时间设定',
// tip: '通知提前时间',
clickFunc: function () {
let popup = new Popup(`<label>提前提醒时间(秒)<input type="number" value="${ WuhuConfig.get('_15AlarmTime') }" /></label><p>区间为 1 ~ 60默认 50</p>`, '啤酒提醒时间设定');
let confirm = document.createElement('button');
confirm.innerHTML = '确定';
confirm.style.float = 'right';
confirm.addEventListener('click', () => {
let input: HTMLInputElement = popup.getElement().querySelector('input');
let num = (input.value as any) | 0;
if (num === WuhuConfig.get('_15AlarmTime')) return;
if (num < 1 || num > 60) num = 50;
input.value = num.toString();
WuhuConfig.set('_15AlarmTime', num);
beer.set_time(num);
// 之前的运行状态
if (beer.is_running()) beer.start();
popup.close();
});
popup.getElement().appendChild(confirm);
},
});
// 其他
list.push({
domType: 'plain',
domId: '',
domHTML: '其他',
tagName: 'h4',
});
// 任务助手
list.push({
domType: 'checkbox',
domId: 'wh-mission-lint',
domText: ' 任务助手',
dictName: 'missionHint',
tip: 'Duke任务的一些中文小提示',
isHide: true,
});
// 捡垃圾助手
list.push({
domType: 'checkbox',
domId: 'wh-city-finder',
domText: ' 捡垃圾助手',
dictName: 'cityFinder',
tip: '城市地图中放大显示物品并且估计价值',
isHide: true,
});
// 快速crime
list.push({
domType: 'checkbox',
domId: 'wh-quick-crime',
domText: ' 快速犯罪',
dictName: 'quickCrime',
tip: '显示快捷操作按钮,目前不支持自定义',
isHide: true,
});
// 叠E保护
list.push({
domType: 'checkbox',
domId: 'wh-SEProtect-check',
domText: ' 叠E保护',
dictName: 'SEProtect',
tip: '隐藏健身房的锻炼按钮,防止误操作',
isHide: true,
});
// PT一键购买
list.push({
domType: 'checkbox',
domId: 'wh-ptQuickBuy-check',
domText: ' PT一键购买',
dictName: 'ptQuickBuy',
tip: 'PT市场页面购买时跳过确认',
isHide: true,
});
// 4条转跳
list.push({
domType: 'checkbox',
domId: '',
domText: ' 4条转跳',
dictName: 'barsRedirect',
tip: '点击4条时转跳对应页面',
});
// 清除多余的脚本
list.push({
domType: 'checkbox',
domId: '',
domText: ' 清除多余的脚本',
dictName: 'removeScripts',
tip: '清除Google相关脚本、顶部横幅等',
});
// 危险行为⚠️
if (WuhuConfig.get('dangerZone') === true) {
// 攻击界面自刷新
list.push({
domType: 'select',
domId: 'wh-attack-reload',
domText: '⚠️攻击界面自动刷新 ',
dictName: 'attReload',
domSelectOpt: [
{
domVal: 'none',
domText: '无间隔',
},
{
domVal: '1',
domText: '约1s',
},
{
domVal: '2',
domText: '约2s',
},
{
domVal: '3',
domText: '约3s',
},
{
domVal: '4',
domText: '约4s',
},
{
domVal: '5',
domText: '约5s',
},
{
domVal: 'disabled',
domText: '关闭',
},
],
isHide: true,
tip: '危险功能:接机时常用,将自动刷新页面直到目标落地',
});
// 自动开打和结束
list.push({
domType: 'checkbox',
domId: 'wh-auto-start-finish',
domText: ' ⚠️自动开打和结束',
dictName: 'autoStartFinish',
tip: '脚本将会自动按下战斗和结束按钮',
isHide: true,
});
} else {
WuhuConfig.set('autoStartFinish', false)
WuhuConfig.set('attReload', 6)
}
// dev
list.push({
domType: 'checkbox',
domId: 'wh-dev-mode',
domText: '开发模式',
dictName: 'isDev',
isHide: true,
});
// 查看logs
list.push({
domType: 'button',
domId: null,
domText: '查看日志',
clickFunc: () => {
let logCounter = Log.getCounter();
let pop = new Popup('<textarea readonly style="width:100%;height:340px;"></textarea>', '查看日志');
let text = pop.getElement().querySelector('textarea');
text.innerHTML = Log.getLogs();
text.onclick = () => text.select();
pop.getElement().insertAdjacentHTML('afterbegin', `<p>${ logCounter.info }信息 ${ logCounter.warning }警告 ${ logCounter.error }错误</p>`)
}
});
// 更多设定
list.push({
domType: 'button', domId: 'wh-otherBtn', domText: '更多设定',
clickFunc: () => {
let pop = new Popup('', '更多设定');
let insertHtml = '<p><button class="torn-btn">清空设置</button></p><p><button class="torn-btn">通知权限</button></p><p><button class="torn-btn">外部数据权限</button></p>';
pop.getElement().insertAdjacentHTML('beforeend', insertHtml);
let [btn1, btn2, btn3] = Array.from(pop.getElement().querySelectorAll('button'));
btn1.addEventListener('click', () => {
localStorage.removeItem('wh_trv_alarm');
localStorage.removeItem('wh_trans_settings');
localStorage.removeItem('whuuid');
localStorage.removeItem('wh-gs-storage');
localStorage.removeItem('WHTEST');
new Alert('已清空,刷新页面');
window.location.reload();
});
btn2.addEventListener('click', () => {
});
btn3.addEventListener('click', () => {
});
},
// isHide: true,
});
this.settingItemList = list;
Log.info('构造设置列表结束' + timer.getTimeMs());
return this;
}
// 默认设置
private setDefaultSettings(): ZhongIcon {
Log.info('设置默认值开始');
let count = 0;
[
// 开启翻译
{ key: 'transEnable', val: false },
// 快速犯罪
{ key: 'quickCrime', val: true },
// 任务助手
{ key: 'missionHint', val: true },
// 小镇攻略
{ key: 'xmasTownWT', val: true },
// 小镇提醒
{ key: 'xmasTownNotify', val: true },
// 起飞爆e
{ key: 'energyAlert', val: true },
// 飞行闹钟
{ key: 'trvAlarm', val: true },
// 啤酒提醒
{ key: '_15Alarm', val: true },
// 捡垃圾助手
{ key: 'cityFinder', val: false },
// 叠E保护
{ key: 'SEProtect', val: false },
// PT一键购买
{ key: 'ptQuickBuy', val: false },
// 光速拔刀 6-关闭
{ key: 'quickAttIndex', val: 2 },
// 光速跑路 0-leave 1-mug 2-hos 3-关闭
{ key: 'quickFinishAtt', val: 3 },
// 自动开打和结束
{ key: 'autoStartFinish', val: false },
// 废弃
{ key: 'attRelocate', val: true },
// 攻击自刷新 0-无间隔 1-5s 6-关闭
{ key: 'attReload', val: 6 },
// 价格监视
{ key: 'priceWatcher', val: { xan: -1, pt: -1 } },
// 开发者模式
{ key: 'isDev', val: false },
// 啤酒提醒时间
{ key: '_15AlarmTime', val: 50 },
// 4条转跳
{ key: 'barsRedirect', val: true },
// 浮动存钱框
{ key: 'floatDepo', val: true },
// 公司转跳存钱
{ key: 'companyRedirect', val: true },
// 收起公司冰蛙效率表
{ key: 'companyBWCollapse', val: true },
// 清除多余的脚本
{ key: 'removeScripts', val: true },
// 海外警告
{ key: 'abroadWarning', val: true },
// 落地转跳
{ key: 'landedRedirect', val: '' },
// 任何位置一键存钱
{ key: 'companyDepositAnywhere', val: false },
// 危险行为⚠️
{ key: 'dangerZone', val: false },
].forEach(df => {
if (typeof WuhuConfig.get(df.key) !== typeof df.val) {
WuhuConfig.set(df.key, df.val);
count++;
}
});
Log.info('设置默认值结束,新:' + count);
return this;
}
}
interface MenuItemConfig {
domType: 'button' | 'plain' | 'checkbox' | 'select';
tagName?: string;
domId?: string;
domText?: string;
clickFunc?: (ev?) => void;
domHTML?: string;
tip?: string;
dictName?: string;
changeEv?: (ev) => void;
domSelectOpt?: { domVal: string, domText: string }[];
/**
* 隐藏菜单已弃用
* @deprecated
*/
isHide?: boolean;
}
interface EventWrapper {
onEv: boolean;
daysLeft: number;
events: Event[];
current?: Event;
next?: Event;
html?: string;
}
interface Event {
start: number[];
end: number[];
name: string;
eff: string;
}