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 `
`;
}
// 抢啤酒
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 = `点击开打:
`;
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 = `
NNB(Natural Nerve Bar)意思是:扣除所有加成后,玩家本身的犯罪条上限,可用于衡量大佬隐藏的犯罪技能等级
一般来说,左侧红色的犯罪条(Nerve Bar/NB)的上限都是包含加成的,如来自帮派、天赋的加成等。额外的加成不会影响玩家的犯罪技能
查看NNB的方法很简单,在Torn主页面的最下方有一栏Perks,NB-Perks=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 = `
`;
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 = `
水晶球解密地图攻略
来源:Torn City公众号,图文详情请查看公众号文章
`;
const wt_dict = {
"None": {title: '', wt: ``,},
"Christmas Town": {
title: '圣诞小镇', wt: `
- 旧攻略提到的驯鹿车已被移除,只能手动找一条蓝色的小路[94,3]
- 向南走,然后上木桥,沿着它向西走到达冰湖
- 在冰湖[55,7][61,64]附近找Labyrinth传送门进入迷宫
- 迷宫的出口在中间的方向[395,397]一个冰湖,走进冰湖传送
- 走到企鹅
`,
},
"Maltese Snow Globe": {
title: 'Maltese Snow Globe', wt: `
- 1.想办法进入前几层的楼梯口
- 2.出来之后往南走, 在码头找到天鹅船
- 3.按着数字1-12走过乐高博物馆
- 4.跟着大路走到天鹅船。
- 5.走到901,486的银行
- 6.最左上的楼梯
- 7.B-D-C-E-F-G-C-A
- 8.右,右,右,北,北,右,右
- 9.走到右上角铁路
- 10.小游戏:
- 移动1到最右,移动2到中间,移动1到2上面,移动3到最右,移动1到最左,移动2到3.上面,移动1到2上面。
- 11.往上走出铁丝网,往左绕一个大圈走到300,476
- 12.走到363,406的隧道,走到361,400的隧道 ,往南走。
- 13.走到352,334的迷宫,好像有好几条路,我说我的走法,往左下走,走倒最下了往右走,走到1个不一样的绿色的时候,往上走。
- 14.走到迷宫中间的小人,后面就只有一条路走了,完成。
`,
},
"Long way from home": {
title: 'Long way from home', wt: `
- 1.随便动一下
- 2.左边的管道口
- 3.右走到十字路口,往上,往右,从偏左的那个管道往上。
- 3.出小门,往右到底,往上到底,往右,进上面房间,右上角的电脑,电脑显示的是下面房间的走法,任意移动退出
- 4.去下面房间,右边橙色电力符号,进入解密。下,右下,右下,右上,右上,右,右下,右下,下,左下,左下,
- 左,左,左下,左下,进圈。
- 5.进入新的房间按钮
- 6.一直左走,走到有两个怪兽把手的桥那,进上面的房间,左上角的机器,*是重输密码
- 作者随时改密码,建议看纸条上的提示自己去数
- 7.桥上怪兽消失, 往左走到底,按钮
- 8.右走,走到雪地走大路,按钮开铁门,上darkforest的蓝车
- 9.右走十几步,传送
- 10.右下走,看到铁丝网,顺着铁丝网右走,有个缺口,进去。
- 11.右走,直到看见三颗倒下的圣诞树(记住这里),顺着血迹和脚印走,进山洞。
- 12.顺着山洞走到一滩血,原路出山洞。
- 13.原路回到三颗倒下的圣诞树,正上方有个红色仓库,进入。
- 14.上,上,上,右,上,左,上,路就通了,去拿到右上角的锯子,原路出仓库。
- 15.出来就在车下面,上车,再上车。
- 16.左边的小橘人,完成
`,
},
"Chedburn Towers": {
title: 'Chedburn Towers', wt: `
- 进入地图后,使用附近的FAST的T下方的厕所传送到Chedburn Towers
- 进入大厅,"之"字形上楼,每层都是如此。
- 最终会进入问答题区域,通过在相应的数字上穿过来回答问题
- 答案是:3 9 5 4 9 2 6 8
- 答题后,进入Ched的办公室,向西走,然后一直走到左边的楼梯上
- 向南走下楼梯,然后向东走,沿着小楼梯到地下室
- 向东走到牢房区域
- 先踩下开关,打开牢房门前往右上角的最后一个牢房
- 开关位于JAIL文字的左上方
- 沿着挖出来的隧道一直走,岔路口向左走
- 到金库,Chedburn NPC会给你本地图的水晶球
`,
},
"Kidnapped Santa": {
title: 'Kidnapped Santa', wt: `
- 出生在一个类似城镇的地方
- 沿着这条路向东走,然后向南走
- 到达道路尽头的一个码头时,向西走一段路,踩在精灵的上面,乘坐渡船[124, -30]
- 搭船来到了Fantasy Island
- 小心那个游荡的绿色NPC,不惜一切代价避开他,否则他会把你打回出发点
- 向西走,然后向北走,再向西绕过岩石。要非常小心,不要踩到水里或掉下悬崖,否则你会死
- 然后回到南边,在那里你会看到一些门
- 走进蓝色的门(左二)[111,-60]
- 过了蓝门后继续沿路向南
- 然后沿路向东,再向南
- 再向东走,会看到“恐怖之家”,进入这栋楼[137, -84]
- 向北走,进入洞口[164, -81]
- 穿过隧道到达另一端的洞穴口[142, -63],避开所有怪物和NPC
- 来到另一个岛上
- 向南走,然后向东绕过建筑物,可以进入圣诞老人的洞穴[133, -2]
- 在建筑物内向西走,再向北走,在圣诞老人家work shop的东北角,你会看到一个楼梯,走下去[169,4]
- 在这一区域,要避开所有出现破损或有异样的地砖,也要避开四处游荡的邪恶的格林奇NPC
- 沿着地牢里的走廊向东走,然后向南走,避开所有看起来不同的瓷砖
- 它们上面有一些小裂缝和花纹,如果你是用手机的话,我建议你把亮度调高,以防万一
- 最终会看到一个发绿光的小开关
- 走到开关上[165, 18],激活它,然后进入向北打开的大门
- 走到黄色精灵NPC脸上[166,25],可以得到本地图的水晶球
`,
},
"Holiday terror": {
title: 'Holiday terror', wt: `
- 1. 从出生地沿着路向东,然后向北。过桥并沿着穿过城镇的小路继续前行,避开任何明显的陷阱(道路上的洞、打开的井盖等)。
- 2. 继续向东和向北前进,直到到达 Mansion's Labyrinth(豪宅迷宫)[121,29]
- 3. 豪宅入口在[131,41]
- 4. 进入豪宅后向北走,你会看到一条由骷髅守卫的道路
- 5. 沿着棕色的小路走,在黑色的区域前停下
- 6. 按照如下的方式行进
- 上3格,左2,上2,右4,下1,右3,上6,左2,下1,左6,下2,左2,上4,右5,上4
- 7. 来到一个区域,在这里你必须在两个洞穴中做出选择
- 第一次选择,答案是Christmas Miracle,选择左边的洞窟。
- 第二次选择,答案是24/12/2019,选择左边的洞窟。
- 第三次选择,答案是Hohoho Coldington,选择右边的洞窟。
- 第四次选择,答案是Christmas Miracle Cave,选择左边的洞窟。
- 8. 出现在一个用糖果棒装饰的红色地板的房间里,去地图的右上角一个冰洞的入口[101,-74]
- 9. 进入冰洞。向西走,寻找叫Erik the last elf的黄色小NPC
- 10. 拿到水晶球
`,
},
"Among Us": {
title: 'Among Us', wt: `
- 出生点步行到传送点进入地图 1 [399,12]
- 到达地图1,你出现在食堂,往下走,绕到红色按钮处[502,-1]
- 答案:D B A A D D B B B C A D D D 最终: B (Green)
- 然后你会被传送到地图2
- 在地图2中,你需要沿着小路向南走,然后向东进入通风口,前往下一个部分[556,24]
- 穿过通风口后,进入食堂。向南走到红色按钮所在的位置 [571,32]
- 答题阶段,答案如下BBACBDC A
- 被传送到地图3
- 先直接向南走一点,再沿着走廊走。进入左边的一个通风口[345,170]
- 会传送到办公室,在那里找到最后一个红色按钮[356,173]
- 答题阶段,答案如下CCADABBCD
- 进入"PEEP SHOW",获得本地图的水晶球
`,
},
"Kiss My Festivus": {
title: 'Kiss My Festivus', wt: `
- 从起点出发,沿着小路向北走到出租车处,乘坐前往Dark Forest的出租车 [96,16]
- 沿着公路向东走,继续向东进入雪地
- 沿着暗淡的蓝色轨迹向东南方向走,穿过树林,直到你到达一个铁栅栏[坐标为114,-89]
- 铁栅栏进不去。有人会告诉你乘坐他们的雪地车。
- 向西走到雪地车旁,注意不要踩到任何冬青树(鲜艳黄红色的矮树),否则你将回到起点。
- 被传送到锯木厂,在伐木工那里获得钥匙。
- 然后向南走,然后向东走(向东走很长一段路),沿着小路返回铁栅栏处。
- 来到一个炫酷的45°视角迷宫,你要走到地图的东北部,抵达另一个洞穴口[156,-74]
- 先往左下方走到岔路口,然后往右上方走,接下来将只有一条路
- 到达岛屿沿着小楼梯上去,绕到正下方那艘天鹅船
- 到一个新的岛屿,向南走几步,踩在[12, -79]的蓝色火花上
- 被传送到另一个有几辆拖车的岛上
- 向北走,进入一个新的山洞口
- 人被挡住了,要在冰层下向西北方向一直走,主要是向上和向左走
- 沿着这条路一直往上走,然后在开阔的地方往东走,你会看到一座房子[房子的入口在26,58]
- 进入房子,向北走几步,穿过闪闪发光的入口,你就可以进入房子了
- 沿着东南方向走,你会看到Evil-Duck NPC,他将给你本地图的水晶球
`,
},
"Stanley Hotel": {
title: 'Stanley Hotel', wt: `
- 从起点开始,你会看到正北方有一座房子。向北走几步到门前,进入房子。
- 传送到一个有门的地方。绕过并向上走,激活位于[188,72]的大门开关。
- 向东北方向前进,沿着血迹穿过森林,直到你到达一个山洞。
- 依次使用使用防御(踩盾牌标记),然后攻击(剑),然后魔法(闪亮的蓝色气泡)来杀死怪物。
- 最后,你会来到工人Bob的房间,他将给你本地图的水晶球。
`,
},
"DoggoQuest": {
title: 'DoggoQuest', wt: `
- 你出现在一个房间里
- 向东走,然后向南走,沿着小走廊就可以离开这个房间
- 来到这个地牢的01层
- 首先向南走,然后绕过墙,攻击你看到的第一个怪物[101,1]
- 然后向西走到墙边,向北攻击史莱姆
- 继续向北,攻击下一个怪物
- 向北走到拐角处,然后向东走到楼梯处继续前进[坐标为101,1]
- 来到第二层,直接向东走上楼梯[11,-19]
- 来到了这个地牢的第03层
- 向东再向南走到墙边,然后向东走,与绿色史莱姆战斗
- 继续向东走,经过被打败的史莱姆,然后向南和向西绕过墙,向北走一格,向西打败另一个史莱姆
- 向西南方向走下楼梯[53,-49]
- 来到了第 04 层
- 走到墙边,撞右边两个镣铐之间的墙,然后向北直接走到墙里[15,-65]
- 直接向北走,踏上红色的东西
- 沿着楼梯向南和东南方向走右边楼梯[39,-69]
- 来到第5层
- 向北走,然后向西绕过中间的十字架,向南走到下一个楼梯[29,-93]
- 来到第 6 层
- 杀死那只大绿狗
- 回到刚才的楼梯,来到05层[33,-114]
- 在第05层,你会看到原来的十字架位置附近出现了新的楼梯口
- 走上该楼梯[54, -99]
- 到达了最后的?层
- 沿着小路向下走,然后沿着冰冷的台阶走到Rudolph NPC
- 在他身边来回走动
- 踩在他身上的次数足够多时,Rudolph会把该图的水晶球交给你
`,
},
"Pokemon CT": {
title: 'Pokemon CT', wt: `
- 宝可梦新增了战斗系统,路过高草丛会几率进入战斗
- 战斗系统为一个十字形界面,上:技能/精灵球捕捉,下:逃跑,左:回血,右:攻击
- 战斗守则:攻击,当你血量为33时回血
- 打败最终BOSS需要捕捉两只,捕捉地点:
- 一:把包裹交给大木博士后,去常磐市的路上
- 二:进入森林后遇到的毛毛虫
- 捕捉时需要将其打到残血。
- 最终BOSS打法:
- 第一个敌方精灵,毛虫进化的蝴蝶,先放技能,使其眩晕,在眩晕期间攻击,一旦醒过来就眩晕,重复。
- 第一个BOSS死后,第二个BOSS会秒杀蝴蝶, 此时用第二个精灵。
- 第二个精灵打法:攻击,看见它放absorbing技能就去回血(当然你没血了也要去回血),重复。
- 【游戏开始】
- 出生在你房间的二楼
- 下楼梯离开房间。走出家门。从那里向东北方向进入高草丛,将被传送到大木博士(Professor Oak)的实验室
- 踩大木博士
- 踏上桌子,选择你的宝可梦
- 现在出门去常磐市(Veridian City)拿一个包裹
- 离开大木博士的实验室,向北走,穿过草地,前往常磐市(Veridian City)
- 进入城市后,前往 Poke Mart [134,-3]
- 回到大木博士的实验室,返回时可以跳下小路西侧的山崖,避开高草丛
- 把包裹交给大木博士后。回常磐市
- 在房子和两个精灵之间的小路上继续向北走,穿过城市[79,-21]
- 过了精灵后一路向北
- 进入一所房子,经过它才能进入常磐森林
- 穿过常磐森林才能到达尼比市
- 森林的入口向东走,直到看到高草,然后向北走,直到下一片高草
- 绕过树木向东走,然后向北走
- 现在绕过树木向西走,然后向北走
- 然后穿过草地向西和向南走
- 沿着这条小路蜿蜒穿过高高的草丛
- 沿着小路穿过草地,最终离开森林
- 离开森林后,沿着草丛旁小路向北走,到达 Pewter City。向北向西绕到大房子处,到达道馆
- 走到大胡桃夹子前,挑战小刚
- 赢得这场战斗后你会被带到大木博士那里,他会给本地图的水晶球
`,
},
"Winter in Gatlin": {
title: 'Winter in Gatlin', wt: `
- 从出生点出发
- 往右走到达树林,往右上走跨过铁栅栏,再往右走,经过红车时从右边缝隙穿过往下走
- 沿公路向下走到第一个岔路向右走到废弃的小屋[14,80]
- 进入小屋时,你会在一个黑色的小房间里,走到亮起的圆圈处
- 在下一个房间里,会有一连串的数字,按以下顺序走到数字上
- 1,4,6,8,7,6,4
- 在最后一个房间,Epic_Heasley NPC 会给你本图的水晶球
`,
},
};
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 = `
`;
// 原页面完全加载
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(``);
$('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 = `电脑
通常电脑浏览器装有油猴等用户脚本扩展时可以使用链接安装(自动更新):点此安装。
这些扩展长这样:

手机
安卓 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 += `| ${1 + (date.slice(0, 2) | 0)}月${date.slice(2)}日 | ${menu_list.fest_date_dict[date].name} | ${menu_list.fest_date_dict[date].eff} |
`);
popupMsg(html += '
', '节日');
})
: 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 += `| ${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} |
`);
popupMsg(html += '
更多信息请关注群聊和公众号
', '活动');
})
: 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 = ``;
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 = `
`;
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
* You gained 1,854.05 speed
*/
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 = `
`;
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 += `| ${el.show} | ${update / 60 | 0}分${update % 60 | 0}秒前 | `;
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 += '
';
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;