This commit is contained in:
Liwanyi 2022-11-03 16:34:58 +08:00
parent 0b6c2cda4f
commit f5e4a5cfe3
29 changed files with 1481 additions and 706 deletions

View File

@ -4,6 +4,18 @@
# CHANGE
## 0.6.7
2022年11月3日
### 修改
- 重做光速跑路(需要更多测试)
### 添加
- 战斗-盯梢模式
## 0.6.6
2022年10月31日

View File

@ -1,6 +1,6 @@
{
"name": "wuhu-torn-helper",
"version": "0.6.6",
"version": "0.6.7",
"description": "芜湖助手",
"dependencies": {},
"scripts": {

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,6 @@ import { Common } from "./Common";
import UrlPattern from "./UrlMatch";
import WuhuConfig from "./WuhuConfig";
import translateMain from "../func/translate/translateMain";
import Global from "./Global";
import CommonUtils from "./utils/CommonUtils";
export default class Application {
@ -22,30 +21,21 @@ export default class Application {
// 插件图标和设置菜单
ZhongIcon.getInstance();
// TODO 临时关闭光速跑路
WuhuConfig.set('quickFinishAtt', 3);
let tmp = () => {
// 所有页面通用
Common.getInstance().resolve();
// URL匹配
UrlPattern.getInstance().resolve();
// 翻译
if (WuhuConfig.get('transEnable')) translateMain(window.location.href);
};
// TODO 临时检测jquery
if (typeof $ === "function") {
// 所有页面通用
Common.getInstance().resolve();
// URL匹配
UrlPattern.getInstance().resolve();
// 翻译
if (WuhuConfig.get('transEnable')) translateMain(Global.getInstance().href);
tmp();
} else {
CommonUtils.getInstance().jQueryReady().then(() => {
// 所有页面通用
Common.getInstance().resolve();
// URL匹配
UrlPattern.getInstance().resolve();
// 翻译
if (WuhuConfig.get('transEnable')) translateMain(Global.getInstance().href);
});
CommonUtils.getInstance().jQueryReady().then(() => tmp());
}
}
}

View File

@ -1,11 +1,11 @@
import depoHelper from "../func/module/depoHelper";
import travelHelper from "../func/module/travelHelper";
import attackHelper from "../func/module/attackHelper";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import WuhuBase from "./WuhuBase";
import WuhuConfig from "./WuhuConfig";
import CommonUtils from "./utils/CommonUtils";
import CompanyHelper from "./action/CompanyHelper";
import AttackHelper from "./action/AttackHelper";
export class Common extends WuhuBase {
className = 'Common';
@ -79,7 +79,8 @@ export class Common extends WuhuBase {
travelHelper().then();
// 战斗相关
attackHelper().then();
// attackHelper().then();
AttackHelper.getInstance();
// 公司助手
CompanyHelper.getInstance();

View File

@ -40,8 +40,8 @@ export default class Global extends WuhuBase implements IGlobal {
bodyAttrs: {
'data-country'?: string;
'data-celebration'?: string;
'data-traveling'?: string;
'data-abroad'?: string;
'data-traveling'?: 'true' | 'false';
'data-abroad'?: 'true' | 'false';
} = null;
constructor() {

View File

@ -29,13 +29,11 @@ export default class Log {
}
public static debug(): boolean {
let ret: boolean;
let ret: boolean = true;
try {
let local = JSON.parse(localStorage.getItem('wh_trans_settings'));
if (local) ret = local['isDev'];
else ret = false;
} catch {
ret = false;
}
return ret;
}

View File

@ -11,14 +11,15 @@ export default class WuhuBase extends Provider {
* localStorage wh_trans_settings (json)
*/
public static getLocal(): IWHSettings {
let localObject = {};
let localObject;
let localItem = localStorage.getItem('wh_trans_settings') || '{}';
try {
localObject = JSON.parse(localStorage.getItem('wh_trans_settings'));
localObject = JSON.parse(localItem);
} catch (e) {
Log.error('解析localStorage对象出错', e);
localStorage.setItem('wh_trans_settings', '{}');
}
return localObject;
return localObject || {};
}
public static conditionInterrupt() {

View File

@ -11,8 +11,9 @@ export default class WuhuConfig extends WuhuBase {
*/
public static get(key: string | string[]) {
let localPool = this.getLocal();
if (typeof key === 'string') return localPool[key];
else {
if (typeof key === 'string') {
return localPool[key];
} else {
let ret: string[] = [];
key.forEach(k => {
ret.push(localPool[k])
@ -106,6 +107,8 @@ export default class WuhuConfig extends WuhuBase {
{ key: 'HideProfileImg', val: false },
// 显示曾用名
{ key: 'ShowNameHistory', val: true },
// 盯梢模式强度 0-550 1-950 2-1450 ms
{ key: 'WatchTargetFreq', val: 1 },
// 危险行为⚠️
{ key: 'dangerZone', val: false },

View File

@ -77,10 +77,10 @@ export default class ZhongIcon extends WuhuBase {
}
};
if (zhongNode.classList.contains('wh-icon-expanded')) {
Log.info('添加事件监听');
Log.info('芜湖助手图标点击->添加监听');
document.body.addEventListener('click', click_func);
} else {
Log.info('移除事件监听');
Log.info('芜湖助手图标->移除监听');
document.body.removeEventListener('click', click_func);
}
};

View File

@ -0,0 +1,328 @@
import WuhuBase from "../WuhuBase";
import WuhuConfig from "../WuhuConfig";
import CommonUtils from "../utils/CommonUtils";
import Log from "../Log";
import Alert from "../utils/Alert";
import Global from "../Global";
import Device from "../../enum/Device";
import ATTACK_HELPER_CSS from "../../static/css/attack_helper.css";
import ActionButtonUtils from "../utils/ActionButtonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import DialogMsgBox from "../utils/DialogMsgBox";
import FetchUtils from "../utils/FetchUtils";
import MathUtils from "../utils/MathUtils";
import LoopHelper from "../utils/LoopHelper";
import TRAVEL_STATE from "../../enum/TravelState";
enum FIGHT_STAGE {
READY = 'ready',
IN_PROGRESS_OR_ERROR = 'in_progress_or_error',
FINISHED = 'finished',
END = 'end',
OTHER = 'other'
}
/**
*
*/
export default class AttackHelper extends WuhuBase {
className = 'AttackHelper';
private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER;
constructor() {
super();
window.setTimeout(() => this.urlMatch(), 0);
}
private urlMatch(): void {
if (window.location.href.contains(/loader\.php\?sid=attack/)) {
this.fightingPageHandle();
}
// 错误的攻击页面转跳
else if (window.location.href.includes('loader2.php') && WuhuConfig.get('attRelocate')) {
const spl = window.location.href.trim().split('=');
const uid = spl[spl.length - 1];
if (CommonUtils.getInstance().isValidUid(uid)) {
window.location.href = 'https://www.torn.com/loader.php?sid=attack&user2ID=' + uid;
} else {
Log.error('[AttackHelper] UID格式不正确');
}
}
}
private fightingPageHandle(): void {
// 光速刷新按钮
ActionButtonUtils.getInstance().add('光速刷新', () => this.doAttackReload());
// 盯梢
this.watchTarget();
new MutationObserver((_, observer) => {
let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
if (btnList.length === 0) {
// 错误或正在打
this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
Log.info('[attackHelper] currentStage', this.currentStage);
return;
}
btnList.forEach(btn => {
if (btn.innerText.toLowerCase().includes('start')) {
// 开始
this.quickStartFight();
} else if (btn.innerText.toLowerCase().includes('continue')) {
// 结束end
this.currentStage = FIGHT_STAGE.END;
observer.disconnect();
} else if (btn.innerText.toLowerCase().includes('leave')) {
// 无意识状态FINISHED
this.quickFinishFight(btnList);
}
Log.info('[attackHelper] currentStage', this.currentStage);
})
})
.observe(document.querySelector('#react-root'), { childList: true, subtree: true });
}
// 战斗页面快速刷新
private doAttackReload(): void {
if (!window.ReactDOM) {
new Alert('光速刷新失败未找到React对象');
Log.error('光速刷新失败未找到React对象');
return;
}
if (!document.querySelector('#react-root').querySelector('#attacker')) return;
let script = document.querySelector('script[src*="/builds/attack/"]');
let url = script.src;
if (!url.contains('app.js')) return;
window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root'));
script.remove();
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.head.appendChild(node);
}
// 光速拔刀
private quickStartFight(): void {
if (this.currentStage === FIGHT_STAGE.READY) {
return;
} else {
this.currentStage = FIGHT_STAGE.READY;
}
if (WuhuConfig.get('quickAttIndex') === 6) return;
/**
* pc #defender
* mobile #attacker
*/
const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
Log.info('操作按钮', { btn });
if (!btn.innerText.toLowerCase().includes('fight')) {
Log.info('未找到攻击按钮, 光速拔刀跳过');
new Alert('未找到攻击按钮, 光速拔刀跳过');
} else {
// 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots');
// modal层
// const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
let device = Global.getInstance().device;
Log.info(`当前设备类型是${ device }`);
// 区分设备
switch (device) {
case Device.PC: {
Log.info(`开始调整按钮位置`);
// 隐藏modal层
// modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (WuhuConfig.get('quickAttIndex')) {
// weapon_second
case 1: {
css_top = '97px';
break;
}
// weapon_melee
case 2: {
css_top = '194px';
break;
}
// weapon_temp
case 3: {
css_top = '291px';
break;
}
// weapon_fists
case 4:
// weapon_boots
case 5: {
css_top = '375px';
break;
}
}
CommonUtils.addStyle(ATTACK_HELPER_CSS);
CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
document.body.classList.add('wh-move-btn');
break;
}
case Device.MOBILE: {
Log.info(`开始调整按钮位置`);
// 加入css
let css_top = '0';
let slot_height = '76px';
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (WuhuConfig.get('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') as HTMLElement;
const height = slot.offsetHeight + 1;
// TODO 待验证
slot_height = height + 'px';
// 根据选择的武器调整
switch (WuhuConfig.get('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 = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// `
// .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;}
// `;
CommonUtils.addStyle(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (WuhuConfig.get('quickFinishAtt') !== 3) {
btn.remove();
// 停止自动刷新
// stop_reload = true;
} else {
document.body.classList.toggle('wh-move-btn');
}
};
break;
}
case Device.TABLET: {
break;
}
}
}
}
// 光速跑路
private quickFinishFight(btnList: NodeListOf<HTMLButtonElement>): void {
if (this.currentStage === FIGHT_STAGE.FINISHED) {
return;
} else {
this.currentStage = FIGHT_STAGE.FINISHED;
}
if (WuhuConfig.get('quickFinishAtt') === 3) return;
const user_btn_select = ['leave', 'mug', 'hosp'][WuhuConfig.get('quickFinishAtt')];
// const wrap = document.querySelector('#react-root');
Log.info('光速跑路选项选中:', user_btn_select);
// const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btnList.length > 1) btnList.forEach(btn => {
const flag = btn.innerText.toLowerCase().includes(user_btn_select);
Log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
});
}
// 盯梢模式
private watchTarget(): void {
Log.info('获取目标id');
let targetId = window.location.href.split('user2ID=')[1];
if (!CommonUtils.getInstance().isValidUid(targetId)) {
Log.error('目标id获取错误', targetId);
throw new Error('目标id获取错误:' + targetId);
}
let loop = new LoopHelper(async () => {
let userProfile;
try {
userProfile = await FetchUtils.getInstance().getProfile(targetId);
} catch {
Log.error('盯梢模式无法获取目标id');
throw new Error('盯梢模式无法获取目标id');
}
await CommonUtils.getInstance().sleep(MathUtils.getInstance().getRandomInt(20, 50));
if ((userProfile.userStatus.status === 'ok' && CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.IN_TORN) ||
(userProfile.userStatus.status === 'abroad' && CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.ABROAD)) {
watchSwitch.getInput().checked = false;
window.setTimeout(async () => {
new Alert('目标已落地/出院/出狱!', { timeout: 10, force: true, sysNotify: true });
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
}, 0);
}
});
let block = new TornStyleBlock('盯梢模式').insert2Dom();
let watchSwitch = new TornStyleSwitch('开启');
block.append(watchSwitch.getBase());
watchSwitch.getInput().addEventListener('change', () => {
if (watchSwitch.getInput().checked) {
new DialogMsgBox('检测玩家状态,当目标状态变成(海外)落地、出院或出狱时通知并播放声音提醒,后可搭配光速刷新食用<br/>确定开启?', {
callback: () => {
if (CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.FLYING) {
new Alert('失败!已取消');
watchSwitch.getInput().checked = false;
return;
}
Log.info('盯梢开启, 目标id' + targetId);
loop.start(parseInt(WuhuConfig.get('WatchTargetFreq')));
},
cancel: () => watchSwitch.getInput().checked = false
});
} else {
loop.stop();
Log.info('盯梢关闭');
}
});
}
}

View File

@ -5,6 +5,7 @@ import MathUtils from "../utils/MathUtils";
import CommonUtils from "../utils/CommonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import Timer from "../utils/Timer";
import FetchUtils from "../utils/FetchUtils";
export default class LotteryHelper extends WuhuBase {
className = 'LotteryHelper';
@ -132,7 +133,7 @@ export default class LotteryHelper extends WuhuBase {
rsMsg = `终止操作,已完成${ i }/${ inputNumber }`;
break;
}
await CommonUtils.ajaxFetch({
await FetchUtils.getInstance().ajaxFetch({
url: window.addRFC('https://www.torn.com/loader.php?sid=lotteryPlay&step=buyTicket&lotteryID=' + lotteryType),
method: 'GET',
referrer: '/loader.php?sid=lottery',

View File

@ -4,6 +4,7 @@ import WuhuConfig from "../WuhuConfig";
import CommonUtils from "../utils/CommonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import FetchUtils from "../utils/FetchUtils";
export default class ProfileHelper extends WuhuBase {
className = 'ProfileHelper';
@ -13,7 +14,7 @@ export default class ProfileHelper extends WuhuBase {
CommonUtils.addStyle('body.wh-hide_profile_img .profile-image a.profile-image-wrapper .img-wrap img{display:none;}');
let id = document.querySelector('link[rel="canonical"]').getAttribute('href').split('=')[1];
// id获取格式判断
if (!/^[0-9]{1,7}$/.test(id)) {
if (!CommonUtils.getInstance().isValidUid(id)) {
Log.error('[ProfileHelper] id格式错误');
}
if (WuhuConfig.get('HideProfileImg')) {
@ -34,18 +35,13 @@ export default class ProfileHelper extends WuhuBase {
nameHistoryNode = document.createElement('p');
nameHistoryNode.innerHTML = '曾用名:';
block.append(nameHistoryNode);
CommonUtils.ajaxFetch({
url: window.addRFC('https://www.torn.com/profiles.php?step=getProfileData&XID=' + id),
method: 'GET'
}).then((o) => {
o.json().then((res) => {
FetchUtils.getInstance().getProfile(id).then((res) => {
if (res.userInformation.previousAliases.length > 0) {
res.userInformation.previousAliases.forEach(item => nameHistoryNode.innerHTML += item + ' ');
} else {
nameHistoryNode.innerHTML += '暂无';
}
}).catch(e => Log.error('[ProfileHelper] 错误: ', e.message, '错误堆栈: ', e.stack));
}).catch(e => Log.error('[ProfileHelper] 错误: ', e.message, '错误堆栈: ', e.stack));
});
}
}
}

View File

@ -1,11 +1,11 @@
import WuhuBase from "../WuhuBase";
import XUNZHAOMUZHUANG_HTML from "../../static/html/xunzhaomuzhuang/index.html";
import * as MUZHUANG_ID_LIST_JSON from "../../static/json/muzhuang_id_list.json";
import Log from "../Log";
import CommonUtils from "../utils/CommonUtils";
import XUNZHAOMUZHUANG_CSS from "../../static/css/xunzhaomuzhuang.css";
import TornStyleBlock from "../utils/TornStyleBlock";
import MathUtils from "../utils/MathUtils";
import FetchUtils from "../utils/FetchUtils";
/**
*
@ -61,12 +61,7 @@ export default class XZMZ extends WuhuBase {
}
private async SearchDeadman(id) {
CommonUtils.ajaxFetch({
url: window.addRFC('https://www.torn.com/profiles.php?step=getProfileData&XID=' + id),
method: 'GET'
}).then((o) => {
this.counterHandler();
o.json().then((res) => {
FetchUtils.getInstance().getProfile(id).then((res) => {
if (res.userStatus.status.type === 'ok') {
this.addRow({
player_id: res.user.userID,
@ -74,10 +69,7 @@ export default class XZMZ extends WuhuBase {
level: res.userInformation.level
});
}
}).catch(e => {
Log.error('[XZMZ] [CommonUtils.ajaxFetch]错误: ', e.message, '错误堆栈: ', e.stack);
});
})
await CommonUtils.getInstance().sleep(MathUtils.getInstance().getRandomInt(100, 200));
}

View File

@ -1,6 +1,7 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import Alert from "../utils/Alert";
import DialogMsgBox from "../utils/DialogMsgBox";
export default class AdditionalSettingsHandler extends WuhuBase {
className = 'AdditionalSettingsHandler';
@ -11,6 +12,8 @@ export default class AdditionalSettingsHandler extends WuhuBase {
pop.getElement().insertAdjacentHTML('beforeend', insertHtml);
let [btn1, btn2, btn3] = Array.from(pop.getElement().querySelectorAll('button'));
btn1.addEventListener('click', () => {
new DialogMsgBox('将清空所有芜湖助手相关设置并刷新页面,确定?', {
callback: () => {
localStorage.removeItem('wh_trv_alarm');
localStorage.removeItem('wh_trans_settings');
localStorage.removeItem('whuuid');
@ -18,6 +21,8 @@ export default class AdditionalSettingsHandler extends WuhuBase {
localStorage.removeItem('WHTEST');
new Alert('已清空,刷新页面');
window.location.reload();
}
});
});
btn2.addEventListener('click', () => {
});

View File

@ -6,7 +6,6 @@ import BuyBeerHelper from "../action/BuyBeerHelper";
import UpdateTranslateDict from "./UpdateTranslateDict";
import landedRedirect from "../../func/module/landedRedirect";
import Alert from "../utils/Alert";
import WuhuConfig from "../WuhuConfig";
import ViewLogsHandler from "./ViewLogsHandler";
import AdditionalSettingsHandler from "./AdditionalSettingsHandler";
import Popup from "../utils/Popup";
@ -26,16 +25,18 @@ export default class SettingsHandler extends WuhuBase {
let startTime = new Timer();
Log.info('构造设置开始');
let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置');
window.setTimeout(() => {
let tmp = document.createElement('div');
tmp.classList.add('gSetting');
this.list.forEach(set => CommonUtils.getInstance().elemGenerator(set, tmp));
// 本日不提醒
tmp.querySelector('#wh-qua-alarm-check-btn')
.addEventListener('click', () => BuyBeerHelper.getInstance().skip_today());
pop.getElement().innerHTML = '';
pop.getElement().appendChild(tmp);
// 本日不提醒
pop.getElement().querySelector('#wh-qua-alarm-check-btn')
.addEventListener('click', () => BuyBeerHelper.getInstance().skip_today());
(window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip'));
Log.info('构造设置结束 ' + startTime.getTimeMs());
}, 0)
}
// 设置
@ -95,11 +96,11 @@ export default class SettingsHandler extends WuhuBase {
clickFunc: () => UpdateTranslateDict.getInstance().handle()
});
// 战斗优化
// 战斗
list.push({
domType: 'plain',
domId: '',
domHTML: '战斗优化',
domHTML: '战斗',
tagName: 'h4',
});
// 光速拔刀
@ -138,7 +139,6 @@ export default class SettingsHandler extends WuhuBase {
},
],
dictName: 'quickAttIndex',
isHide: true,
tip: '将Start Fight按钮移动到指定格子上',
});
// 光速跑路
@ -165,8 +165,7 @@ export default class SettingsHandler extends WuhuBase {
},
],
dictName: 'quickFinishAtt',
isHide: true,
tip: '<del>将结束后指定按钮移动到上面指定的格子上</del>暂时关闭',
tip: '将结束后指定按钮移动到上面指定的格子上',
});
// 攻击链接转跳
list.push({
@ -174,63 +173,75 @@ export default class SettingsHandler extends WuhuBase {
domId: 'wh-attack-relocate',
domText: ' 真·攻击界面转跳',
dictName: 'attRelocate',
tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面',
isHide: true,
tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面失效Ched疑似已移除此转跳',
});
// 危险行为⚠️
if (WuhuConfig.get('dangerZone') === true) {
// 攻击界面自刷新
// 盯梢模式强度
list.push({
domType: 'select',
domId: 'wh-attack-reload',
domText: '⚠️攻击界面自动刷新 ',
dictName: 'attReload',
domId: '',
domText: '盯梢模式强度 ',
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: '关闭',
},
{ domVal: '550', domText: '强' },
{ domVal: '950', domText: '标准' },
{ domVal: '1450', domText: '弱' }
],
isHide: true,
tip: '危险功能:接机时常用,将自动刷新页面直到目标落地',
});
// 自动开打和结束
list.push({
domType: 'checkbox',
domId: 'wh-auto-start-finish',
domText: ' ⚠️自动开打和结束',
dictName: 'autoStartFinish',
tip: '脚本将会自动按下战斗和结束按钮',
isHide: true,
});
} else {
WuhuConfig.set('autoStartFinish', false)
WuhuConfig.set('attReload', 6)
}
dictName: 'WatchTargetFreq',
tip: '越强盯得越紧刷新越快越容易触发Torn大流量保护机制<br/>强 ~0.6s<br/>标准 ~1s<br/>弱 ~1.5s',
})
// 危险行为⚠️
// if (WuhuConfig.get('dangerZone') === true) {
// // 攻击界面自刷新
// list.push({
// domType: 'select',
// domId: 'wh-attack-reload',
// domText: '⚠️攻击界面自动刷新 ',
// dictName: 'attReload',
// domSelectOpt: [
// {
// domVal: 'none',
// domText: '无间隔',
// },
// {
// domVal: '1',
// domText: '约1s',
// },
// {
// domVal: '2',
// domText: '约2s',
// },
// {
// domVal: '3',
// domText: '约3s',
// },
// {
// domVal: '4',
// domText: '约4s',
// },
// {
// domVal: '5',
// domText: '约5s',
// },
// {
// domVal: 'disabled',
// domText: '关闭',
// },
// ],
// isHide: true,
// tip: '危险功能:接机时常用,将自动刷新页面直到目标落地',
// });
// // 自动开打和结束
// list.push({
// domType: 'checkbox',
// domId: 'wh-auto-start-finish',
// domText: ' ⚠️自动开打和结束',
// dictName: 'autoStartFinish',
// tip: '脚本将会自动按下战斗和结束按钮',
// isHide: true,
// });
// } else {
// WuhuConfig.set('autoStartFinish', false)
// WuhuConfig.set('attReload', 6)
// }
// 飞行
list.push({

View File

@ -1,19 +1,47 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import VIEW_LOGS_HANDLER_HTML from "../../static/html/view_logs_handler.html";
export default class ViewLogsHandler extends WuhuBase {
className = 'ViewLogsHandler';
public handle(): void {
let logCounter = Log.getCounter();
let pop = new Popup('<textarea readonly style="width:100%;height:340px;"></textarea>', '查看日志');
let text = pop.getElement().querySelector('textarea');
text.innerHTML = Log.getLogs();
text.onclick = () => text.select();
pop.getElement().insertAdjacentHTML(
'afterbegin',
`<p>${ logCounter.info }信息 ${ logCounter.warning }警告 ${ logCounter.error }错误</p>`
let pop = new Popup(VIEW_LOGS_HANDLER_HTML
.replace('{{}}', logCounter.info.toString())
.replace('{{}}', logCounter.warning.toString())
.replace('{{}}', logCounter.error.toString()), '查看日志');
window.setTimeout(() => {
let container = pop.getElement().querySelector('div');
let text = document.createElement('div');
let logs = Log.getLogs().split('\r\n');
logs.forEach(log => {
let p = document.createElement('p');
p.innerText = log;
if (log.includes('ERR')) {
p.style.backgroundColor = '#ff000080';
} else if (log.includes('WRN')) {
p.style.backgroundColor = '#ffff0080';
}
text.append(p);
});
pop.getElement().querySelector('button').addEventListener('click', () => window.setTimeout(() => {
CommonUtils.getInstance()
.exportTextFile(
'wuhu_log_' + Log.getTime()
.replace('[', '')
.replace(']', '')
.replace(' ', '')
.replace('.', '')
.replaceAll('-', '')
.replaceAll(':', '') + '.log',
[Log.getLogs()]
);
}, 0));
container.innerHTML = '';
container.append(text);
}, 0);
}
}

View File

@ -2,13 +2,13 @@ import UserScriptEngine from "../../enum/UserScriptEngine";
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Device from "../../enum/Device";
import AjaxFetchOption from "../../interface/AjaxFetchOption";
import LOADING_IMG_HTML from "../../static/html/loading_img.html";
import Timer from "./Timer";
import FetchUtils from "./FetchUtils";
import TornStyleSwitch from "./TornStyleSwitch";
import WuhuConfig from "../WuhuConfig";
import { MenuItemConfig } from "../ZhongIcon";
import TRAVEL_STATE from "../../enum/TravelState";
export default class CommonUtils extends WuhuBase {
className = 'CommonUtils';
@ -125,19 +125,19 @@ export default class CommonUtils extends WuhuBase {
}
}
public static ajaxFetch(opt: AjaxFetchOption) {
let { url, referrer = '/', method, body = null } = opt;
let req_params: RequestInit = {
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 window.fetch(url, req_params);
}
// public static ajaxFetch(opt: AjaxFetchOption) {
// let { url, referrer = '/', method, body = null } = opt;
// let req_params: RequestInit = {
// 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 window.fetch(url, req_params);
// }
/**
* mutation.observe
@ -221,7 +221,6 @@ export default class CommonUtils extends WuhuBase {
*/
public isNewDay(target: number | Date, offsetHours: number = 0): boolean {
let tar: Date = typeof target === "number" ? new Date(target) : target;
Log.info(tar.toLocaleString());
let today = new Date();
let utcNewDay = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()));
utcNewDay.setHours(utcNewDay.getHours() + offsetHours);
@ -321,4 +320,36 @@ export default class CommonUtils extends WuhuBase {
// 移动节点
return root_node.appendChild(new_node);
}
public exportTextFile(filename, content) {
const tmp = document.createElement('a');
tmp.href = URL.createObjectURL(new Blob(content, { type: 'text/plain', endings: 'transparent' }));
tmp.download = filename;
tmp.click();
tmp.remove();
URL.revokeObjectURL(tmp.href);
}
public isValidUid(id: string | number): boolean {
if (typeof id === 'string') {
return /^[0-9]{1,7}$/.test(id);
} else {
return /^[0-9]{1,7}$/.test(id.toString());
}
}
public getTravelStage(): TRAVEL_STATE {
let global = CommonUtils.glob;
if (global.bodyAttrs["data-abroad"] === 'false') {
return TRAVEL_STATE.IN_TORN;
}
// 海外落地abroad
else if (global.bodyAttrs["data-traveling"] === 'false') {
return TRAVEL_STATE.ABROAD;
}
// 飞行中traveling+abroad
else {
return TRAVEL_STATE.FLYING;
}
}
}

View File

@ -7,7 +7,7 @@ export default class DialogMsgBox {
constructor(msg: string, opt: DialogMsgBoxOptions) {
Log.info('创建DialogMsgBox', { msg, opt });
let { title = '提示', callback } = opt;
let { title = '提示', callback, cancel } = opt;
if (!callback) {
Log.error('无callback');
throw new Error('无callback');
@ -19,12 +19,13 @@ export default class DialogMsgBox {
this.container = document.createElement('div');
this.container.id = 'wh-dialog';
this.container.innerHTML = DIALOG_MSG_BOX_HTML.replace('{{}}', title).replace('{{}}', msg);
let [confirm, cancel] = Array.from(this.container.querySelectorAll('button'));
let [confirm, cancelBtn] = Array.from(this.container.querySelectorAll('button'));
confirm.addEventListener('click', () => {
callback(this.container);
this.destroy();
});
cancel.addEventListener('click', () => {
cancelBtn.addEventListener('click', () => {
cancel ? cancel() : null;
this.destroy();
});
document.body.append(this.container);
@ -50,4 +51,5 @@ export default class DialogMsgBox {
interface DialogMsgBoxOptions {
title?: string;
callback: Function;
cancel?: Function;
}

View File

@ -1,5 +1,7 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import AjaxFetchOption from "../../interface/AjaxFetchOption";
import IUserProfileData from "../../interface/IUserProfileData";
export default class FetchUtils extends WuhuBase {
className = 'FetchUtils';
@ -24,6 +26,20 @@ export default class FetchUtils extends WuhuBase {
});
}
public ajaxFetch(opt: AjaxFetchOption) {
let { url, referrer = '/', method, body = null } = opt;
let req_params: RequestInit = {
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 window.fetch(url, req_params);
}
public fetchText(url: string, init: RequestInit = null): Promise<string> {
return new Promise((resolve, reject) =>
window.fetch(url, init)
@ -35,4 +51,23 @@ export default class FetchUtils extends WuhuBase {
})
);
}
public getProfile(uid: string): Promise<IUserProfileData> {
return new Promise((resolve, reject) => {
this.ajaxFetch({
url: window.addRFC('https://www.torn.com/profiles.php?step=getProfileData&XID=' + uid),
method: 'GET'
}).then((o) => {
o.json().then((res) => {
resolve(res);
}).catch(e => {
Log.error('[ProfileHelper] JSON解析错误: ', e.message, '错误堆栈: ', e.stack);
reject(e);
});
}).catch(e => {
Log.error('[ProfileHelper] 网络错误: ', e.message, '错误堆栈: ', e.stack);
reject(e);
});
});
}
}

View File

@ -3,6 +3,7 @@ import Alert from "./Alert";
import ISidebarData from "../../interface/ISidebarData";
import Log from "../Log";
import CommonUtils from "./CommonUtils";
import FetchUtils from "./FetchUtils";
export default class InfoUtils extends WuhuBase {
className = 'InfoUtils';
@ -37,7 +38,7 @@ export default class InfoUtils extends WuhuBase {
ret = JSON.parse(sessionStorage.getItem(field));
} else {
Log.info('无法从sessionStorage获取数据')
ret = await (await CommonUtils.ajaxFetch({
ret = await (await FetchUtils.getInstance().ajaxFetch({
url: window.addRFC('/sidebarAjaxAction.php?q=getSidebarData'),
method: 'POST',
})).json();

View File

@ -0,0 +1,37 @@
import Log from "../Log";
import Timer from "./Timer";
export default class LoopHelper {
private intervalId: number = null;
private readonly handler: Function;
private timer: Timer;
constructor(callback: Function) {
this.handler = callback;
Log.info('[LoopHelper] 已创建, 方法: ', callback);
}
public start(loopGap: number = 1000): void {
Log.info('[LoopHelper] 已启动, 间隔' + loopGap);
this.timer = new Timer();
this.intervalId = window.setInterval(() => {
try {
this.handler();
} catch (e) {
Log.error(e.message, e.stack);
throw e;
}
}, loopGap);
}
public stop(): void {
// this.counter = 0;
Log.info('[LoopHelper] 已停止, 运行' + this.timer.getTimeMs());
window.clearInterval(this.intervalId);
this.intervalId = null;
}
public isRunning(): boolean {
return this.intervalId !== null;
}
}

7
src/enum/TravelState.ts Normal file
View File

@ -0,0 +1,7 @@
enum TRAVEL_STATE {
IN_TORN,
FLYING,
ABROAD
}
export default TRAVEL_STATE

View File

@ -1,306 +1,535 @@
import Device from "../../enum/Device";
import WuhuBase from "../../class/WuhuBase";
import WuhuConfig from "../../class/WuhuConfig";
import CommonUtils from "../../class/utils/CommonUtils";
import Log from "../../class/Log";
import Alert from "../../class/utils/Alert";
import MathUtils from "../../class/utils/MathUtils";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
import ATTACK_HELPER_CSS from "../../static/css/attack_helper.css";
enum FIGHT_STAGE {
READY,
IN_PROGRESS_OR_ERROR,
FINISHED
}
enum DIALOG_BUTTON {
START = 'start',
JOIN = 'join',
LEAVE = 'leave',
MUG = 'mug',
// TODO
HOST = 'hospitalize',
OTHER = 'other'
}
/**
* TODO class重构
*/
export default async function attackHelper(): Promise<null> {
let { href, device } = WuhuBase.glob;
// 攻击页面URL判断
if (href.contains(/loader\.php\?sid=attack/)) {
let stop_reload = false;
const quickAttIndex = WuhuConfig.get('quickAttIndex');
const quickFinishAtt = WuhuConfig.get('quickFinishAtt');
const attReload = WuhuConfig.get('attReload');
// 光速刷新按钮
ActionButtonUtils.getInstance().add('光速刷新', doAttackReload);
// 自刷新
let audio_played_flag;
// @ts-ignore TODO
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];
CommonUtils.elementReady(selector).then(elem => {
if (!elem.querySelector('button')) {
if (WuhuConfig.get('attReload') === 0 && stop_reload !== true) {
doAttackReload();
} else {
let reload_flag;
const timeout = WuhuConfig.get('attReload') * 1000 + MathUtils.getInstance().getRandomInt(-500, 500);
Log.info(`[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);
}
});
}
// await CommonUtils.querySelector('#react-root div[class^="players___"]'); // pc 可用
let playersModelWrap = await CommonUtils.querySelector('#react-root div[class^="playersModelWrap___"]');
let fightStage = document.querySelectorAll('div[class^="dialogButtons___"] button').length > 1;
Log.info('响应式内容已加载');
// 光速拔刀
if (quickAttIndex !== 6) {
/**
* pc #defender
* mobile #attacker
*/
const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
Log.info('操作按钮', { btn });
if (!btn.innerText.toLowerCase().includes('fight')) {
Log.info('未找到攻击按钮, 光速拔刀跳过');
new Alert('未找到攻击按钮, 光速拔刀跳过');
} else {
// 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots');
// modal层
// const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
Log.info(`当前设备类型是${ device }`);
// 区分设备
switch (device) {
case Device.PC: {
Log.info(`开始调整按钮位置`);
// 隐藏modal层
// modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (WuhuConfig.get('quickAttIndex')) {
// weapon_second
case 1: {
css_top = '97px';
break;
}
// weapon_melee
case 2: {
css_top = '194px';
break;
}
// weapon_temp
case 3: {
css_top = '291px';
break;
}
// weapon_fists
case 4:
// weapon_boots
case 5: {
css_top = '375px';
break;
}
}
CommonUtils.addStyle(ATTACK_HELPER_CSS);
CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
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.info(`开始调整按钮位置`);
// 加入css
let css_top = '0';
let slot_height = '76px';
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (WuhuConfig.get('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') as HTMLElement;
const height = slot.offsetHeight + 1;
// TODO 待验证
slot_height = height + 'px';
// 根据选择的武器调整
switch (WuhuConfig.get('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 = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// `
// .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;}
// `;
CommonUtils.addStyle(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (WuhuConfig.get('quickFinishAtt') !== 3) {
btn.remove();
// 停止自动刷新
stop_reload = true;
} else {
document.body.classList.toggle('wh-move-btn');
}
};
break;
}
case Device.TABLET: {
break;
}
}
// 自动开打
if (WuhuConfig.get('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();
}
}
}
}
// 光速跑路 TODO 暂时关闭
if (quickFinishAtt !== 3) {
const user_btn_select = ['leave', 'mug', 'hosp'][WuhuConfig.get('quickFinishAtt')];
const wrap = document.querySelector('#react-root');
Log.info('光速跑路选项选中:', user_btn_select);
new MutationObserver((mut, obs) => {
const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btn_arr.length > 1) btn_arr.forEach(btn => {
const flag = btn.innerText.toLowerCase().includes(user_btn_select);
Log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
// 自动结束
else if (WuhuConfig.get('autoStartFinish')) {
try {
btn.click();
} catch {
}
}
});
}).observe(wrap, { subtree: true, attributes: true, childList: true });
}
return;
}
// 错误的攻击页面
if (WuhuConfig.get('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;
}
}
// 战斗页面快速刷新
function doAttackReload() {
if (!window.ReactDOM) {
new Alert('光速刷新失败未找到React对象');
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;
window.ReactDOM.unmountComponentAtNode(react_root);
script.remove();
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.head.appendChild(node);
}
// import Device from "../../enum/Device";
// import WuhuBase from "../../class/WuhuBase";
// import WuhuConfig from "../../class/WuhuConfig";
// import CommonUtils from "../../class/utils/CommonUtils";
// import Log from "../../class/Log";
// import Alert from "../../class/utils/Alert";
// import MathUtils from "../../class/utils/MathUtils";
// import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
// import ATTACK_HELPER_CSS from "../../static/css/attack_helper.css";
// import Global from "../../class/Global";
// import TornStyleBlock from "../../class/utils/TornStyleBlock";
// import TornStyleSwitch from "../../class/utils/TornStyleSwitch";
// import DialogMsgBox from "../../class/utils/DialogMsgBox";
//
// enum FIGHT_STAGE {
// READY,
// IN_PROGRESS_OR_ERROR,
// FINISHED,
// END,
// OTHER
// }
//
// // enum DIALOG_BUTTON {
// // START = 'start',
// // JOIN = 'join',
// // LEAVE = 'leave',
// // MUG = 'mug',
// // HOSPITALIZE = 'hospitalize',
// // OTHER = 'other'
// // }
// let currentStage = FIGHT_STAGE.OTHER;
//
// /**
// * TODO class重构、各功能联动
// */
// export default async function attackHelper(): Promise<null> {
// let { href, device } = WuhuBase.glob;
// // 攻击页面URL判断
// if (href.contains(/loader\.php\?sid=attack/)) {
// let stop_reload = false;
// const attReload = WuhuConfig.get('attReload');
//
// // 光速刷新按钮
// ActionButtonUtils.getInstance().add('光速刷新', doAttackReload);
//
// // 自刷新
// let audio_played_flag;
// // @ts-ignore TODO
// 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];
// CommonUtils.elementReady(selector).then(elem => {
// if (!elem.querySelector('button')) {
// if (WuhuConfig.get('attReload') === 0 && stop_reload !== true) {
// doAttackReload();
// } else {
// let reload_flag;
// const timeout = WuhuConfig.get('attReload') * 1000 + MathUtils.getInstance().getRandomInt(-500, 500);
// Log.info(`[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);
// }
// });
// }
//
// // await CommonUtils.querySelector('#react-root div[class^="players___"]'); // pc 可用
// // await CommonUtils.querySelector('#react-root div[class^="playersModelWrap___"]');
// Log.info('响应式内容已加载');
// // 光速拔刀
// // if (quickAttIndex !== 6) {
// // /**
// // * pc #defender
// // * mobile #attacker
// // */
// // const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
// // Log.info('操作按钮', { btn });
// // if (!btn.innerText.toLowerCase().includes('fight')) {
// // Log.info('未找到攻击按钮, 光速拔刀跳过');
// // new Alert('未找到攻击按钮, 光速拔刀跳过');
// // } else {
// // // 判断是否存在脚踢
// // const hasKick = !!document.querySelector('#weapon_boots');
// // // modal层
// // // const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
// // Log.info(`当前设备类型是${ device }`);
// // // 区分设备
// // switch (device) {
// // case Device.PC: {
// // Log.info(`开始调整按钮位置`);
// // // 隐藏modal层
// // // modal.style.display = 'none';
// // // 根据选择的武器调整css
// // let css_top = '0';
// // switch (WuhuConfig.get('quickAttIndex')) {
// // // weapon_second
// // case 1: {
// // css_top = '97px';
// // break;
// // }
// // // weapon_melee
// // case 2: {
// // css_top = '194px';
// // break;
// // }
// // // weapon_temp
// // case 3: {
// // css_top = '291px';
// // break;
// // }
// // // weapon_fists
// // case 4:
// // // weapon_boots
// // case 5: {
// // css_top = '375px';
// // break;
// // }
// // }
// // CommonUtils.addStyle(ATTACK_HELPER_CSS);
// // CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
// // 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.info(`开始调整按钮位置`);
// // // 加入css
// // let css_top = '0';
// // let slot_height = '76px';
// // // 判断有没有脚踢
// // if (hasKick) {
// // // 根据选择的武器调整
// // switch (WuhuConfig.get('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') as HTMLElement;
// // const height = slot.offsetHeight + 1;
// // // TODO 待验证
// // slot_height = height + 'px';
// // // 根据选择的武器调整
// // switch (WuhuConfig.get('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 = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// // // `
// // // .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;}
// // // `;
// // CommonUtils.addStyle(css_rule);
// // document.body.classList.toggle('wh-move-btn');
// // btn.onclick = () => {
// // if (WuhuConfig.get('quickFinishAtt') !== 3) {
// // btn.remove();
// // // 停止自动刷新
// // stop_reload = true;
// // } else {
// // document.body.classList.toggle('wh-move-btn');
// // }
// // };
// // break;
// // }
// // case Device.TABLET: {
// // break;
// // }
// // }
// // // 自动开打
// // if (WuhuConfig.get('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();
// // }
// // }
// // }
// // }
//
// // 光速跑路 TODO 暂时关闭
// // if (quickFinishAtt !== 3) {
// // const user_btn_select = ['leave', 'mug', 'hosp'][WuhuConfig.get('quickFinishAtt')];
// // const wrap = document.querySelector('#react-root');
// // Log.info('光速跑路选项选中:', user_btn_select);
// // new MutationObserver((mut, obs) => {
// // const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
// // if (btn_arr.length > 1) btn_arr.forEach(btn => {
// // const flag = btn.innerText.toLowerCase().includes(user_btn_select);
// // Log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
// // if (!flag) btn.style.display = 'none';
// // // 自动结束
// // else if (WuhuConfig.get('autoStartFinish')) {
// // try {
// // btn.click();
// // } catch {
// // }
// // }
// // });
// // }).observe(wrap, { subtree: true, attributes: true, childList: true });
// // }
//
// new MutationObserver((_, mut) => {
// let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
// if (btnList.length === 0) {
// // 错误或正在打
// currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
// Log.info('[attackHelper] currentStage', currentStage);
// return;
// }
// btnList.forEach(btn => {
// if (btn.innerText.toLowerCase().includes('start')) {
// // 开始
// quickStartFight();
// } else if (btn.innerText.toLowerCase().includes('continue')) {
// // 结束end
// currentStage = FIGHT_STAGE.END;
// mut.disconnect();
// } else if (btn.innerText.toLowerCase().includes('leave')) {
// // 无意识状态FINISHED
// quickFinishFight(btnList);
// }
// Log.info('[attackHelper] currentStage', currentStage);
// })
// })
// .observe(document.querySelector('#react-root'), { childList: true, subtree: true });
//
// // 盯梢模式
// let block = new TornStyleBlock('盯梢模式').insert2Dom();
// let watchSwitch = new TornStyleSwitch('开启');
// block.append(watchSwitch.getBase());
// watchSwitch.getInput().addEventListener('change', () => {
// if (watchSwitch.getInput().checked) {
// new DialogMsgBox('开启效果:检测玩家状态,当状态变成落地或出院、出狱时将会启用【光速刷新】,并且播放声音提醒<br/>确定开启?', {
// callback: () => watchTarget(),
// cancel: () => watchSwitch.getInput().checked = false
// });
// } else {
// Log.info('guanbi');
// }
// });
//
// return;
// }
//
// // 错误的攻击页面
// if (WuhuConfig.get('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;
// }
// }
//
// // 战斗页面快速刷新
// function doAttackReload() {
// if (!window.ReactDOM) {
// new Alert('光速刷新失败未找到React对象');
// 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;
// window.ReactDOM.unmountComponentAtNode(react_root);
// script.remove();
// let node = document.createElement('script');
// node.src = url;
// node.type = 'text/javascript';
// document.head.appendChild(node);
// }
//
// // 光速拔刀
// function quickStartFight(): void {
// if (currentStage === FIGHT_STAGE.READY) {
// return;
// } else {
// currentStage = FIGHT_STAGE.READY;
// }
// if (WuhuConfig.get('quickAttIndex') === 6) return;
// /**
// * pc #defender
// * mobile #attacker
// */
// const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
// Log.info('操作按钮', { btn });
// if (!btn.innerText.toLowerCase().includes('fight')) {
// Log.info('未找到攻击按钮, 光速拔刀跳过');
// new Alert('未找到攻击按钮, 光速拔刀跳过');
// } else {
// // 判断是否存在脚踢
// const hasKick = !!document.querySelector('#weapon_boots');
// // modal层
// // const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
// let device = Global.getInstance().device;
// Log.info(`当前设备类型是${ device }`);
// // 区分设备
// switch (device) {
// case Device.PC: {
// Log.info(`开始调整按钮位置`);
// // 隐藏modal层
// // modal.style.display = 'none';
// // 根据选择的武器调整css
// let css_top = '0';
// switch (WuhuConfig.get('quickAttIndex')) {
// // weapon_second
// case 1: {
// css_top = '97px';
// break;
// }
// // weapon_melee
// case 2: {
// css_top = '194px';
// break;
// }
// // weapon_temp
// case 3: {
// css_top = '291px';
// break;
// }
// // weapon_fists
// case 4:
// // weapon_boots
// case 5: {
// css_top = '375px';
// break;
// }
// }
// CommonUtils.addStyle(ATTACK_HELPER_CSS);
// CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
// document.body.classList.add('wh-move-btn');
// break;
// }
// case Device.MOBILE: {
// Log.info(`开始调整按钮位置`);
// // 加入css
// let css_top = '0';
// let slot_height = '76px';
// // 判断有没有脚踢
// if (hasKick) {
// // 根据选择的武器调整
// switch (WuhuConfig.get('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') as HTMLElement;
// const height = slot.offsetHeight + 1;
// // TODO 待验证
// slot_height = height + 'px';
// // 根据选择的武器调整
// switch (WuhuConfig.get('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 = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// // `
// // .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;}
// // `;
// CommonUtils.addStyle(css_rule);
// document.body.classList.toggle('wh-move-btn');
// btn.onclick = () => {
// if (WuhuConfig.get('quickFinishAtt') !== 3) {
// btn.remove();
// // 停止自动刷新
// // stop_reload = true;
// } else {
// document.body.classList.toggle('wh-move-btn');
// }
// };
// break;
// }
// case Device.TABLET: {
// break;
// }
// }
// }
// }
//
// // 光速跑路
// function quickFinishFight(btnList: NodeListOf<HTMLButtonElement>): void {
// if (currentStage === FIGHT_STAGE.FINISHED) {
// return;
// } else {
// currentStage = FIGHT_STAGE.FINISHED;
// }
// if (WuhuConfig.get('quickFinishAtt') === 3) return;
// const user_btn_select = ['leave', 'mug', 'hosp'][WuhuConfig.get('quickFinishAtt')];
// // const wrap = document.querySelector('#react-root');
// Log.info('光速跑路选项选中:', user_btn_select);
// // new MutationObserver((mut, obs) => {
// // const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
// if (btnList.length > 1) btnList.forEach(btn => {
// const flag = btn.innerText.toLowerCase().includes(user_btn_select);
// Log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
// if (!flag) btn.style.display = 'none';
// // 自动结束
// // else if (WuhuConfig.get('autoStartFinish')) {
// // try {
// // btn.click();
// // } catch {
// // }
// // }
// });
// // }).observe(wrap, { subtree: true, attributes: true, childList: true });
// }
//
// function watchTarget(): void {
// Log.info('获取目标id');
// let targetId = window.location.href.split('user2ID=')[1];
// if (!CommonUtils.getInstance().isValidUid(targetId)) {
// Log.error('目标id获取错误', targetId);
// throw new Error('目标id获取错误:' + targetId);
// }
// }

View File

@ -89,7 +89,11 @@ export default function depoHelper() {
let getTraceMoney = async () => {
if (typeof addRFC === 'function') {
let url = addRFC('/trade.php?step=getFullMoney&ID=' + traceId);
return (await CommonUtils.ajaxFetch({ url: url, method: 'GET', referrer: 'trade.php' })).text();
return (await FetchUtils.getInstance().ajaxFetch({
url: url,
method: 'GET',
referrer: 'trade.php'
})).text();
}
};
// 监听jquery ajax请求
@ -148,7 +152,7 @@ export default function depoHelper() {
new Alert('无法定额取钱,原因:数不对');
return;
}
await CommonUtils.ajaxFetch({
await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',
@ -160,7 +164,7 @@ export default function depoHelper() {
buttonDepositAll.addEventListener('click', async () => {
let money = await getTraceMoney();
if (money === '0') return;
await CommonUtils.ajaxFetch({
await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',
@ -170,7 +174,7 @@ export default function depoHelper() {
});
// 全取
buttonWithdrawAll.addEventListener('click', async () => {
await CommonUtils.ajaxFetch({
await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',

View File

@ -10,14 +10,15 @@ import TRAVEL_ALARM_CSS from "../../static/css/travel_alarm.css";
import TRAVEL_ALARM_HTML from "../../static/html/travel_alarm.html";
import TornStyleBlock from "../../class/utils/TornStyleBlock";
import QuickFlyBtnHandler from "../../class/handler/QuickFlyBtnHandler";
import TRAVEL_STATE from "../../enum/TravelState";
export default async function travelHelper(): Promise<null> {
export default async function travelHelper(): Promise<void> {
let { href, bodyAttrs, device } = WuhuBase.glob;
// URL判断 + 人不在城内
if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'true') {
if (href.includes('index.php')) {
switch (CommonUtils.getInstance().getTravelStage()) {
// 飞行中
if (bodyAttrs["data-traveling"] === 'true') {
case TRAVEL_STATE.FLYING: {
// 飞行闹钟
if (device === Device.PC && WuhuConfig.get('trvAlarm')) {
// 获取目的地
@ -27,9 +28,17 @@ export default async function travelHelper(): Promise<null> {
dest_cn = '回城';
} else {
dest_cn = {
'uk': "英国", 'switzerland': "瑞士", 'mexico': '墨西哥', 'canada': '加拿大', 'cayman': '开曼',
'hawaii': '夏威夷', 'argentina': '阿根廷',
'japan': '日本', 'china': '中国', 'uae': 'UAE', 'south-africa': '南非',
'uk': "英国",
'switzerland': "瑞士",
'mexico': '墨西哥',
'canada': '加拿大',
'cayman': '开曼',
'hawaii': '夏威夷',
'argentina': '阿根廷',
'japan': '日本',
'china': '中国',
'uae': 'UAE',
'south-africa': '南非',
}[country] || country;
}
@ -189,9 +198,10 @@ export default async function travelHelper(): Promise<null> {
sessionStorage['wh-landed-redirect'] = JSON.stringify(obj);
});
}
break;
}
// 不在飞行中 海外落地页面
else {
// 海外落地
case TRAVEL_STATE.ABROAD: {
// 一键回城
ActionButtonUtils.getInstance().add('直接回城', travelBack);
// 海外警告
@ -207,24 +217,11 @@ export default async function travelHelper(): Promise<null> {
let block = new TornStyleBlock('解毒提醒');
block.setContent('<p><a href="/index.php?page=rehab">❤️ 点击前往解毒</a></p>');
document.querySelector('h4#skip-to-content').before(block.getBase());
// let page_title = document.querySelector('h4#skip-to-content');
// let msg = document.createElement('div');
// msg.innerHTML = `<div class="info-msg border-round">
// <i class="info-icon"></i>
// <div class="delimiter">
// <div class="msg right-round" tabindex="0" role="alert">
// <p><a href="/index.php?page=rehab">❤️ 点击前往解毒</a></p>
// </div>
// </div>
// </div>`;
// msg.classList.add('info-msg-cont', 'green', 'border-round', 'm-bottom10');
// page_title.before(msg);
}
break;
}
return;
}
// URL判断 + 人在城内
else if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'false') {
// 主页界面
case TRAVEL_STATE.IN_TORN: {
// 落地转跳
if (sessionStorage['wh-landed-redirect']) {
let { url, timestamp } = JSON.parse(sessionStorage['wh-landed-redirect']);
@ -233,18 +230,21 @@ export default async function travelHelper(): Promise<null> {
location.href = url;
}
}
break;
}
}
}
// 起飞页面
if (href.contains(/travelagency\.php/)) {
// 起飞提醒
else if (href.contains(/travelagency\.php/)) {
// 起飞提醒 TODO 去除jquery mutation
if (WuhuConfig.get('energyAlert')) {
const $$ = $('.content-wrapper');
const contentWrapper = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
contentTitleLinksTrans();
trans();
OB.observe($$.get(0), {
OB.observe(contentWrapper, {
characterData: true,
attributes: true,
subtree: true,
@ -277,7 +277,7 @@ export default async function travelHelper(): Promise<null> {
});
};
trans();
OB.observe($$.get(0), {
OB.observe(contentWrapper, {
characterData: true,
attributes: true,
subtree: true,

View File

@ -0,0 +1,46 @@
export default interface IUserProfileData {
user: {
playerName: string,
userID: number,
displayPersonalDetails: boolean,
isFriend: boolean,
isEnemy: boolean,
signUp: number,
role: string,
sendMoneyWarning: string
};
currentUser: {
"playerName": string,
"userID": number,
"money": number,
"canSendAnonymously": boolean,
"loggedIn": boolean
};
userInformation: {
"name": string,
"previousAliases": string[],
"level": number,
"rank": {
"userTitle": string,
"userRank": string
},
"age": number,
"honorTitle": string,
"image": unknown
};
profileButtons: unknown;
userStatus: {
"status": {
"type": "ok" | "traveling-from" | "abroad-hospital" | "abroad"
},
"trait": {
"loot": unknown
}
};
medalInformation: unknown;
basicInformation: unknown;
personalInformation: unknown;
competitionStatus: unknown;
staffTools: null;
profileSignature: null;
}

View File

@ -0,0 +1,16 @@
<style>
#WHLogsCont {
width: 100%;
height: 340px;
}
#WHLogsCont p {
overflow-x: auto;
white-space: nowrap;
word-break: keep-all;
}
</style>
<p>{{}}信息 {{}}警告 {{}}错误
<button class="torn-btn">导出日志</button>
</p>
<div id="WHLogsCont">加载中</div>

View File

@ -1,18 +1,19 @@
import WuhuBase from "../class/WuhuBase";
import Log from "../class/Log";
import DialogMsgBox from "../class/utils/DialogMsgBox";
import CommonUtils from "../class/utils/CommonUtils";
import TornStyleBlock from "../class/utils/TornStyleBlock";
import Popup from "../class/utils/Popup";
export default class Test extends WuhuBase {
className = 'Test';
public test(): void {
// let popup = new Popup('');
// popup.getElement()['__POOL__'] = Test.getPool();
let popup = new Popup(CommonUtils.getInstance().getTravelStage().toString());
popup.getElement()['__POOL__'] = Test.getPool();
// this.case1()
// this.case2()
this.case3().then();
// window.fetch('/test').then(res=>res.text()).then(o=>Log.info(o))
}
private case1() {
@ -50,6 +51,6 @@ export default class Test extends WuhuBase {
}
private async case3() {
new DialogMsgBox('123', { callback: () => alert(1) })
new TornStyleBlock('1').insert2Dom();
}
}