From 371cc45fce9464704c9752e38277495baf2bd44e Mon Sep 17 00:00:00 2001 From: dodying <549779963@qq.com> Date: Sun, 13 Jul 2025 09:28:07 +0800 Subject: [PATCH 1/2] 3.5.514 --- novel/novelDownloader/novelDownloader3.user.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/novel/novelDownloader/novelDownloader3.user.js b/novel/novelDownloader/novelDownloader3.user.js index d8ffbc7c..b6fe5898 100644 --- a/novel/novelDownloader/novelDownloader3.user.js +++ b/novel/novelDownloader/novelDownloader3.user.js @@ -2,9 +2,9 @@ // ==UserScript== // @name novelDownloader3 // @description 菜单```Download Novel```或**双击页面最左侧**来显示面板 -// @version 3.5.510 +// @version 3.5.514 // @created 2020-03-16 16:59:04 -// @modified 2025-07-11 21:26:37 +// @modified 2025-07-13 09:24:07 // @author dodying // @namespace https://github.com/dodying/UserJs // @supportURL https://github.com/dodying/UserJs/issues @@ -3148,7 +3148,7 @@ '
', ' 书籍作者: ', '
', - ' 书籍简介: ', + ' 书籍简介: ', '
', ' 书籍封面: ', '', @@ -3731,7 +3731,9 @@ container.find('[name="config"]').find('button[name="toggle"]').on('click', (e) => { container.find('.useless[name="config"]').toggle(); }); - container.find('[name="info"]>input[type="text"]').on('change', (e) => (Storage.book[$(e.target).attr('name')] = e.target.value)); + container.find('[name="info"]>input[type="text"],[name="info"]>textarea').on('change', (e) => { + Storage.book[$(e.target).attr('name')] = e.target.value; + }); container.find('[name="how"]').on('click', (e) => { const a = window.open('about:blank', '_blank'); a.document.write(``); From adef81d0014b559e253a5259e65c0a4b87158635 Mon Sep 17 00:00:00 2001 From: Qiyue Date: Mon, 18 Aug 2025 13:08:37 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E5=9C=A8=E5=90=8C=E6=97=B6=E6=BB=A1=E8=B6=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E6=8A=80=E8=83=BD=E6=9D=A1=E4=BB=B6=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E4=BC=9A=E9=87=8A=E6=94=BE=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E9=A1=BA=E4=BD=8D=E6=8A=80=E8=83=BD=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20=20=20=20=20=20=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E4=B8=AD=EF=BC=8C=E5=AF=B9=E4=BA=8E=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E5=8F=AF=E9=87=8A=E6=94=BE=E5=88=A4=E6=96=AD=E7=9B=B8?= =?UTF-8?q?=E5=8F=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6198 +++++++---------- 1 file changed, 2509 insertions(+), 3689 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 4320d152..32d29fc5 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,16 +6,14 @@ // @description HV auto attack script, for the first user, should configure before use it. // @description:zh-CN HV自动打怪脚本,初次使用,请先设置好选项,请确认字体设置正常 // @description:zh-TW HV自動打怪腳本,初次使用,請先設置好選項,請確認字體設置正常 -// @version 2.90.22.10 +// @version 2.90.25.08 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues // @icon https://github.com/dodying/UserJs/raw/master/Logo.png // @include http*://hentaiverse.org/* // @include http*://alt.hentaiverse.org/* -// @include http*://e-hentai.org/* -// @connect hentaiverse.org -// @connect e-hentai.org +// @include https://e-hentai.org/* // @compatible Firefox + Greasemonkey // @compatible Chrome/Chromium + Tampermonkey // @compatible Android + Firefox + Usi/Tampermonkey @@ -24,3045 +22,2020 @@ // @grant GM_setValue // @grant GM_getValue // @grant GM_notification -// @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-end // ==/UserScript== /* eslint-disable camelcase */ -const standalone = ['option', 'arena', 'drop', 'stats', 'staminaLostLog', 'battleCode', 'disabled', 'stamina', 'staminaTime', 'lastHref', 'battle', 'monsterDB', 'monsterMID', 'ability']; +const standalone = ['option', 'arena', 'drop', 'stats', 'roundType', 'staminaLostLog', 'monsterStatus', 'battleCode', 'roundAll', 'roundAll', 'roundNow', 'disabled']; const sharable = ['option']; const excludeStandalone = { 'option': ['optionStandalone', 'version', 'lang'] }; -const href = window.location.href; -const isIsekai = href.indexOf('isekai') !== -1; -const current = isIsekai ? 'isekai' : 'persistent'; -const other = isIsekai ? 'persistent' : 'isekai'; -let GM_cache; - -const _1s = 1000; -const _1m = 60 * _1s; -const _1h = 60 * _1m; -const _1d = 24 * _1h; - -try { - const isFrame = window.self !== window.top; - if (isFrame) { - if (!window.top.location.href.match(`/equip/`) && (gE('#riddlecounter') || !gE('#navbar'))) { - if(!window.top.location.href.endsWith(`?s=Battle`)){ - setValue('lastHref', window.top.location.href); - } - window.top.location.href = window.self.location.href; - } - if(window.location.href.indexOf(`?s=Battle&ss=ar`) !== -1 || window.location.href.indexOf(`?s=Battle&ss=rb`) !== -1){ - loadOption(); - setArenaDisplay(); - } - return; - } - try { - if(window.location.href.startsWith('https://')) { - MAIN_URL = MAIN_URL.replace(/^http:/, /^https:/); - } else { - MAIN_URL = MAIN_URL.replace(/^https:/, /^http:/); - } - } catch (e) {} - const Debug = { - Stack: class extends Error { - constructor(description, ...params) { - super(...params); - this.name = 'Debug.Stack'; - } - }, - realtime: false, - logList: [], - maxLogCache: 100, - switchRealtimeLog: function () { - Debug.enableRealtimeLog(Debug.realtime); - }, - enableRealtimeLog: function (enabled) { - Debug.realtime = enabled; - if (enabled) { - Debug.shiftLog(); - } - }, - log: function () { - if (Debug.realtime) { - console.log(...arguments, `\n`, (new Debug.Stack()).stack); - return; - } - Debug.logList.push({ - args: arguments, - stack: (new Debug.Stack()).stack - }); - if (Debug.logList.length > Debug.maxLogCache) { - Debug.logList.shift(); - } - }, - shiftLog: function () { - while (Debug.logList.length) { - const log = Debug.logList.shift(); - console.log(...log.args, `\n`, log.stack); - } - } - } - - const asyncList = []; - function consoleAsyncTasks(name, state) { - if (!state) { - asyncList.splice(asyncList.indexOf(name), 1); - } else { - asyncList.push(name); - } - console.log(`${state ? 'Start' : 'End'} ${name}\n`, JSON.parse(JSON.stringify(asyncList))); - } - function logSwitchAsyncTask(args) { - try{ - const argsStr = Array.from(args).join(','); - const name = `${args.callee.name}${argsStr === '' ? argsStr : `(${argsStr})`}`; - consoleAsyncTasks(name, asyncList.indexOf(name) === -1); - }catch(e){} - } - - //ajax - function $doc(h) { - const d = document.implementation.createHTMLDocument(''); d.documentElement.innerHTML = h; return d; - } - var $ajax = { - - interval: 300, // DO NOT DECREASE THIS NUMBER, OR IT MAY TRIGGER THE SERVER'S LIMITER AND YOU WILL GET BANNED - max: 4, - tid: null, - conn: 0, - index: 0, - queue: [], - - fetch: function (url, data, method, context = {}, headers = {}) { - return new Promise((resolve, reject) => { - $ajax.add(method, url, data, resolve, reject, context, headers); - }); - }, - open: function (url, data, method, context = {}, headers = {}) { - $ajax.fetch(url, data, method, context, headers).then(goto).catch(e=>{console.error(e)}); - }, - openNoFetch: function (url, newTab) { - window.open(url, newTab ? '_blank' : '_self') - // const a = gE('body').appendChild(cE('a')); - // a.href = url; - // a.target = newTab ? '_blank' : '_self'; - // a.click(); - }, - repeat: function (count, func, ...args) { - const list = []; - for (let i = 0; i < count; i++) { - list.push(func(...args)); - } - return list; - }, - add: function (method, url, data, onload, onerror, context = {}, headers = {}) { - method = !data ? 'GET' : method ?? 'POST'; - if (method === 'POST') { - headers['Content-Type'] ??= 'application/x-www-form-urlencoded'; - if (data && typeof data === 'object') { - data = Object.entries(data).map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v)).join('&'); +let isIsekai = window.location.href.indexOf('isekai') !== -1; +let current = isIsekai ? 'isekai' : 'persistent'; +let other = isIsekai ? 'persistent' : 'isekai'; + +(function init() { + if (window.location.host === 'e-hentai.org') { + let href = getValue('url') || (document.referrer.match('hentaiverse.org') ? new URL(document.referrer).origin : 'https://hentaiverse.org'); + href = gE('#eventpane>div>a') ? `${href}/${gE('#eventpane>div>a').href.split('/')[3]}` : getValue('lastEncounter') || href; + if (window.location.href === 'https://e-hentai.org/news.php?encounter') { + openUrl(href); + } else if (gE('#eventpane>div>a')) { + setValue('lastEncounter', href); } - } else if (method === 'JSON') { - method = 'POST'; - headers['Content-Type'] ??= 'application/json'; - if (data && typeof data === 'object') { - data = JSON.stringify(data); - } - } - context.onload = onload; - context.onerror = onerror; - $ajax.queue.push({ method, url, data, headers, context, onload: $ajax.onload, onerror: $ajax.onerror }); - $ajax.next(); - }, - next: function () { - if (!$ajax.queue[$ajax.index] || $ajax.error) { return; - } - if ($ajax.tid) { - if (!$ajax.conn) { - clearTimeout($ajax.tid); - $ajax.timer(); - $ajax.send(); - } - } else { - if ($ajax.conn < $ajax.max) { - $ajax.timer(); - $ajax.send(); - } - } - }, - timer: function () { - var _ns = isIsekai ? 'hvuti' : 'hvut'; - function getValue(k, d, p = _ns + '_') { const v = localStorage.getItem(p + k); return v === null ? d : JSON.parse(v); } - function setValue(k, v, p = _ns + '_', r) { localStorage.setItem(p + k, JSON.stringify(v, r)); } - function ontimer() { - const now = new Date().getTime(); - const last = getValue('last_post'); - if (last && last - now < $ajax.interval) { - $ajax.next(); - return; - } - setValue('last_post', now); - $ajax.tid = null; - $ajax.next(); - }; - $ajax.tid = setTimeout(ontimer, $ajax.interval); - }, - send: function () { - GM_xmlhttpRequest($ajax.queue[$ajax.index]); - $ajax.index++; - $ajax.conn++; - }, - onload: function (r) { - $ajax.conn--; - const text = r.responseText; - if (r.status !== 200) { - $ajax.error = `${r.status} ${r.statusText}: ${r.finalUrl}`; - r.context.onerror?.(); - } else if (text === 'state lock limiter in effect') { - if ($ajax.error !== text) { - // popup(`

${text}

Your connection speed is so fast that
you have reached the maximum connection limit.

Try again later.

`); - console.error(`${text}\nYour connection speed is so fast that you have reached the maximum connection limit. Try again later.`) - } - $ajax.error = text; - r.context.onerror?.(); - } else { - r.context.onload?.(text); - $ajax.next(); - } - }, - onerror: function (r) { - $ajax.conn--; - $ajax.error = `${r.status} ${r.statusText}: ${r.finalUrl}`; - r.context.onerror?.(); - $ajax.next(); - }, - }; - - window.addEventListener('unhandledrejection', (e) => { console.error($ajax.error, e); }); - - (function init() { - if (!checkIsHV()) { - return; } - + setValue('url', window.location.origin); if (!gE('#navbar,#riddlecounter,#textlog')) { - setTimeout(goto, 5 * _1m); - return; - } - - g('version', GM_info ? GM_info.script.version.substr(0, 4) : '2.90'); - if (!getValue('option')) { - g('lang', window.prompt('请输入以下语言代码对应的数字\nPlease put in the number of your preferred language (0, 1 or 2)\n0.简体中文\n1.繁體中文\n2.English', 0) || 2); - addStyle(g('lang')); - _alert(0, '请设置hvAutoAttack', '請設置hvAutoAttack', 'Please config this script'); - gE('.hvAAButton').click(); - return; - } - loadOption(); - g('lang', g('option').lang || '0'); - addStyle(g('lang')); - if (g('option').version !== g('version')) { - gE('.hvAAButton').click(); - if (_alert(1, 'hvAutoAttack版本更新,请重新设置\n强烈推荐【重置设置】后再设置。\n是否查看更新说明?', 'hvAutoAttack版本更新,請重新設置\n強烈推薦【重置設置】後再設置。\n是否查看更新說明?', 'hvAutoAttack version update, please reset\nIt\'s recommended to reset all configuration.\nDo you want to read the changelog?')) { - $ajax.openNoFetch('https://github.com/dodying/UserJs/commits/master/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js', true); - } - gE('.hvAAReset').focus(); - return; - } - - if (gE('[class^="c5"],[class^="c4"]') && _alert(1, '请设置字体\n使用默认字体可能使某些功能失效\n是否查看相关说明?', '請設置字體\n使用默認字體可能使某些功能失效\n是否查看相關說明?', 'Please set the font\nThe default font may make some functions fail to work\nDo you want to see instructions?')) { - $ajax.openNoFetch(`https://github.com/dodying/UserJs/blob/master/HentaiVerse/hvAutoAttack/README${g('lang') === '2' ? '_en.md#about-font' : '.md#关于字体的说明'}`, true); - return; - } - - unsafeWindow = typeof unsafeWindow === 'undefined' ? window : unsafeWindow; - - if (gE('#riddlecounter')) { // 需要答题 - if (!g('option').riddlePopup || window.opener) { - riddleAlert(); // 答题警报 + setTimeout(goto, 5 * 60 * 1000); return; - } - window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); - return; - } - - if (!gE('#navbar')) { // 战斗中 - const box2 = gE('#battle_main').appendChild(cE('div')); - box2.id = 'hvAABox2'; - setPauseUI(box2); - reloader(); - g('attackStatus', g('option').attackStatus); - g('timeNow', time(0)); - g('runSpeed', 1); - Debug.log('______________newRound', false); - newRound(false); - if (g('option').recordEach && !getValue('battleCode')) { - setValue('battleCode', `${time(1)}: ${g('battle')?.roundType?.toUpperCase()}-${g('battle')?.roundAll}`); - } - onBattle(); - updateEncounter(false, true); - return; - } - if(window.top.location.href.endsWith(`?s=Battle`)){ - $ajax.openNoFetch(getValue('lastHref')); - return; } - - // 战斗外 - if (window.location.href.indexOf(`?s=Battle&ss=ba`) === -1) { // 不缓存encounter - setValue('lastHref', window.top.location.href); // 缓存进入战斗前的页面地址 - setArenaDisplay(); + g('version', GM_info ? GM_info.script.version.substr(0, 4) : '2.89'); + if (getValue('option')) { + g('option', getValue('option', true)); + g('lang', g('option').lang || '0'); + addStyle(g('lang')); + if (g('option').version !== g('version')) { + gE('.hvAAButton').click(); + if (_alert(1, 'hvAutoAttack版本更新,请重新设置\n强烈推荐【重置设置】后再设置。\n是否查看更新说明?', 'hvAutoAttack版本更新,請重新設置\n強烈推薦【重置設置】後再設置。\n是否查看更新說明?', 'hvAutoAttack version update, please reset\nIt\'s recommended to reset all configuration.\nDo you want to read the changelog?')) openUrl('https://github.com/dodying/UserJs/commits/master/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js', true); + gE('.hvAAReset').focus(); + return; + } } else { - // 补充记录(因写入冲突、网络卡顿等)未被记录的encounter链接 - const encounterURL = window.location.href?.split('/')[3]; - const encounter = getEncounter(); - if (!encounter.filter(e => e.href === encounterURL).length) { - encounter.unshift({ href: encounterURL, time: time(0), encountered: time(0) }); - } - setEncounter(encounter); - } - delValue(1); - if (g('option').showQuickSite && g('option').quickSite) { - quickSite(); - } - const hvAAPauseUI = document.body.appendChild(cE('div')); - hvAAPauseUI.classList.add('hvAAPauseUI'); - setPauseUI(hvAAPauseUI); - asyncOnIdle(); - - }()); - - function setArenaDisplay(){ - if(window.location.href.indexOf(`?s=Battle&ss=ar`) === -1 && window.location.href.indexOf(`?s=Battle&ss=rb`) === -1){ - return; - } - var ar = g('option').idleArenaValue?.split(','); - if(!ar || ar.length === 0){ - return; - } - if(!g('option').obscureNotIdleArena){ - return; - } - gE('img[src*="startchallenge.png"]', 'all', document).forEach((btn) => { - const temp = btn.getAttribute('onclick').match(/init_battle\((\d+),\d+,'(.*?)'\)/); - if(ar.includes(temp[1])) { + g('lang', window.prompt('请输入以下语言代码对应的数字\nPlease put in the number of your preferred language (0, 1 or 2)\n0.简体中文\n1.繁體中文\n2.English', 0) || 2); + addStyle(g('lang')); + _alert(0, '请设置hvAutoAttack', '請設置hvAutoAttack', 'Please config this script'); + gE('.hvAAButton').click(); return; - } - gE('div', 'all', btn.parentNode.parentNode).forEach(div=>{div.style.cssText += 'color:grey!important;'}); - }); - } - - function loadOption() { - let option = getValue('option', true); - const aliasDict = { - 'debuffSkillImAll': 'debuffSkillAllIm', - 'debuffSkillWeAll': 'debuffSkillAllWk', - 'debuffSkillAllImCondition': 'debuffSkillImpCondition', - 'debuffSkillAllWeCondition': 'debuffSkillWkCondition', - 'battleUnresponsive_Alert': 'delayAlert', - 'battleUnresponsive_Reload': 'delayReload', - 'battleUnresponsive_Alt': 'delayAlt', - 'battleUnresponsiveTime_Alert': 'delayAlertTime', - 'battleUnresponsiveTime_Reload': 'delayReloadTime', - 'battleUnresponsiveTime_Alt': 'delayAltTime', - } - for (let key in aliasDict) { - const itemArray = key.split('_'); - if (itemArray.length === 1) { - option[key] ??= option[aliasDict[key]]; - option[aliasDict[key]] = undefined; - } else { - option[itemArray[0]] ??= {}; - option[itemArray[0]][itemArray[1]] ??= option[aliasDict[key]]; - } } - if(isFrame){ - g('option', option); - } else{ - g('option', setValue('option', option)); - } - } - - async function asyncOnIdle() { try { - let notBattleReady = false; - const idleStart = time(0); - await Promise.all([ - (async () => { try { - await asyncGetItems(); - const checked = await asyncCheckSupply(); - notBattleReady ||= !checked; - } catch (e) {console.error(e)}})(), - asyncSetStamina(), - asyncSetEnergyDrinkHathperk(), - asyncSetAbilityData(), - updateArena(), - updateEncounter(g('option').encounter), - (async () => { try { - const checked = await asyncCheckRepair(); - notBattleReady ||= !checked; - } catch (e) {console.error(e)}})(), - ]); - if (notBattleReady) { - return; - } - if (g('option').idleArena && g('option').idleArenaValue) { - startUpdateArena(idleStart); - } - setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); - } catch (e) {console.error(e)}} - - // 通用// - function setPauseUI(parent) { - setPauseButton(parent); - setPauseHotkey(); - } - - function setPauseButton(parent) { - if (!g('option').pauseButton) { - return; - } - const button = parent.appendChild(cE('button')); - button.innerHTML = '暂停暫停Pause'; - if (getValue('disabled')) { // 如果禁用 - document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - button.innerHTML = '继续繼續Continue'; - } - button.className = 'pauseChange'; - button.onclick = pauseChange; - } - function setPauseHotkey() { - if (!g('option').pauseHotkey) { - return; - } - document.addEventListener('keydown', (e) => { - if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + if (gE('[class^="c5"],[class^="c4"]') && _alert(1, '请设置字体\n使用默认字体可能使某些功能失效\n是否查看相关说明?', '請設置字體\n使用默認字體可能使某些功能失效\n是否查看相關說明?', 'Please set the font\nThe default font may make some functions fail to work\nDo you want to see instructions?')) { + openUrl(`https://github.com/dodying/UserJs/blob/master/HentaiVerse/hvAutoAttack/README${g('lang') === '2' ? '_en.md#about-font' : '.md#关于字体的说明'}`, true); return; - } - if (e.keyCode === g('option').pauseHotkeyCode) { - pauseChange(); - } - }, false); - } - - function formatTime(t, size = 2) { - t = [t / _1h, (t / _1m) % 60, (t / _1s) % 60, (t % _1s) / 10].map(cdi => Math.floor(cdi)); - while (t.length > Math.max(size, g('option').encounterQuickCheck ? 2 : 3)) { // remove zero front - const front = t.shift(); - if (!front) { - continue; - } - t.unshift(front); - break; } - return t; - } - - function getKeys(objArr, prop) { + unsafeWindow = typeof unsafeWindow === 'undefined' ? window : unsafeWindow; + if (gE('#riddlecounter')) { // 需要答题 + if (g('option').riddlePopup && !window.opener) { + window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); + } else { + riddleAlert(); // 答题警报 + } + } else if (!gE('#navbar')) { // 战斗中 + const box2 = gE('#battle_main').appendChild(cE('div')); + box2.id = 'hvAABox2'; + if (g('option').pauseButton) { + const button = box2.appendChild(cE('button')); + button.innerHTML = '暂停暫停Pause'; + button.className = 'pauseChange'; + button.onclick = function () { + pauseChange(); + }; + } + if (g('option').pauseHotkey) { + document.addEventListener('keydown', (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; + if (e.keyCode === g('option').pauseHotkeyCode) { + pauseChange(); + // document.removeEventListener('keydown', pause, false); + } + }, false); + } + reloader(); + g('attackStatus', g('option').attackStatus); + g('timeNow', time(0)); + g('runSpeed', 1); + newRound(); + if (g('option').recordEach && !getValue('battleCode')) setValue('battleCode', `${time(1)}: ${g('roundType').toUpperCase()}-${g('roundAll')}`); + main(); + } else { // 战斗外 + delValue(2); + g('dateNow', time(2)); + if (g('option').quickSite) quickSite(); + if (g('option').encounter) encounterCheck(); + if (!g('option').restoreStamina && gE('#stamina_readout .fc4.far>div').textContent.match(/\d+/)[0] * 1 <= g('option').staminaLow) { + setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * 1000); + return; + } + if (g('option').repair) { + repairCheck(); + return; + } + if (g('option').idleArena) setTimeout(idleArena, (g('option').idleArenaTime * (Math.random() * 20 + 90) / 100) * 1000); + } +}()); +// 通用// +function getKeys(objArr, prop) { let out = []; objArr.forEach((_objArr) => { - out = prop ? out.concat(Object.keys(_objArr[prop])) : out.concat(Object.keys(_objArr)); + out = prop ? out.concat(Object.keys(_objArr[prop])) : out.concat(Object.keys(_objArr)); }); out = out.sort(); for (let i = 1; i < out.length; i++) { - if (out[i - 1] === out[i]) { - out.splice(i, 1); - i--; - } + if (out[i - 1] === out[i]) { + out.splice(i, 1); + i--; + } } return out; - } +} - function time(e, stamp) { +function time(e, stamp) { const date = stamp ? new Date(stamp) : new Date(); if (e === 0) { - return date.getTime(); + return date.getTime(); } if (e === 1) { - return `${date.getUTCMonth() + 1}/${date.getUTCDate()}`; - } if (e === 2) { - return `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${date.getUTCDate()}`; + return `${date.getUTCMonth() + 1}/${date.getUTCDate()}`; + } if (e === 2) { // date.toLocaleDateString(lang,option); + return `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${date.getUTCDate()}`; } if (e === 3) { - return date.toLocaleString(navigator.language, { - hour12: false, - }); + return date.toLocaleString(navigator.language, { + hour12: false, + }); } - } +} - function gE(ele, mode, parent) { // 获取元素 +function gE(ele, mode, parent) { // 获取元素 if (typeof ele === 'object') { - return ele; + return ele; } if (mode === undefined && parent === undefined) { - return (isNaN(ele * 1)) ? document.querySelector(ele) : document.getElementById(ele); + return (isNaN(ele * 1)) ? document.querySelector(ele) : document.getElementById(ele); } if (mode === 'all') { - return (parent === undefined) ? document.querySelectorAll(ele) : parent.querySelectorAll(ele); + return (parent === undefined) ? document.querySelectorAll(ele) : parent.querySelectorAll(ele); } if (typeof mode === 'object' && parent === undefined) { - return mode.querySelector(ele); + return mode.querySelector(ele); } - } +} - function cE(name) { // 创建元素 +function cE(name) { // 创建元素 return document.createElement(name); - } +} - function isOn(id) { // 是否可以施放技能/使用物品 +function isOn(id) { // 是否可以施放技能/使用物品 if (id * 1 > 10000) { // 使用物品 - return gE(`.bti3>div[onmouseover*="${id}"]`); + return gE(`.bti3>div[onmouseover*="${id}"]`); } // 施放技能 return (gE(id) && gE(id).style.opacity !== '0.5') ? gE(id) : false; - } +} - function setLocal(item, value) { +function setLocal(item, value) { if (typeof GM_setValue === 'undefined') { - window.localStorage[`hvAA-${item}`] = (typeof value === 'string') ? value : JSON.stringify(value); + window.localStorage[`hvAA-${item}`] = (typeof value === 'string') ? value : JSON.stringify(value); } else { - GM_setValue(item, value); + GM_setValue(item, value); } - } +} - function setValue(item, value) { // 储存数据 +function setValue(item, value) { // 储存数据 if (!standalone.includes(item)) { - setLocal(item, value); - return value; + setLocal(item, value); + return; } setLocal(`${current}_${item}`, value); if (sharable.includes(item) && !getValue('option').optionStandalone) { - setLocal(`${other}_${item}`, value); + setLocal(`${other}_${item}`, value); } - return value; - } +} - function getLocal(item, toJSON) { +function getLocal(item, toJSON) { if (typeof GM_getValue === 'undefined' || !GM_getValue(item, null)) { - item = `hvAA-${item}`; - return (item in window.localStorage) ? ((toJSON) ? JSON.parse(window.localStorage[item]) : window.localStorage[item]) : null; + item = `hvAA-${item}`; + return (item in window.localStorage) ? ((toJSON) ? JSON.parse(window.localStorage[item]) : window.localStorage[item]) : null; } return GM_getValue(item, null); - } +} - function getValue(key, toJSON) { // 读取数据 - if (!standalone.includes(key)) { - return getLocal(key, toJSON); +function getValue(item, toJSON) { // 读取数据 + if (!standalone.includes(item)) { + return getLocal(item, toJSON); } - let otherWorldItem = getLocal(`${other}_${key}`); + let otherWorldItem = getLocal(`${other}_${item}`); // 将旧的数据迁移到新的数据 - if (!getLocal(`${current}_${key}`)) { - let itemExisted = getLocal(key); - if (!itemExisted && sharable.includes(key)) { - itemExisted = otherWorldItem; - } - if (!itemExisted) { - return null; // 若都没有该数据 - } - itemExisted = JSON.parse(JSON.stringify(itemExisted)); - setLocal(`${current}_${key}`, itemExisted); - delLocal(key); + if (!getLocal(`${current}_${item}`)) { + let itemExisted = getLocal(item); + if (!itemExisted && sharable.includes(item)) { + itemExisted = otherWorldItem; + } + if (!itemExisted) { + return null; // 若都没有该数据 + } + itemExisted = JSON.parse(JSON.stringify(itemExisted)); + setLocal(`${current}_${item}`, itemExisted); + delLocal(item); } - if (Object.keys(excludeStandalone).includes(key)) { - otherWorldItem ??= getLocal(`${current}_${key}`) ?? {}; - for (let i of excludeStandalone[key]) { - otherWorldItem[i] = getLocal(`${current}_${key}`)[i]; - } + if (Object.keys(excludeStandalone).includes(item)) { + if (!otherWorldItem) { + otherWorldItem = getLocal(`${current}_${item}`) + } + if (!otherWorldItem) { + otherWorldItem = {} + } + for (let i in excludeStandalone[item]) { + const key = excludeStandalone[item][i]; + otherWorldItem[key] = getLocal(`${current}_${item}`)[key]; + } } - setLocal(`${other}_${key}`, otherWorldItem); - return getLocal(`${current}_${key}`); - } + setLocal(`${other}_${item}`, otherWorldItem) + return getLocal(`${current}_${item}`); +} - function delLocal(key) { +function delLocal(item) { if (typeof GM_deleteValue === 'undefined') { - window.localStorage.removeItem(`hvAA-${key}`); - return; + window.localStorage.removeItem(`hvAA-${item}`); + } else { + GM_deleteValue(item); } - GM_deleteValue(key); - } +} - function delValue(key) { // 删除数据 - if (standalone.includes(key)) { - key = `${current}_${key}`; - } - if (typeof key === 'string') { - delLocal(key); - return; - } - if (typeof key !== 'number') { - return; - } - const itemMap = { - 0: ['disabled'], - 1: ['battle', 'battleCode'], - } - for (let item of itemMap[key]) { - delValue(item); +function delValue(item) { // 删除数据 + if (standalone.includes(item)) { + item = `${current}_${item}`; + } + if (typeof item === 'string') { + delLocal(item); + } else if (typeof item === 'number') { + if (item === 0) { + delValue('disabled'); + } else if (item === 1) { + delValue('roundNow'); + delValue('roundAll'); + delValue('monsterStatus'); + } else if (item === 2) { + delValue('roundType'); + delValue('battleCode'); + delValue(0); + delValue(1); + } } - } +} - function goto() { // 前进 +function goto() { // 前进 window.location.href = window.location; setTimeout(goto, 5000); - } - function gotoAlt() { - const hv = 'hentaiverse.org'; - const alt = 'alt.' + hv; - if(window.location.host === hv) { - window.location.href = window.location.href.replace(`://${hv}`, `://${alt}`) - } else if (window.location.host === alt) { - window.location.href = window.location.href.replace(`://${alt}`, `://${hv}`) - } - } - function g(key, value) { // 全局变量 +} + +function g(key, value) { // 全局变量 const hvAA = window.hvAA || {}; if (key === undefined && value === undefined) { - return hvAA; + return hvAA; } if (value === undefined) { - return hvAA[key]; + return hvAA[key]; } hvAA[key] = value; window.hvAA = hvAA; return window.hvAA[key]; - } +} + +function post(href, func, parm, type) { // post + let xhr = new window.XMLHttpRequest(); + xhr.open(parm ? 'POST' : 'GET', href); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); + xhr.responseType = type || 'document'; + xhr.onerror = function () { + xhr = null; + post(href, func, parm, type); + }; + xhr.onload = function (e) { + if (e.target.status >= 200 && e.target.status < 400 && typeof func === 'function') { + const data = e.target.response; + if (xhr.responseType === 'document' && gE('#messagebox', data)) { + if (gE('#messagebox')) { + gE('#csp').replaceChild(gE('#messagebox', data), gE('#messagebox')); + } else { + gE('#csp').appendChild(gE('#messagebox', data)); + } + } + func(data, e); + } + xhr = null; + }; + xhr.send(parm); +} - function objArrSort(key) { // 对象数组排序函数,从小到大排序 +function objArrSort(key) { // 对象数组排序函数,从小到大排序 return function (obj1, obj2) { - return (obj2[key] < obj1[key]) ? 1 : (obj2[key] > obj1[key]) ? -1 : 0; + return (obj2[key] < obj1[key]) ? 1 : (obj2[key] > obj1[key]) ? -1 : 0; }; - } +} - function objSort(obj) { // 对象排序 +function objSort(obj) { // 对象排序 const objNew = {}; const arr = Object.keys(obj).sort(); arr.forEach((key) => { - objNew[key] = obj[key]; + objNew[key] = obj[key]; }); return objNew; - } +} - function _alert(func, l0, l1, l2, answer) { +function _alert(func, l0, l1, l2, answer) { const lang = [l0, l1, l2][g('lang')]; if (func === -1) { - return lang; + return lang; } if (func === 0) { - window.alert(lang); + window.alert(lang); } else if (func === 1) { - return window.confirm(lang); + return window.confirm(lang); } else if (func === 2) { - return window.prompt(lang, answer); + return window.prompt(lang, answer); } - } +} - function addStyle(lang) { // CSS +function openUrl(url, newTab) { + const a = gE('body').appendChild(cE('a')); + a.href = url; + a.target = newTab ? '_blank' : '_self'; + a.click(); +} + +function addStyle(lang) { // CSS const langStyle = gE('head').appendChild(cE('style')); langStyle.className = 'hvAA-LangStyle'; langStyle.textContent = `l${lang}{display:inline!important;}`; - if (/^[01]$/.test(lang)) { - langStyle.textContent = `${langStyle.textContent}l01{display:inline!important;}`; - } + if (/^[01]$/.test(lang)) langStyle.textContent = `${langStyle.textContent}l01{display:inline!important;}`; const globalStyle = gE('head').appendChild(cE('style')); const cssContent = [ - // hvAA - 'l0,l1,l01,l2{display:none;}', // l0: 简体 l1: 繁体 l01:简繁体共用 l2: 英文 - '#hvAABox2{position:absolute;left:1075px;padding-top: 6px;}', - '.hvAALog{font-size:20px;}', - '.hvAAPauseUI{top:30px;left:1246px;position:absolute;z-index:9999}', - '.hvAAButton{top:5px;left:1255px;position:absolute;z-index:9999;cursor:pointer;width:24px;height:24px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADi0lEQVRIiZVWPYgUZxj+dvGEk7vsNdPYCMul2J15n+d991PIMkWmOEyMyRW2FoJIUojYp5ADFbZJkyISY3EqKGpgz+Ma4bqrUojICaIsKGIXSSJcsZuD3RT3zWZucquXDwYG5n2f9/d5vnFuHwfAZySfAXgN4DXJzTiOj+3H90OnkmXZAe/9FMm3JJ8AuBGepyRfle2yLDvgnKt8EDVJkq8B3DGzjve+1m63p0n2AVzJbUh2SG455yre+5qZ/aCq983sxMfATwHYJvlCVYckHwFYVdURgO8LAS6RHJJcM7N1VR0CeE5yAGBxT3AR+QrA3wA20tQOq+pFkgOS90Tk85J51Xs9qaorqjoAcC6KohmSGyQHcRx/kbdv7AHgDskXaWqH0zSddc5Voyia2SOXapqmswsLvpam6ez8/Pwn+YcoimYAvARw04XZ5N8qZtZR1aGqXnTOVSd0cRd42U5EzqvqSFWX2u32tPd+yjnnXNiCGslHJAf7ybwM7r2vAdgWkYdZls157w+NK/DeT7Xb7WkAqyTvlZHjOD5oxgtmtqrKLsmze1VJsquqKwsLO9vnnKvkJHpLsq+qo/JAd8BtneTvqvqTiPwoIu9EZKUUpGpmi2Y2UtU+yTdJkhx1JJ8FEl0pruK/TrwA4F2r1WrkgI1G4wjJP0XkdLF9WaZzZnZZVa8GMj5xgf43JvXczFZbLb1ebgnJn0nenjQbEVkG0JsUYOykyi6Aa+XoQTJuTRr8OADJzVBOh+SlckYkz5L8Q0TquXOj0fhURN6r6pkSeAXAUsDaJPnYxXF8jOQrklskh97ryZJTVURWAPwF4DqAX0TkvRl/zTKdK2aeJMnxICFbAHrNZtOKVVdIrrVa2t1jz6sicprkbQC3VPVMGTzMpQvgQY63i8lBFddVdVCk/6TZlMFzopFci+P44H+YHCR3CODc/wUvDPY7ksMg9buZrKr3ATwvyoT3vrafzPP3er1eA9Azs7tjJhcqOBHkeSOKohkROR9K7prZYqnnlSRJjofhb4vIt/V6vUbyN1Xtt1qtb1zpZqs45xyAxXAnvCQ5FJGHqrpiZiMzu5xnHlZxCOABybXw3gvgp/Zq3/gA+BLATVVdyrJsbods2lfVq7lN4crMtapjZndD5pPBixWFLTgU7uQ3AJ6KyLKILAdy9sp25bZMBC//JSRJcjQIYg9Aj+TjZrNp+/mb+Ad711sdZZ1k/QAAAABJRU5ErkJggg==) center no-repeat transparent;}', - '#hvAABox{left:calc(50% - 350px);top:50px;font-size:16px!important;z-index:4;width:700px;height:538px;position:absolute;text-align:left;background-color:#E3E0D1;border:1px solid #000;border-radius:10px;font-family:"Microsoft Yahei";}', - '.hvAATablist{position:relative;left:14px;}', - '.hvAATabmenu{position:absolute;left:-9px;}', - '.hvAATabmenu>span{display:block;padding:5px 10px;margin:0 10px 0 0;border:1px solid #91a7b4;border-radius:5px;background-color:#E3F1F8;color:#000;text-decoration:none;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;cursor:pointer;}', - '.hvAATabmenu>span:hover{left:-5px;position:relative;color:#0000FF;z-index:2!important;}', - '.hvAATabmenu>span>input{margin:0 0 0 -8px;}', - '.hvAATab{position:absolute;width:605px;height:430px;left:36px;padding:15px;border:1px solid #91A7B4;border-radius:3px;box-shadow:0 2px 3px rgba(0,0,0,0.1);color:#666;background-color:#EDEBDF;overflow:auto;}', - '.hvAATab>div:nth-child(2n){border:1px solid #EAEAEA;background-color:#FAFAFA;}', - '.hvAATab>div:nth-child(2n+1){border:1px solid #808080;background-color:#DADADA;}', - '.hvAATab a{margin:0 2px;}', - '.hvAATab b{font-family:Georgia,Serif;font-size:larger;}', - '.hvAATab input.hvAANumber{width:24px;text-align:right;}', - '#hvAABox input[type=\'checkbox\']{top: 3px;}', - '.hvAATab ul,.hvAATab ol{margin:0;}', - '.hvAATab label{cursor:pointer;}', - '.hvAATab table{border:2px solid #000;border-collapse:collapse;margin:0 auto;}', - '.hvAATh>*{font-weight:bold;font-size:larger;}', - '.hvAATab table>tbody>tr>*{border:1px solid #000;}', - '#hvAATab-Drop tr>td:nth-child(1),#hvAATab-Usage tr>td:nth-child(1){text-align:left;}', - '#hvAATab-Drop td,#hvAATab-Usage td{text-align:right;white-space:nowrap;}', - // '#hvAATab-Drop td:empty:before,#hvAATab-Usage td:empty:before{content:"";}', - '.selectTable{cursor:pointer;}', - `.selectTable:before{content:"${String.fromCharCode(0x22A0.toString(10))}";}`, - '.hvAACenter{text-align:center;}', - '.hvAATitle{font-weight:bolder;}', - '.hvAAGoto{cursor:pointer;text-decoration:underline;}', - '.hvAANew{width:25px;height:25px;float:left;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAMCAYAAACX8hZLAAAAcElEQVQ4jbVRSQ4AIQjz/59mTiZIF3twmnCwFAq4FkeFXM+5vCzohYxjPMtfxS8CN6iqQ7TfE0wrODxVbzJNgoaTo4CmbBO1ZWICouQ0DHaL259MEzaU+w8pZOdSjcUgaPJDHCbO0A2kuAiuwPGQ+wBms12x8HExTwAAAABJRU5ErkJggg==) center no-repeat transparent;}', - '#hvAATab-Alarm input[type="text"]{width:512px;}', - '.testAlarms>div{border:2px solid #000;}', - '.hvAAArenaLevels{display:none; grid-template-columns:repeat(7, 20px 1fr);}', - '.hvAAcheckItems{display:grid; grid-template-columns:repeat(3, 0.1fr 0.3fr 1fr)}', - '.hvAAcheckItems>input.hvAANumber{width:32px}', - '.hvAAConfig{width:100%;height:16px;}', - '.hvAAButtonBox{position:relative;top:468px;}', - '.encounterUI{font-weight:bold;font-size:10pt;position:absolute;top:58px;left:1240px;text-decoration:none;}', - '.quickSiteBar{position:absolute;top:0px;left:1290px;font-size:18px;text-align:left;width:165px;height:calc(100% - 10px);display:flex;flex-direction:column;flex-wrap:wrap;}', - '.quickSiteBar>span{display:block;max-height:24px;overflow:hidden;text-overflow:ellipsis;}', - '.quickSiteBar>span>a{text-decoration:none;}', - '.customize{border: 2px dashed red!important;min-height:21px;}', - '.customize>.customizeGroup{display:block;background-color:#FFF;}', - '.customize>.customizeGroup:nth-child(2n){background-color:#C9DAF8;}', - '.customizeBox{position:absolute;z-index:-1;border:1px solid #000;background-color:#EDEBDF;}', - '.customizeBox>span{display:inline-block;font-size:16px;margin:0 1px;padding:0 5px;font-weight:bold;border:1px solid #5C0D11;border-radius:10px;}', - '.customizeBox>span.hvAAInspect{padding:0 3px;cursor:pointer;}', - '.customizeBox>span.hvAAInspect[title="on"]{background-color:red;}', - '.customizeBox>span a{text-decoration:none;}', - '.customizeBox>select{max-width:60px;}', - '.favicon{width:16px;height:16px;margin:-3px 1px;border:1px solid #000;border-radius:3px;}', - '.answerBar{z-index:1000;width:710px;height:40px;position:absolute;top:55px;left:282px;display:table;border-spacing:5px;}', - '.answerBar>div{border:4px solid red;display:table-cell;cursor:pointer;}', - '.answerBar>div:hover{background:rgba(63,207,208,0.20);}', - '#hvAAInspectBox{background-color:#EDEBDF;position:absolute;z-index:9;border: 2px solid #5C0D11;font-size:16px;font-weight:bold;padding:3px;display:none;}', - // 全局 - 'button{border-radius:3px;border:2px solid #808080;cursor:pointer;margin:0 1px;}', - // hv - '#riddleform>div:nth-child(3)>img{width:700px;}', - '#battle_right{overflow:visible;}', - '#pane_log{height:403px;}', - '.tlbQRA{text-align:left;font-weight:bold;}', // 标记已检测的日志行 - '.tlbWARN{text-align:left;font-weight:bold;color:red;font-size:20pt;}', // 标记检测出异常的日志行 - // 怪物标号用数字替代字母,目前弃用 - // '#pane_monster{counter-reset:order;}', - // '.btm2>div:nth-child(1):before{font-size:23px;font-weight:bold;text-shadow:1px 1px 2px;content:counter(order);counter-increment:order;}', - // '.btm2>div:nth-child(1)>img{display:none;}', + // hvAA + 'l0,l1,l01,l2{display:none;}', // l0: 简体 l1: 繁体 l01:简繁体共用 l2: 英文 + '#hvAABox2{position:absolute;left:1075px}', + '.hvAALog{font-size:20px;}', + '.hvAAButton{top:4px;left:1250px;position:absolute;z-index:9999;cursor:pointer;width:24px;height:24px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADi0lEQVRIiZVWPYgUZxj+dvGEk7vsNdPYCMul2J15n+d991PIMkWmOEyMyRW2FoJIUojYp5ADFbZJkyISY3EqKGpgz+Ma4bqrUojICaIsKGIXSSJcsZuD3RT3zWZucquXDwYG5n2f9/d5vnFuHwfAZySfAXgN4DXJzTiOj+3H90OnkmXZAe/9FMm3JJ8AuBGepyRfle2yLDvgnKt8EDVJkq8B3DGzjve+1m63p0n2AVzJbUh2SG455yre+5qZ/aCq983sxMfATwHYJvlCVYckHwFYVdURgO8LAS6RHJJcM7N1VR0CeE5yAGBxT3AR+QrA3wA20tQOq+pFkgOS90Tk85J51Xs9qaorqjoAcC6KohmSGyQHcRx/kbdv7AHgDskXaWqH0zSddc5Voyia2SOXapqmswsLvpam6ez8/Pwn+YcoimYAvARw04XZ5N8qZtZR1aGqXnTOVSd0cRd42U5EzqvqSFWX2u32tPd+yjnnXNiCGslHJAf7ybwM7r2vAdgWkYdZls157w+NK/DeT7Xb7WkAqyTvlZHjOD5oxgtmtqrKLsmze1VJsquqKwsLO9vnnKvkJHpLsq+qo/JAd8BtneTvqvqTiPwoIu9EZKUUpGpmi2Y2UtU+yTdJkhx1JJ8FEl0pruK/TrwA4F2r1WrkgI1G4wjJP0XkdLF9WaZzZnZZVa8GMj5xgf43JvXczFZbLb1ebgnJn0nenjQbEVkG0JsUYOykyi6Aa+XoQTJuTRr8OADJzVBOh+SlckYkz5L8Q0TquXOj0fhURN6r6pkSeAXAUsDaJPnYxXF8jOQrklskh97ryZJTVURWAPwF4DqAX0TkvRl/zTKdK2aeJMnxICFbAHrNZtOKVVdIrrVa2t1jz6sicprkbQC3VPVMGTzMpQvgQY63i8lBFddVdVCk/6TZlMFzopFci+P44H+YHCR3CODc/wUvDPY7ksMg9buZrKr3ATwvyoT3vrafzPP3er1eA9Azs7tjJhcqOBHkeSOKohkROR9K7prZYqnnlSRJjofhb4vIt/V6vUbyN1Xtt1qtb1zpZqs45xyAxXAnvCQ5FJGHqrpiZiMzu5xnHlZxCOABybXw3gvgp/Zq3/gA+BLATVVdyrJsbods2lfVq7lN4crMtapjZndD5pPBixWFLTgU7uQ3AJ6KyLKILAdy9sp25bZMBC//JSRJcjQIYg9Aj+TjZrNp+/mb+Ad711sdZZ1k/QAAAABJRU5ErkJggg==) center no-repeat transparent;}', + '#hvAABox{left:calc(619px - 350px);top:calc(min(100%, 1094px)*0.5 - 269px);font-size:16px!important;z-index:4;width:700px;height:538px;position:absolute;text-align:left;background-color:#E3E0D1;border:1px solid #000;border-radius:10px;font-family:"Microsoft Yahei";}', + '.hvAATablist{position:relative;left:14px;}', + '.hvAATabmenu{position:absolute;left:-9px;}', + '.hvAATabmenu>span{display:block;padding:5px 10px;margin:0 10px 0 0;border:1px solid #91a7b4;border-radius:5px;background-color:#E3F1F8;color:#000;text-decoration:none;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;cursor:pointer;}', + '.hvAATabmenu>span:hover{left:-5px;position:relative;color:#0000FF;z-index:2!important;}', + '.hvAATabmenu>span>input{margin:0 0 0 -8px;}', + '.hvAATab{position:absolute;width:605px;height:430px;left:36px;padding:15px;border:1px solid #91A7B4;border-radius:3px;box-shadow:0 2px 3px rgba(0,0,0,0.1);color:#666;background-color:#EDEBDF;overflow:auto;}', + '.hvAATab>div:nth-child(2n){border:1px solid #EAEAEA;background-color:#FAFAFA;}', + '.hvAATab>div:nth-child(2n+1){border:1px solid #808080;background-color:#DADADA;}', + '.hvAATab a{margin:0 2px;}', + '.hvAATab b{font-family:Georgia,Serif;font-size:larger;}', + '.hvAATab input.hvAANumber{width:24px;text-align:right;}', + '.hvAATab ul,.hvAATab ol{margin:0;}', + '.hvAATab label{cursor:pointer;}', + '.hvAATab table{border:2px solid #000;border-collapse:collapse;margin:0 auto;}', + '.hvAATh>*{font-weight:bold;font-size:larger;}', + '.hvAATab table>tbody>tr>*{border:1px solid #000;}', + '#hvAATab-Drop tr>td:nth-child(1),#hvAATab-Usage tr>td:nth-child(1){text-align:left;}', + '#hvAATab-Drop td,#hvAATab-Usage td{text-align:right;white-space:nowrap;}', + // '#hvAATab-Drop td:empty:before,#hvAATab-Usage td:empty:before{content:"";}', + '.selectTable{cursor:pointer;}', + `.selectTable:before{content:"${String.fromCharCode(0x22A0.toString(10))}";}`, + '.hvAACenter{text-align:center;}', + '.hvAATitle{font-weight:bolder;}', + '.hvAAGoto{cursor:pointer;text-decoration:underline;color:#5C0D11;}', + '.hvAANew{width:25px;height:25px;float:left;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAMCAYAAACX8hZLAAAAcElEQVQ4jbVRSQ4AIQjz/59mTiZIF3twmnCwFAq4FkeFXM+5vCzohYxjPMtfxS8CN6iqQ7TfE0wrODxVbzJNgoaTo4CmbBO1ZWICouQ0DHaL259MEzaU+w8pZOdSjcUgaPJDHCbO0A2kuAiuwPGQ+wBms12x8HExTwAAAABJRU5ErkJggg==) center no-repeat transparent;}', + '#hvAATab-Alarm input[type="text"]{width:512px;}', + '.testAlarms>div{border:2px solid #000;}', + '.hvAAArenaLevels{display:none;}', + '.hvAAConfig{width:100%;height:16px;}', + '.hvAAButtonBox{position:relative;top:468px;}', + '.lastEncounter{font-weight:bold;font-size:large;position:absolute;top:32px;left:1253px;text-decoration:none;}', + '.quickSiteBar{position:absolute;top:0px;left:1280px;font-size:18px;text-align:left;width:165px;height:calc(100% - 10px);display:flex;flex-direction:column;flex-wrap:wrap;}', + '.quickSiteBar>span{display:block;max-height:24px;overflow:hidden;text-overflow:ellipsis;}', + '.quickSiteBar>span>a{text-decoration:none;}', + '.customize{border: 2px dashed red!important;min-height:21px;}', + '.customize>.customizeGroup{display:block;background-color:#FFF;}', + '.customize>.customizeGroup:nth-child(2n){background-color:#C9DAF8;}', + '.customizeBox{position:absolute;z-index:-1;border:1px solid #000;background-color:#EDEBDF;}', + '.customizeBox>span{display:inline-block;font-size:16px;margin:0 1px;padding:0 5px;font-weight:bold;border:1px solid #5C0D11;border-radius:10px;}', + '.customizeBox>span.hvAAInspect{padding:0 3px;cursor:pointer;}', + '.customizeBox>span.hvAAInspect[title="on"]{background-color:red;}', + '.customizeBox>span a{text-decoration:none;}', + '.customizeBox>select{max-width:60px;}', + '.favicon{width:16px;height:16px;margin:-3px 1px;border:1px solid #000;border-radius:3px;}', + '.answerBar{z-index:1000;width:710px;height:40px;position:absolute;top:55px;left:282px;display:table;border-spacing:5px;}', + '.answerBar>div{border:4px solid red;display:table-cell;cursor:pointer;}', + '.answerBar>div:hover{background:rgba(63,207,208,0.20);}', + '#hvAAInspectBox{background-color:#EDEBDF;position:absolute;z-index:9;border: 2px solid #5C0D11;font-size:16px;font-weight:bold;padding:3px;display:none;}', + // 全局 + 'button{border-radius:3px;border:2px solid #808080;cursor:pointer;margin:0 1px;}', + // hv + '#riddleform>div:nth-child(3)>img{width:700px;}', + '#battle_right{overflow:visible;}', + '#pane_log{height:403px;}', + // '#pane_monster{counter-reset:order;}', + // '.btm2>div:nth-child(1):before{font-size:30px;font-weight:bold;text-shadow:1px 1px 2px;content:counter(order);counter-increment:order;}', + // '.btm2>div:nth-child(1)>img{display:none;}' + '.tlbQRA{text-align:left;font-weight:bold;}', // 标记已检测的日志行 + '.tlbWARN{text-align:left;font-weight:bold;color:red;font-size:20pt;}', // 标记检测出异常的日志行 ].join(''); globalStyle.textContent = cssContent; optionButton(lang); - } +} - function optionButton(lang) { // 配置按钮 +function optionButton(lang) { // 配置按钮 const optionButton = gE('body').appendChild(cE('div')); optionButton.className = 'hvAAButton'; optionButton.onclick = function () { - if (gE('#hvAABox')) { - gE('#hvAABox').style.display = (gE('#hvAABox').style.display === 'none') ? 'block' : 'none'; - } else { - optionBox(); - gE('#hvAATab-Main').style.zIndex = 1; - gE('select[name="lang"]').value = lang; - } + if (gE('#hvAABox')) { + gE('#hvAABox').style.display = (gE('#hvAABox').style.display === 'none') ? 'block' : 'none'; + } else { + optionBox(); + gE('#hvAATab-Main').style.zIndex = 1; + gE('select[name="lang"]').value = lang; + } }; - } +} - function optionBox() { // 配置界面 +function optionBox() { // 配置界面 const optionBox = gE('body').appendChild(cE('div')); optionBox.id = 'hvAABox'; optionBox.innerHTML = [ - '
', - '

hvAutoAttack

', - ' 更新历史更新歷史ChangeLog', - ' 使用说明README', - ' ', - (g('option')?.optionStandalone? isIsekai?'当前为异世界单独配置當前為異世界單獨配置Using Isekai standalone option':'当前为恒定世界单独配置當前為恆定世界單獨配置Using Persistent standalone option':''), - ' by Koko191
', - '
', - - '
', - ' 主要选项主要選項Main', - ' 战斗开启戰鬥開啟BattleStarter', - ' 恢复技能恢復技能Recovery', - ' 引导技能引導技能Channel Spells', - ' BUFF技能 Spells', - ' DEBUFF技能 Spells', - ' 其他技能Skills', - ' 卷轴捲軸Scroll', - ' 警报警報Alarm', - ' 攻击规则攻擊規則Attack Rule', - ' 掉落监测掉落監測Drops Tracking', - ' 数据记录數據記錄Usage Tracking', - ' 工具工具Tools', - ' 反馈Feedback', - '
', - - '
', - '
异世界相关異世界相關Isekai: ', - ' ', - ' ; ', - '
在任意页面停留

在任意頁面停留

Idle in any page for
秒后,进行跳转秒後,進行跳轉s, start switch check
', - '
小马答题小馬答題RIDDLE: ; ', - '
内置插件Built-in Plugin: ;
', - '
时间時間If ETR秒,如果输入框为空则随机生成答案并提交秒,如果輸入框為空則隨機生成答案並提交s and no answer has been chosen yet, a random answer will be generated and submitted
', - '
', - '
脚本行为腳本行為Script Activity', - '
暂停相关暫停相關Pause with: ', - ' ; ', - '
', - '
警告相关警告相關To Warn: ', - ' ; ', - ' ', - '
', - '
掉落及数据记录掉落及數據記錄Drops and Usage Tracking:
', - '
延迟延遲Delay: 1. Buff/Debuff/其他技能Buff/Debuff/其他技能Skills&BUFF/DEBUFF Spells: ms 2. 其他Other: ms (', - ' 说明: 单位毫秒,且在设定值基础上取其的50%-150%进行延迟,0表示不延迟說明: 單位毫秒,且在設定值基礎上取其的50%-150%進行延遲,0表示不延遲Note: unit milliseconds, and based on the set value multiply 50% -150% to delay, 0 means no delay)
', - '
', - '
*攻击模式攻擊模式Attack Mode:', - '
', - - '
战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed):
', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - ' ', - '
', - '
使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
', - '
', - '
', - '
: {{etherTapCondition}}
', - '
: {{turnOnSSCondition}}
', - '
: {{turnOffSSCondition}}
', - '
: {{defendCondition}}
', - '
: {{focusCondition}}
', - '
: {{pauseCondition}}
', - '
: {{fleeCondition}}
', - '
', - '
继续新回合延时繼續新回合延時New round wait time: (秒)(秒)(s)
', - '
战斗结束退出延时戰鬥結束退出延時Exit battle wait time: (秒)(秒)(s)
', - '
当损失精力當損失精力If it lost Stamina: ', - ' ;', - ' ; ', - ' ', - '
', - '
战斗页面停留戰鬥頁面停留If the page for : ', - ' ; ', - ' ', - '
', - '
', - - '
', - '
', - '
;
', - ' 进行的竞技场相对应等级進行的競技場相對應等級The levels of the Arena you want to complete: ', - '
', - ' ', - '
', - ' ', - ' ', - ' ', - '
', - '
', - '
精力精力Stamina: 阈值閾值 threshold: Min(85, );
', - '
含本日自然恢复的阈值含本日自然恢復的閾值Stamina threshold with naturally recovers today.: ;
', - '
', - '
进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', - '
', - '
: ', - ' 耐久度耐久度Durability%
', - '
检查物品库存檢查物品庫存Check is item needs supply: ', - '
', - ' 体力药水體力藥水Health Potion', - ' 体力长效药體力長效藥Health Draught', - ' 体力秘药體力秘藥Health Elixir', - ' 魔力药水魔力藥水Mana Potion', - ' 魔力长效药魔力長效藥Mana Draught', - ' 魔力秘药魔力秘藥Mana Elixir', - ' 灵力药水靈力藥水Spirit Potion', - ' 灵力长效药靈力長效藥Spirit Draught', - ' 灵力秘药靈力秘藥Spirit Elixir', - ' 终极秘药終極秘藥Last Elixir', - ' 花瓶花瓶Flower Vase', - ' 泡泡糖泡泡糖Bubble-Gum', - ' 能量饮料能量飲料Energy Drink', - ' 咖啡因糖果咖啡因糖果Caffeinated Candy', - ' 火焰魔药火焰魔藥Infusion of Flames', - ' 冰冷魔药冰冷魔藥Infusion of Frost', - ' 闪电魔药閃電魔藥Infusion of Lightning', - ' 风暴魔药風暴魔藥Infusion of Storms', - ' 神圣魔药神聖魔藥Infusion of Divinity', - ' 黑暗魔药黑暗魔藥Infusion of Darkness', - ' 加速卷轴加速捲軸Scroll of Swiftness', - ' 守护卷轴守護捲軸Scroll of Protection', - ' 化身卷轴化身捲軸Scroll of the Avatar', - ' 吸收卷轴吸收捲軸Scroll of Absorption', - ' 幻影卷轴幻影捲軸Scroll of Shadows', - ' 生命卷轴生命捲軸Scroll of Life', - ' 众神卷轴眾神捲軸Scroll of the Gods', - '
', - '
', - - '
', - '
施放顺序施放順序Cast Order:
', - ' ', - '
', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - '
', - ' ', - ' ', - '
', - ' ', - ' ', - '
', - '
: {{itemHGCondition}}
', - '
: {{itemMGCondition}}
', - '
: {{itemSGCondition}}
', - '
: {{itemMysticCondition}}
', - '
: {{itemCureCondition}}
', - '
: {{itemFCCondition}}
', - '
: {{itemHPCondition}}
', - '
: {{itemHECondition}}
', - '
: {{itemMPCondition}}
', - '
: {{itemMECondition}}
', - '
: {{itemSPCondition}}
', - '
: {{itemSECondition}}
', - '
: {{itemLECondition}}
', - '
: {{itemEDCondition}}
', - '
: {{itemCCCondition}}
', - - '
', - ' 获得引导时(此时1点MP施法与150%伤害)獲得引導時(此時1點MP施法與150%傷害)During Channeling effect (1 mp spell cost and 150% spell damage):', - '
先施放引导技能先施放引導技能First cast:
', - ' 注意: 此处的施放顺序与注意: 此處的施放順序与Note: The cast order here is the same as inBUFF技能 Spells里的相同裡的相同
', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - ' ', - ' ', - '
', - '
: ', - '
施放顺序施放順序Cast Order:
', - ' ', - ' ', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - ' ', - ' ', - '
', - '
最后ReBuff: 重新施放最先消失的Buff最後ReBuff: 重新施放最先消失的BuffAt last, re-cast the spells which will expire first.
', - - '
', - '
施放顺序施放順序Cast Order: ', - '
', - ' ', - ' ', - ' ', - '
', - ' ', - ' ', - ' ', - ' ', - ' ', - '
', - '
Buff释放条件Buff釋放條件Cast spells Condition{{buffSkillCondition}}
', - '
{{buffSkillHDCondition}}
', - '
{{buffSkillMDCondition}}
', - '
{{buffSkillSDCondition}}
', - '
{{buffSkillFVCondition}}
', - '
{{buffSkillBGCondition}}
', - '
{{buffSkillPrCondition}}
', - '
{{buffSkillSLCondition}}
', - '
{{buffSkillSSCondition}}
', - '
{{buffSkillHaCondition}}
', - '
{{buffSkillAFCondition}}
', - '
{{buffSkillHeCondition}}
', - '
{{buffSkillReCondition}}
', - '
{{buffSkillSVCondition}}
', - '
{{buffSkillAbCondition}}
', - '
', - - '
', - '

', - ' 沉眠(Sl)沉眠(Sl)Sleep: ', - ' 致盲(Bl)致盲(Bl)Blind: ', - ' 缓慢(Slo)緩慢(Slo)Slow:
', - ' 陷危(Im)陷危(Im)Imperil: ', - ' 魔磁网(MN)魔磁網(MN)MagNet: ', - ' 沉默(Si)沉默(Si)Silence:
', - ' 枯竭(Dr)枯竭(Dr)Drain: ', - ' 虚弱(We)虛弱(We)Weaken: ', - ' 混乱(Co)混亂(Co)Confuse:
', - '
施放顺序施放順序Cast Order:', - '
', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '
', - '
特殊Special
{{debuffSkillWeAllCondition}}', - '
特殊Special
{{debuffSkillImAllCondition}}', - '
{{debuffSkillSleCondition}}
', - '
{{debuffSkillBlCondition}}
', - '
{{debuffSkillSloCondition}}
', - '
{{debuffSkillImCondition}}
', - '
{{debuffSkillMNCondition}}
', - '
{{debuffSkillSiCondition}}
', - '
{{debuffSkillDrCondition}}
', - '
{{debuffSkillWeCondition}}
', - '
{{debuffSkillCoCondition}}
', - '
', - - '
', - '
注意: 默认在灵动架式状态下使用,请在主要选项勾选并设置开启/关闭灵动架式注意: 默認在靈動架式狀態下使用,請在主要選項勾選並設置開啟/關閉靈動架式Note: use under Spirit by default, please check and set the Turn on/off Spirit Stance in Main
', - '
施放顺序施放順序Cast Order: ', - '
', - '
', - '
: {{skillOFCCondition}}
', - '
: {{skillFRDCondition}}
', - '
战斗风格戰鬥風格Fighting style:
', - '
:
{{skillT3Condition}}
', - '
: {{skillT2Condition}}
', - '
: {{skillT1Condition}}
', - - '
', - ' 战役模式戰役模式Battle type: ', - ' {{scrollCondition}}', - ' ', - '
{{scrollSwCondition}}
', - '
{{scrollPrCondition}}
', - '
{{scrollAvCondition}}
', - '
{{scrollAbCondition}}
', - '
{{scrollShCondition}}
', - '
{{scrollLiCondition}}
', - '
{{scrollGoCondition}}
', - - '
', - ' 自定义警报自定義警報Alarm
', - ' 注意:留空则使用默认音频,建议每个用户使用自定义音频注意:留空則使用默認音頻,建議每個用戶使用自定義音頻Note: Leave the box blank to use default audio, it\'s recommended for all user to use custom audio.', - '




', - '
请将将要测试的音频文件的地址填入这里請將將要測試的音頻文件的地址填入這裡Plz put in the audio file address you want to test:
', - - '
', - ' 攻击规则攻擊規則Attack Rule 示例Example', - '
1. 初始血量权重=Log10(目标血量/场上最低血量)初始血量權重=Log10(目標血量/場上最低血量)BaseHpWeight = BaseHpRatio*Log10(TargetHP/MaxHPOnField)
', - ' 初始权重系数(>0:低血量优先;<0:高血量优先)初始權重係數(>0:低血量優先;<0:高血量優先)BaseHpRatio(>0:low hp first;<0:high hp first)
', - ' 不可命中目标的权重不可名中目標的權重Unreachable Target Weight
', - '
', - '
2. 初始权重与下述各Buff权重相加初始權重與下述各Buff權重相加PW(X) = BaseHpWeight + Accumulated_Weight_of_Deprecating_Spells_In_Effect(X)
', - ' 虚弱(We)虛弱(We)Weaken: ', - ' 致盲(Bl)致盲(Bl)Blind: ', - ' 缓慢(Slo)緩慢(Slo)Slow: ', - ' 沉默(Si)沉默(Si)Silence: ', - ' 沉眠(Sl)沉眠(Sl)Sleep:
', - ' 陷危(Im)陷危(Im)Imperil: ', - ' 破甲(PA)破甲(PA)Penetrated Armor: ', - ' 流血(Bl)流血(Bl)Bleeding Wound:
', - ' 混乱(Co)混亂(Co)Confuse: ', - ' 枯竭(Dr)枯竭(Dr)Drain: ', - ' 魔磁网(MN)魔磁網(MN)MagNet: ', - ' 眩晕(St)眩暈(St)Stunned:
', - ' 魔力合流(CM)魔力合流(CM)Coalesced Mana:
', - '
', - '
3. PW(X) += Log10(1 + 武器攻击中央目标伤害倍率(副手及冲击技能)乘以武器攻擊中央目標傷害倍率(副手及衝擊技能)Weapon Attack Central Target Damage Ratio (Offhand & Strike))
额外伤害比例:額外傷害比例:Extra DMG Ratio: %
', - '
4. 优先选择权重最低的目标優先選擇權重最低的目標Choose target with lowest rank first
BOSS:Yggdrasil额外权重BOSS:Yggdrasil額外權重BOSS:Yggdrasil Extra Weight
', - '
显示权重及顺序顯示權重及順序DIsplay Weight and order', - ' 显示优先级背景色顯示優先級背景色DIsplay Priority Background Color', - ' CSS格式或可eval执行的公式(可用<rank>, <all>指代优先级和总优先级数量, <style_x>指代第x个的相同配置值),例如:CSS格式或可eval執行的公式(可用<rank>, <all>指代優先級和總優先級數量, <style_x>指代第x個的相同配置值):例如CSS or eval executable formula(use <rank> and <all> to refer to priority rank and total rank count, <style_x> to refer to the same option value of option No.x)Such as:
`hsl(${Math.round(240*<rank>/Math.max(1,<all>-1))}deg 50% 50%)`
', - ' 1.
', - ' 2. ', - ' 3. ', - ' 4.
', - ' 5. ', - ' 6. ', - ' 7.
', - ' 8. ', - ' 9. ', - ' 10. ', - '
', - '
PS. 如果你对各Buff权重有特别见解,请务必如果你對各Buff權重有特別見解,請務必If you have any suggestions, please 告诉我告訴我let me know.
参考公式为:參考公式為:Basic Weight Calculation as: PW(X) = Log10(
(HP/MaxHPOnField/(1+CentralAttackDamageExtraRatio)
*[HPActualEffectivenessRate:∏(1-debuff),debuff=Im|PA|Bl|Co|Dr|MN|St]
/[DMGActualEffectivenessRate:∏(1-debuff),debuff=We|Bl|Slo|Si|Sl|Co|Dr|MN|St])
)
', - '
', - - '
', - ' 掉落监测掉落監測Drops Tracking', - '
记录装备的最低品质記錄裝備的最低品質Minimum drop quality:
', - '
', - - '
', - ' 数据记录數據記錄Usage Tracking', - '
', - - '
', - '
当前状况當前狀況Current status: ', - ' 如果脚本长期暂停且网络无问题,请点击如果腳本長期暫停且網絡無問題,請點擊If the script does not work and you are sure that it\'s not because of your internet, click
', - ' 战役模式戰役模式Battle type: 当前回合當前回合Current round: 总回合總回合Total rounds:
', - '
快捷站点快捷站點Quick Site
', - ' 注意: 留空“姓名”一栏则表示删除该行,修改后请保存注意: 留空“姓名”一欄則表示刪除該行,修改後請保存Note: The "name" input box left blank will be deleted, after change please save in time.', - '
图标圖標ICON名称名稱Name链接鏈接Link
', - '
备份与还原備份與還原Backup and Restore
    ', - '
    导入与导出導入與導出Import and Export
    ', - - '
    ', - ' 反馈Feedback', - '
    链接鏈接Links: 1. GitHub2. GreasyFork
    ', - '
    反馈说明反饋說明Feedback Note:
    ', - ' 如果你遇见了Bug,想帮助作者修复它
    你应当提供以下多种资料:
    1. 场景描述
    2. 你的配置
    3. 控制台日志 (按Ctrl+Shift+i打开开发者助手,再选择Console(控制台)面板)
    4. 战斗日志 (如果是在战斗中)
    如果是无法容忍甚至使脚本失效的Bug,请尝试安装旧版本
    如果你有一些建议使这个脚本更加有用,那么:
    1. 请尽量简述你的想法
    2. 如果可以,请提供一些场景 (方便作者更好理解)
    ', - ' 如果你遇見了Bug,想幫助作者修復它
    你應當提供以下多種資料:
    1. 場景描述
    2. 你的配置
    3. 控制台日誌 (按Ctrl+Shift+i打開開發者助手,再選擇Console(控制台)面板)
    4. 戰鬥日誌 (如果是在戰鬥中)
    如果是無法容忍甚至使腳本失效的Bug,請嘗試安裝舊版本
    如果你有一些建議使這個腳本更加有用,那麼:
    1. 請盡量簡述你的想法
    2.如果可以,請提供一些場景 (方便作者更好理解)
    ', - ' If you encounter a bug and would like to help the author fix it
    You should provide the following information:
    1. the Situation
    2. Your Configuration
    3. Console Log (press Ctrl + Shift + i to open the Developer Assistant, And then select the Console panel)
    4. Battle Log (if in combat)
    If you are unable to tolerate this bug or even the bug made the script fail, try installing the old version
    If you have some suggestions to make this script more useful, then:
    1. Please briefly describe your thoughts
    2. If you can, please provide some scenes (to facilitate the author to better understand)
    PS. For English user, please express in basic English (Oh my poor English, thanks for Google Translate)
    ', - '
    ', - - '
    ', - '
    ', + '
    ', + '

    hvAutoAttack

    ', + ' 更新历史更新歷史ChangeLog', + ' 使用说明README', + ' ', + ' by Koko191
    ', + '
    ', + '
    ', + ' 主要选项主要選項Main', + ' 物品Item', + ' Channel技能 Spells', + ' BUFF技能 Spells', + ' DEBUFF技能 Spells', + ' 其他技能Skills', + ' 卷轴捲軸Scroll', + ' 魔药魔藥Infusion', + ' 警报警報Alarm', + ' 攻击规则攻擊規則Attack Rule', + ' 掉落监测掉落監測Drops Tracking', + ' 数据记录數據記錄Usage Tracking', + ' 关于本脚本關於本腳本About This', + ' 反馈Feedback
    ', + '
    ', + + '
    异世界相关異世界相關Isekai: ', + ' ', + '; ', + '
    在任意页面停留

    在任意頁面停留

    Idle in any page for
    秒后,进行跳转秒後,進行跳轉s, start switch check
    ', + + '
    ', + ' Gem: Health.%', + ' Mana.%%', + ' Spirt.%
    ', + '
    *攻击模式攻擊模式Attack Mode:', + '
    ', + '
    暂停相关暫停相關Pause with: ', + ' ; ', + '
    ', + '
    警告相关警告相關To Warn: ', + ' ; ', + ' ', + '
    ', + '
    内置插件Built-in Plugin: ', + ' ; ', + '
    ', + '
    魔法技能Offensive Magic:
    ', + ' 中阶技能使用条件中階技能使用條件Conditions for 2nd Tier: {{middleSkillCondition}}', + ' 高阶技能使用条件高階技能使用條件Conditions for 3rd Tier: {{highSkillCondition}}
    ', + '
    : {{turnOnSSCondition}}
    ', + '
    : {{turnOffSSCondition}}
    ', + '
    : {{defendCondition}}
    ', + '
    : {{focusCondition}}
    ', + '
    If the page 页面停留頁面停留stays idle for : ', + ' ; ', + '
    ', + '
    小马答题时间小馬答題時間If RIDDLE ETR秒,如果输入框为空则随机生成答案并提交秒,如果輸入框為空則隨機生成答案並提交s and no answer has been chosen yet, a random answer will be generated and submitted
    ', + '
    小马答题小馬答題If RIDDLE: ', + ' ;
    ', + '
    Stamina: 当损失當損失If it lost Stamina ≥ : ', + ' ; ', + ' ; ', + ' ', + '
    ', + '
    ;
    ', + ' 进行的竞技场相对应等级進行的競技場相對應等級The levels of the Arena you want to complete: ', + '
    ', + ' ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    : ', + ' 耐久度耐久度Durability%
    ', + '
    : {{etherTapCondition}}
    ', + '
    : {{fleeCondition}}
    ', + '
    : {{pauseCondition}}
    ', + '

    ', + ' 说明: 如果不勾选,当Stamina小于此值后,则不进行闲置竞技场說明: 如果不勾選,當Stamina小於此值後,則不進行閒置競技場Note: If unchecked, when Stamina is less than this value, no Idle Arena
    ', + '
    ', + '
    延迟延遲Delay: 1. 其他/Buff/Debuff技能其他/Buff/Debuff技能Skills&BUFF/DEBUFF Spells: ms 2. 其他Other: ms
    ', + ' 说明: 单位毫秒,且在设定值基础上取其的50%-150%进行延迟,0表示不延迟說明: 單位毫秒,且在設定值基礎上取其的50%-150%進行延遲,0表示不延遲Note: unit milliseconds, and based on the set value multiply 50% -150% to delay, 0 means no delay', + '
    ', + '
    ', + '
    ', + '
    施放顺序施放順序Cast Order:
    ', + '
    ', + '
    ', + '
    : {{itemCureCondition}}
    ', + '
    : {{itemFCCondition}}
    ', + '
    : {{itemHPCondition}}
    ', + '
    : {{itemHECondition}}
    ', + '
    : {{itemMPCondition}}
    ', + '
    : {{itemMECondition}}
    ', + '
    : {{itemSPCondition}}
    ', + '
    : {{itemSECondition}}
    ', + '
    : {{itemLECondition}}
    ', + '
    : {{itemEDCondition}}
    ', + '
    ', + ' 获得Channel时(此时1点MP施法与150%伤害)獲得Channel時(此時1點MP施法與150%傷害)During Channeling effect (1 mp spell cost and 150% spell damage):', + '
    先施放Channel技能先施放Channel技能First cast:
    ', + ' 注意: 此处的施放顺序与注意: 此處的施放順序与Note: The cast order here is the same as inBUFF技能 Spells里的相同裡的相同
    ', + '
    ', + '
    ', + '
    : ', + '
    施放顺序施放順序Cast Order:
    ', + '
    ', + '
    ', + '
    最后ReBuff: 重新施放最先消失的Buff最後ReBuff: 重新施放最先消失的BuffAt last, re-cast the spells which will expire first.
    ', + '
    {{buffSkillCondition}}', + '
    施放顺序施放順序Cast Order: ', + '
    ', + '
    ', + '
    ', + '
    Buff不存在就施放的技能Buff不存在就施放的技能Cast spells if the buff is not present: ', + '
    {{buffSkillHDCondition}}
    ', + '
    {{buffSkillMDCondition}}
    ', + '
    {{buffSkillSDCondition}}
    ', + '
    {{buffSkillFVCondition}}
    ', + '
    {{buffSkillBGCondition}}
    ', + '
    {{buffSkillPrCondition}}
    ', + '
    {{buffSkillSLCondition}}
    ', + '
    {{buffSkillSSCondition}}
    ', + '
    {{buffSkillHaCondition}}
    ', + '
    {{buffSkillAFCondition}}
    ', + '
    {{buffSkillHeCondition}}
    ', + '
    {{buffSkillReCondition}}
    ', + '
    {{buffSkillSVCondition}}
    ', + '
    {{buffSkillAbCondition}}
    ', + '
    ', + '
    施放顺序施放順序Cast Order:', + '
    ', + '
    ', + '
    ', + '
    特殊Special
    {{debuffSkillImAllCondition}}', + '
    特殊Special
    {{debuffSkillWeAllCondition}}', + '
    {{debuffSkillSleCondition}}
    ', + '
    {{debuffSkillBlCondition}}
    ', + '
    {{debuffSkillSloCondition}}
    ', + '
    {{debuffSkillImCondition}}
    ', + '
    {{debuffSkillMNCondition}}
    ', + '
    {{debuffSkillSiCondition}}
    ', + '
    {{debuffSkillDrCondition}}
    ', + '
    {{debuffSkillWeCondition}}
    ', + '
    {{debuffSkillCoCondition}}
    ', + '
    持续持續Expire Turns:
    ', + ' Sleep: Blind: Slow:
    ', + ' Imperil: MagNet: Silence:
    ', + ' Drain: Weaken: Confuse:
    ', + '
    ', + '
    注意: 默认在Spirit状态下使用,请在主要选项勾选并设置开启/关闭Spirit Stance注意: 默認在Spirit狀態下使用,請在主要選項勾選並設置開啟/關閉Spirit StanceNote: use under Spirit by default, please check and set the Turn on/off Spirit Stance in Main
    ', + '
    施放顺序施放順序Cast Order: ', + '
    ', + '
    ', + '
    : {{skillOFCCondition}}
    ', + '
    : {{skillFRDCondition}}
    ', + '
    战斗风格戰鬥風格Fighting style:
    ', + '
    :
    {{skillT3Condition}}
    ', + '
    : {{skillT2Condition}}
    ', + '
    : {{skillT1Condition}}
    ', + '
    ', + ' 战役模式戰役模式Battle type: ', + ' {{scrollCondition}}', + ' ', + '
    {{scrollGoCondition}}
    ', + '
    {{scrollAvCondition}}
    ', + '
    {{scrollPrCondition}}
    ', + '
    {{scrollSwCondition}}
    ', + '
    {{scrollLiCondition}}
    ', + '
    {{scrollShCondition}}
    ', + '
    {{scrollAbCondition}}
    ', + '
    ', + ' 注意:魔药属性与注意:魔藥屬性與Note: The style of infusion is the same as Attack Mode in 主要选项主要選項Main里的攻击模式相同裡的攻擊模式相同
    {{infusionCondition}}
    ', + '
    ', + ' 自定义警报自定義警報Alarm
    ', + ' 注意:留空则使用默认音频,建议每个用户使用自定义音频注意:留空則使用默認音頻,建議每個用戶使用自定義音頻Note: Leave the box blank to use default audio, it\'s recommended for all user to use custom audio.', + '




    ', + '
    请将将要测试的音频文件的地址填入这里請將將要測試的音頻文件的地址填入這裡Plz put in the audio file address you want to test:
    ', + '
    ', + ' 攻击规则攻擊規則Attack Rule 示例Example', + '
    1. 每回合计算敌人当前血量,血量最低的设置初始血量为10,其他敌人为当前血量倍数*10每回合計算敌人當前血量,血量最低的設置初始血量為10,其他敌人為當前血量倍數*10Each enemiy is assigned a number which is used to determine the target to attack, let\'s call that number Priority Weight or PW.
    ', + '
    2. 初始权重与下述各Buff权重相加初始權重與下述各Buff權重相加PW(X) = 10 * HP(X) / Min_HP + Accumulated_Weight_of_Deprecating_Spells_In_Effect(X)
    ', + ' Sleep: Blind: Slow: Imperil:
    ', + ' MagNet: Silence: Drain: Weaken:
    ', + ' Confuse: Coalesced Mana:
    ', + ' Stunned: Penetrated Armor: Bleeding Wound:
    ', + '
    3.
    ', + '
    PS. 如果你对各Buff权重有特别见解,请务必如果你對各Buff權重有特別見解,請務必If you have any suggestions, please 告诉我告訴我let me know.
    ', + '
    ', + ' 掉落监测掉落監測Drops Tracking', + '
    记录装备的最低品质記錄裝備的最低品質Minimum drop quality:
    ', + '
    ', + '
    ', + ' 数据记录數據記錄Usage Tracking', + '
    ', + '
    ', + '
    当前状况當前狀況Current status: ', + ' 如果脚本长期暂停且网络无问题,请点击如果腳本長期暫停且網絡無問題,請點擊If the script does not work and you are sure that it\'s not because of your internet, click
    ', + ' 战役模式戰役模式Battle type: 当前回合當前回合Current round: 总回合總回合Total rounds:
    ', + '
    快捷站点快捷站點Quick Site
    ', + ' 注意: 留空“姓名”一栏则表示删除该行,修改后请保存注意: 留空“姓名”一欄則表示刪除該行,修改後請保存Note: The "name" input box left blank will be deleted, after change please save in time.', + '
    图标圖標ICON名称名稱Name链接鏈接Link
    ', + '
    备份与还原備份與還原Backup and Restore
      ', + '
      导入与导出導入與導出Import and Export
      ', + '
      ', + ' 反馈Feedback', + '
      链接鏈接Links: 1. GitHub2. GreasyFork
      ', + '
      反馈说明反饋說明Feedback Note:
      ', + ' 如果你遇见了Bug,想帮助作者修复它
      你应当提供以下多种资料:
      1. 场景描述
      2. 你的配置
      3. 控制台日志 (按Ctrl+Shift+i打开开发者助手,再选择Console(控制台)面板)
      4. 战斗日志 (如果是在战斗中)
      如果是无法容忍甚至使脚本失效的Bug,请尝试安装旧版本
      如果你有一些建议使这个脚本更加有用,那么:
      1. 请尽量简述你的想法
      2. 如果可以,请提供一些场景 (方便作者更好理解)
      ', + ' 如果你遇見了Bug,想幫助作者修復它
      你應當提供以下多種資料:
      1. 場景描述
      2. 你的配置
      3. 控制台日誌 (按Ctrl+Shift+i打開開發者助手,再選擇Console(控制台)面板)
      4. 戰鬥日誌 (如果是在戰鬥中)
      如果是無法容忍甚至使腳本失效的Bug,請嘗試安裝舊版本
      如果你有一些建議使這個腳本更加有用,那麼:
      1. 請盡量簡述你的想法
      2.如果可以,請提供一些場景 (方便作者更好理解)
      ', + ' If you encounter a bug and would like to help the author fix it
      You should provide the following information:
      1. the Situation
      2. Your Configuration
      3. Console Log (press Ctrl + Shift + i to open the Developer Assistant, And then select the Console panel)
      4. Battle Log (if in combat)
      If you are unable to tolerate this bug or even the bug made the script fail, try installing the old version
      If you have some suggestions to make this script more useful, then:
      1. Please briefly describe your thoughts
      2. If you can, please provide some scenes (to facilitate the author to better understand)
      PS. For English user, please express in basic English (Oh my poor English, thanks for Google Translate)
      ', + '
      ', + '
      ', + '
      ', ].join('').replace(/{{(.*?)}}/g, '
      '); // 绑定事件 gE('select[name="lang"]', optionBox).onchange = function () { // 选择语言 - gE('.hvAA-LangStyle').textContent = `l${this.value}{display:inline!important;}`; - if (/^[01]$/.test(this.value)) { - gE('.hvAA-LangStyle').textContent += 'l01{display:inline!important;}'; - } - g('lang', this.value); + gE('.hvAA-LangStyle').textContent = `l${this.value}{display:inline!important;}`; + if (/^[01]$/.test(this.value)) gE('.hvAA-LangStyle').textContent += 'l01{display:inline!important;}'; + g('lang', this.value); }; gE('.hvAATabmenu', optionBox).onclick = function (e) { // 标签页事件 - if (e.target.tagName === 'INPUT') { - return; - } - const target = (e.target.tagName === 'SPAN') ? e.target : e.target.parentNode; - const name = target.getAttribute('name'); - let i; let - _html; - if (name === 'Drop') { // 掉落监测 - let drop = getValue('drop', true) || {}; - const dropOld = getValue('dropOld', true) || []; - drop = objSort(drop); - _html = ''; - if (dropOld.length === 0 || (dropOld.length === 1 && !getValue('drop', true))) { - if (dropOld.length === 1) { - drop = dropOld[0]; - } - _html = `${_html}数量數量Amount`; - for (i in drop) { - _html = `${_html}${i}${drop[i]}`; - } - } else { - if (getValue('drop')) { - drop.__name = getValue('battleCode'); - dropOld.push(drop); - } - dropOld.reverse(); - _html = `${_html}`; - dropOld.forEach((_dropOld) => { - _html = `${_html}${_dropOld.__name}`; - }); - _html = `${_html}`; - getKeys(dropOld).forEach((key) => { - if (key === '__name') { - return; + if (e.target.tagName === 'INPUT') return; + const target = (e.target.tagName === 'SPAN') ? e.target : e.target.parentNode; + const name = target.getAttribute('name'); + let i; let + _html; + if (name === 'Drop') { // 掉落监测 + let drop = getValue('drop', true) || {}; + const dropOld = getValue('dropOld', true) || []; + drop = objSort(drop); + _html = ''; + if (dropOld.length === 0 || (dropOld.length === 1 && !getValue('drop', true))) { + if (dropOld.length === 1) drop = dropOld[0]; + _html = `${_html}数量數量Amount`; + for (i in drop) { + _html = `${_html}${i}${drop[i]}`; + } + } else { + if (getValue('drop')) { + drop.__name = getValue('battleCode'); + dropOld.push(drop); + } + dropOld.reverse(); + _html = `${_html}`; + dropOld.forEach((_dropOld) => { + _html = `${_html}${_dropOld.__name}`; + }); + _html = `${_html}`; + getKeys(dropOld).forEach((key) => { + if (key === '__name') return; + _html = `${_html}${key}`; + dropOld.forEach((_dropOld) => { + if (key in _dropOld) { + _html = `${_html}${_dropOld[key]}`; + } else { + _html = `${_html}`; + } + }); + _html = `${_html}`; + }); } - _html = `${_html}${key}`; - dropOld.forEach((_dropOld) => { - if (key in _dropOld) { - _html = `${_html}${_dropOld[key]}`; - } else { - _html = `${_html}`; - } + _html = `${_html}`; + gE('#hvAATab-Drop>table').innerHTML = _html; + } else if (name === 'Usage') { // 数据记录 + let stats = getValue('stats', true) || {}; + const statsOld = getValue('statsOld', true) || []; + const translation = { + self: '自身 (次数)自身 (次數)Self (Frequency)', + restore: '回复 (总量)回复 (總量)Restore (Amount)', + items: '物品 (次数)物品 (次數)Items (Frequency)', + magic: '技能 (次数)技能 (次數)Magic (Frequency)', + damage: '伤害 (总量)傷害 (總量)Damage (Amount)', + hurt: '受伤 (总量)受傷 (總量)Loss (Amount)', + proficiency: '熟练度 (总量)熟練度 (總量)Proficiency (Amount)', + }; + _html = ''; + if (statsOld.length === 0 || (statsOld.length === 1 && !getValue('stats', true))) { + if (statsOld.length === 1) stats = statsOld[0]; + for (i in stats) { + _html = `${_html}${translation[i]}Value`; + stats[i] = objSort(stats[i]); + for (const j in stats[i]) { + _html = `${_html}${j}${stats[i][j]}`; + } + } + } else { + if (getValue('stats')) { + stats.__name = getValue('battleCode'); + statsOld.push(stats); + } + statsOld.reverse(); + _html = `${_html}`; + statsOld.forEach((_dropOld) => { + _html = `${_html}${_dropOld.__name}`; + }); + _html = `${_html}`; + Object.keys(translation).forEach((i) => { + if (i === '__name') return; + _html = `${_html}${translation[i]}`; + getKeys(statsOld, i).forEach((key) => { + _html = `${_html}${key}`; + statsOld.forEach((_statsOld) => { + if (key in _statsOld[i]) { + _html = `${_html}${_statsOld[i][key]}`; + } else { + _html = `${_html}`; + } + }); + }); + }); + } + _html = `${_html}`; + gE('#hvAATab-Usage>table').innerHTML = _html; + } else if (name === 'About') { // 关于本脚本 + gE('.hvAADebug', 'all', optionBox).forEach((input) => { + if (getValue(input.name)) input.value = getValue(input.name); }); - _html = `${_html}`; - }); } - _html = `${_html}`; - gE('#hvAATab-Drop>table').innerHTML = _html; - } else if (name === 'Usage') { // 数据记录 - let stats = getValue('stats', true) || {}; - const statsOld = getValue('statsOld', true) || []; - const translation = { - self: '自身 (次数)自身 (次數)Self (Frequency)', - restore: '回复 (总量)回复 (總量)Restore (Amount)', - items: '物品 (次数)物品 (次數)Items (Frequency)', - magic: '技能 (次数)技能 (次數)Magic (Frequency)', - damage: '伤害 (总量)傷害 (總量)Damage (Amount)', - hurt: '受伤 (总量)受傷 (總量)Loss (Amount)', - proficiency: '熟练度 (总量)熟練度 (總量)Proficiency (Amount)', - }; - _html = ''; - if (statsOld.length === 0 || (statsOld.length === 1 && !getValue('stats', true))) { - if (statsOld.length === 1) { - stats = statsOld[0]; - } - for (i in stats) { - _html = `${_html}${translation[i]}Value`; - stats[i] = objSort(stats[i]); - for (const j in stats[i]) { - _html = `${_html}${j}${stats[i][j]}`; - } - } - } else { - if (getValue('stats')) { - stats.__name = getValue('battleCode'); - statsOld.push(stats); - } - statsOld.reverse(); - _html = `${_html}`; - statsOld.forEach((_dropOld) => { - _html = `${_html}${_dropOld.__name}`; - }); - _html = `${_html}`; - Object.keys(translation).forEach((i) => { - if (i === '__name') { - return; - } - _html = `${_html}${translation[i]}`; - getKeys(statsOld, i).forEach((key) => { - _html = `${_html}${key}`; - statsOld.forEach((_statsOld) => { - if (key in _statsOld[i]) { - _html = `${_html}${_statsOld[i][key]}`; - } else { - _html = `${_html}`; - } - }); + if (name === 'Drop' || name === 'Usage') { + gE('.selectTable', 'all', optionBox).forEach((i) => { + i.onclick = null; + i.onclick = function (e) { + const select = window.getSelection(); + select.removeAllRanges(); + const range = document.createRange(); + range.selectNodeContents(e.target.parentNode.parentNode.parentNode); + select.addRange(range); + }; }); - }); } - _html = `${_html}`; - gE('#hvAATab-Usage>table').innerHTML = _html; - } else if (name === 'Tools') { // 关于本脚本 - gE('.hvAADebug', 'all', optionBox).forEach((input) => { - if(getValue('battle') && getValue('battle')[input.name]){ - input.value = getValue('battle')[input.name]; - } else if (getValue(input.name)) { - input.value = getValue(input.name); - } - }); - } else if (name === 'Drop' || name === 'Usage') { - gE('.selectTable', 'all', optionBox).forEach((i) => { - i.onclick = null; - i.onclick = function (e) { - const select = window.getSelection(); - select.removeAllRanges(); - const range = document.createRange(); - range.selectNodeContents(e.target.parentNode.parentNode.parentNode); - select.addRange(range); - }; + gE('.hvAATab', 'all', optionBox).forEach((i) => { + i.style.display = (i.id === `hvAATab-${name}`) ? 'block' : 'none'; }); - } - gE('.hvAATab', 'all', optionBox).forEach((i) => { - i.style.display = (i.id === `hvAATab-${name}`) ? 'block' : 'none'; - }); }; gE('.hvAAGoto', 'all', optionBox).forEach((i) => { - i.onclick = function () { - gE(`.hvAATabmenu>span[name="${this.name.replace('hvAATab-', '')}"]`).click(); - }; + i.onclick = function () { + gE(`.hvAATabmenu>span[name="${this.name.replace('hvAATab-', '')}"]`).click(); + }; }); function updateGroup() { - const group = gE('.customizeGroup', 'all', g('customizeTarget')); - const customizeBox = gE('.customizeBox'); - if (group.length + 1 === gE('select[name="groupChoose"]>option', 'all', customizeBox).length) { - return; - } - gE('select[name="groupChoose"]', customizeBox).textContent = ''; - for (let i = 0; i <= group.length; i++) { - const option = gE('select[name="groupChoose"]', customizeBox).appendChild(cE('option')); - if (i === group.length) { - option.value = 'new'; - option.textContent = 'new'; - } else { - option.value = i + 1; - option.textContent = i + 1; + const group = gE('.customizeGroup', 'all', g('customizeTarget')); + const customizeBox = gE('.customizeBox'); + if (group.length + 1 === gE('select[name="groupChoose"]>option', 'all', customizeBox).length) return; + gE('select[name="groupChoose"]', customizeBox).textContent = ''; + for (let i = 0; i <= group.length; i++) { + const option = gE('select[name="groupChoose"]', customizeBox).appendChild(cE('option')); + if (i === group.length) { + option.value = 'new'; + option.textContent = 'new'; + } else { + option.value = i + 1; + option.textContent = i + 1; + } } - } } optionBox.onmousemove = function (e) { // 自定义条件相关事件 - const target = (e.target.className === 'customize') ? e.target : (e.target.parentNode.className === 'customize') ? e.target.parentNode : e.target.parentNode.parentNode; - if (!gE('.customizeBox')) { - customizeBox(); - } - updateGroup(); - if (target.className !== 'customize' && target.parentNode.className !== 'customize') { - if (!target.className.match('customize')) { - gE('.customizeBox').style.zIndex = -1; - } - return; - } - g('customizeTarget', target); - const position = target.getBoundingClientRect(); - gE('.customizeBox').style.zIndex = 5; - gE('.customizeBox').style.top = `${position.bottom + window.scrollY}px`; - gE('.customizeBox').style.left = `${position.left + window.scrollX}px`; + const target = (e.target.className === 'customize') ? e.target : (e.target.parentNode.className === 'customize') ? e.target.parentNode : e.target.parentNode.parentNode; + if (!gE('.customizeBox')) customizeBox(); + updateGroup(); + if (target.className !== 'customize' && target.parentNode.className !== 'customize') { + if (!target.className.match('customize')) gE('.customizeBox').style.zIndex = -1; + return; + } + g('customizeTarget', target); + const position = target.getBoundingClientRect(); + gE('.customizeBox').style.zIndex = 5; + gE('.customizeBox').style.top = `${position.bottom + window.scrollY}px`; + gE('.customizeBox').style.left = `${position.left + window.scrollX}px`; }; // 标签页-主要选项 gE('input[name="pauseHotkeyStr"]', optionBox).onkeyup = function (e) { - this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; - gE('input[name="pauseHotkeyCode"]', optionBox).value = e.keyCode; + this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; + gE('input[name="pauseHotkeyCode"]', optionBox).value = e.keyCode; }; gE('.testNotification', optionBox).onclick = function () { - _alert(0, '接下来开始预处理。\n如果询问是否允许,请选择允许', '接下來開始預處理。\n如果詢問是否允許,請選擇允許', 'Now, pretreat.\nPlease allow to receive notifications if you are asked for permission'); - setNotification('Test'); + _alert(0, '接下来开始预处理。\n如果询问是否允许,请选择允许', '接下來開始預處理。\n如果詢問是否允許,請選擇允許', 'Now, pretreat.\nPlease allow to receive notifications if you are asked for permission'); + setNotification('Test'); }; gE('.testPopup', optionBox).onclick = function () { - _alert(0, '接下来开始预处理。\n关闭本警告框之后,请切换到其他标签页,\n并在足够长的时间后再打开本标签页', '接下來開始預處理。\n關閉本警告框之後,請切換到其他標籤頁,\n並在足夠長的時間後再打開本標籤頁', 'Now, pretreat.\nAfter dismissing this alert, focus other tab,\nfocus this tab again after long time.'); - setTimeout(() => { - const riddleWindow = window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); - if (riddleWindow) { - setTimeout(() => { - riddleWindow.close(); - }, 200); - } - }, 3000); + _alert(0, '接下来开始预处理。\n关闭本警告框之后,请切换到其他标签页,\n并在足够长的时间后再打开本标签页', '接下來開始預處理。\n關閉本警告框之後,請切換到其他標籤頁,\n並在足夠長的時間後再打開本標籤頁', 'Now, pretreat.\nAfter dismissing this alert, focus other tab,\nfocus this tab again after long time.'); + setTimeout(() => { + const riddleWindow = window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); + if (riddleWindow) { + setTimeout(() => { + riddleWindow.close(); + }, 200); + } + }, 3000); }; gE('.staminaLostLog', optionBox).onclick = function () { - const out = []; - const staminaLostLog = getValue('staminaLostLog', true); - for (const i in staminaLostLog) { - out.push(`${i}: ${staminaLostLog[i]}`); - } - if (window.confirm(`总共${out.length}条记录 (There are ${out.length} logs): \n${out.reverse().join('\n')}\n是否重置 (Whether to reset)?`)) { - setValue('staminaLostLog', {}); - } + const out = []; + const staminaLostLog = getValue('staminaLostLog', true); + for (const i in staminaLostLog) { + out.push(`${i}: ${staminaLostLog[i]}`); + } + if (window.confirm(`总共${out.length}条记录 (There are ${out.length} logs): \n${out.reverse().join('\n')}\n是否重置 (Whether to reset)?`)) setValue('staminaLostLog', {}); }; gE('.idleArenaReset', optionBox).onclick = function () { - if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { - delValue('arena'); - } + if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) delValue('arena'); }; gE('.hvAAShowLevels', optionBox).onclick = function () { - gE('.hvAAArenaLevels').style.display = (gE('.hvAAArenaLevels').style.display === 'grid') ? 'none' : 'grid'; + gE('.hvAAArenaLevels').style.display = (gE('.hvAAArenaLevels').style.display === 'block') ? 'none' : 'block'; }; gE('.hvAALevelsClear', optionBox).onclick = function () { - gE('[name="idleArenaLevels"]', optionBox).value = ''; - gE('[name="idleArenaValue"]', optionBox).value = ''; - gE('.hvAAArenaLevels>input', 'all', optionBox).forEach((input) => { - input.checked = false; - }); + gE('[name="idleArenaLevels"]', optionBox).value = ''; + gE('[name="idleArenaValue"]', optionBox).value = ''; + gE('.hvAAArenaLevels>input', 'all', optionBox).forEach((input) => { + input.checked = false; + }); }; gE('.hvAAArenaLevels', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const valueArray = e.target.value.split(','); - let levels = gE('input[name="idleArenaLevels"]').value; - let { value } = gE('input[name="idleArenaValue"]'); - if (e.target.checked) { - levels = levels + ((levels) ? `,${valueArray[0]}` : valueArray[0]); - value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); - } else { - levels = levels.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); - value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="idleArenaLevels"]').value = levels; - gE('input[name="idleArenaValue"]').value = value; - }; - - gE('.battleOrder', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const valueArray = e.target.value.split(','); - let name = gE('input[name="battleOrderName"]').value; - // let { value } = gE('input[name="battleOrderValue"]'); - if (e.target.checked) { - name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); - // value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); - } else { - name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); - // value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="battleOrderName"]').value = name; - // gE('input[name="battleOrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const valueArray = e.target.value.split(','); + let levels = gE('input[name="idleArenaLevels"]').value; + let { value } = gE('input[name="idleArenaValue"]'); + if (e.target.checked) { + levels = levels + ((levels) ? `,${valueArray[0]}` : valueArray[0]); + value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); + } else { + levels = levels.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); + value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="idleArenaLevels"]').value = levels; + gE('input[name="idleArenaValue"]').value = value; }; - // 标签页-物品 gE('.itemOrder', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const valueArray = e.target.value.split(','); - let name = gE('input[name="itemOrderName"]').value; - let { value } = gE('input[name="itemOrderValue"]'); - if (e.target.checked) { - name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); - value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); - } else { - name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); - value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="itemOrderName"]').value = name; - gE('input[name="itemOrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const valueArray = e.target.value.split(','); + let name = gE('input[name="itemOrderName"]').value; + let { value } = gE('input[name="itemOrderValue"]'); + if (e.target.checked) { + name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); + value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); + } else { + name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); + value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="itemOrderName"]').value = name; + gE('input[name="itemOrderValue"]').value = value; }; // 标签页-Channel技能 gE('.channelSkill2Order', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const valueArray = e.target.value.split(','); - let name = gE('input[name="channelSkill2OrderName"]').value; - let { value } = gE('input[name="channelSkill2OrderValue"]'); - if (e.target.checked) { - name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); - value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); - } else { - name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); - value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="channelSkill2OrderName"]').value = name; - gE('input[name="channelSkill2OrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const valueArray = e.target.value.split(','); + let name = gE('input[name="channelSkill2OrderName"]').value; + let { value } = gE('input[name="channelSkill2OrderValue"]'); + if (e.target.checked) { + name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); + value = value + ((value) ? `,${valueArray[1]}` : valueArray[1]); + } else { + name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); + value = value.replace(new RegExp(`(^|,)${valueArray[1]}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="channelSkill2OrderName"]').value = name; + gE('input[name="channelSkill2OrderValue"]').value = value; }; // 标签页-BUFF技能 gE('.buffSkillOrder', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const name = e.target.id.match(/_(.*)/)[1]; - let { value } = gE('input[name="buffSkillOrderValue"]'); - if (e.target.checked) { - value = value + ((value) ? `,${name}` : name); - } else { - value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="buffSkillOrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const name = e.target.id.match(/_(.*)/)[1]; + let { value } = gE('input[name="buffSkillOrderValue"]'); + if (e.target.checked) { + value = value + ((value) ? `,${name}` : name); + } else { + value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="buffSkillOrderValue"]').value = value; }; // 标签页-DEBUFF技能 gE('.debuffSkillOrder', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const name = e.target.id.match(/_(.*)/)[1]; - let { value } = gE('input[name="debuffSkillOrderValue"]'); - if (e.target.checked) { - value = value + ((value) ? `,${name}` : name); - } else { - value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="debuffSkillOrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const name = e.target.id.match(/_(.*)/)[1]; + let { value } = gE('input[name="debuffSkillOrderValue"]'); + if (e.target.checked) { + value = value + ((value) ? `,${name}` : name); + } else { + value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="debuffSkillOrderValue"]').value = value; }; // 标签页-其他技能 gE('.skillOrder', optionBox).onclick = function (e) { - if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { - return; - } - const name = e.target.id.match(/_(.*)/)[1]; - let { value } = gE('input[name="skillOrderValue"]'); - if (e.target.checked) { - value = value + ((value) ? `,${name}` : name); - } else { - value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); - } - gE('input[name="skillOrderValue"]').value = value; + if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') return; + const name = e.target.id.match(/_(.*)/)[1]; + let { value } = gE('input[name="skillOrderValue"]'); + if (e.target.checked) { + value = value + ((value) ? `,${name}` : name); + } else { + value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="skillOrderValue"]').value = value; }; // 标签页-警报 gE('input[name="audio_Text"]', optionBox).onchange = function () { - if (this.value === '') { - return; - } - if (!/^http(s)?:|^ftp:|^data:audio/.test(this.value)) { - _alert(0, '地址必须以"http:","https:","ftp:","data:audio"开头', '地址必須以"http:","https:","ftp:","data:audio"開頭', 'The address must start with "http:", "https:", "ftp:", and "data:audio"'); - return; - } - _alert(0, '接下来将测试该音频\n如果该音频无法播放或无法载入,请变更\n请测试完成后再键入另一个音频', '接下來將測試該音頻\n如果該音頻無法播放或無法載入,請變更\n請測試完成後再鍵入另一個音頻', 'The audio will be tested after you close this prompt\nIf the audio doesn\'t load or play, change the url'); - const box = gE('#hvAATab-Alarm').appendChild(cE('div')); - box.innerHTML = this.value; - const audio = box.appendChild(cE('audio')); - audio.controls = true; - audio.src = this.value; - audio.play(); - }; - // 标签页-攻击规则 - gE('.clearMonsterHPCache', optionBox).onclick = function () { - delValue('monsterDB'); - delValue('monsterMID'); + if (this.value === '') return; + if (!/^http(s)?:|^ftp:|^data:audio/.test(this.value)) { + _alert(0, '地址必须以"http:","https:","ftp:","data:audio"开头', '地址必須以"http:","https:","ftp:","data:audio"開頭', 'The address must start with "http:", "https:", "ftp:", and "data:audio"'); + return; + } + _alert(0, '接下来将测试该音频\n如果该音频无法播放或无法载入,请变更\n请测试完成后再键入另一个音频', '接下來將測試該音頻\n如果該音頻無法播放或無法載入,請變更\n請測試完成後再鍵入另一個音頻', 'The audio will be tested after you close this prompt\nIf the audio doesn\'t load or play, change the url'); + const box = gE('#hvAATab-Alarm').appendChild(cE('div')); + box.innerHTML = this.value; + const audio = box.appendChild(cE('audio')); + audio.controls = true; + audio.src = this.value; + audio.play(); }; // 标签页-掉落监测 gE('.reDropMonitor', optionBox).onclick = function () { - if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { - delValue('drop'); - delValue('dropOld'); - } + if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { + delValue('drop'); + delValue('dropOld'); + } }; // 标签页-数据记录 gE('.reRecordUsage', optionBox).onclick = function () { - if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { - delValue('stats'); - delValue('statsOld'); - } + if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { + delValue('stats'); + delValue('statsOld'); + } }; // 标签页-关于本脚本 gE('.hvAAFix', optionBox).onclick = function () { - gE('.hvAADebug[name^="round"]', 'all', optionBox).forEach((input) => { - setValue(input.name, input.value || input.placeholder); - }); + gE('.hvAADebug[name^="round"]', 'all', optionBox).forEach((input) => { + setValue(input.name, input.value || input.placeholder); + }); }; gE('.quickSiteAdd', optionBox).onclick = function () { - const tr = gE('.hvAAQuickSite>table>tbody', optionBox).appendChild(cE('tr')); - tr.innerHTML = ''; + const tr = gE('.hvAAQuickSite>table>tbody', optionBox).appendChild(cE('tr')); + tr.innerHTML = ''; }; gE('.hvAAConfig', optionBox).onclick = function () { - this.style.height = 0; - this.style.height = `${this.scrollHeight}px`; - this.select(); + this.style.height = 0; + this.style.height = `${this.scrollHeight}px`; + this.select(); }; function rmListItem(code) { // 同步删除界面显示对应的项 - const configs = gE('#hvAATab-Tools > * > ul[class="hvAABackupList"] > li', 'all'); - for (const config of configs) { - if (config.textContent == code) { - config.remove(); + const configs = gE('#hvAATab-About > * > ul[class="hvAABackupList"] > li', 'all'); + for (const config of configs) { + if (config.textContent == code) { + config.remove(); + } } - } } gE('.hvAABackup', optionBox).onclick = function () { - const code = _alert(2, '请输入当前配置代号', '請輸入當前配置代號', 'Please put in a name for the current configuration') || time(3); - const backups = getValue('backup', true) || {}; - if (code in backups) { // 覆写同名配置 - if (_alert(1, '是否覆盖已有的同名配置?', '是否覆蓋已有的同名配置?', 'Do you want to overwrite the configuration with the same name?')) { - delete backups[code]; - rmListItem(code); - } else return; - } - backups[code] = getValue('option'); - setValue('backup', backups); - const li = gE('.hvAABackupList', optionBox).appendChild(cE('li')); - li.textContent = code; + const code = _alert(2, '请输入当前配置代号', '請輸入當前配置代號', 'Please put in a name for the current configuration') || time(3); + const backups = getValue('backup', true) || {}; + if (code in backups) { // 覆写同名配置 + if (_alert(1, '是否覆盖已有的同名配置?', '是否覆蓋已有的同名配置?', 'Do you want to overwrite the configuration with the same name?')) { + delete backups[code]; + rmListItem(code); + } else return; + } + backups[code] = getValue('option'); + setValue('backup', backups); + const li = gE('.hvAABackupList', optionBox).appendChild(cE('li')); + li.textContent = code; }; gE('.hvAARestore', optionBox).onclick = function () { - const code = _alert(2, '请输入配置代号', '請輸入配置代號', 'Please put in a name for a configuration'); - const backups = getValue('backup', true) || {}; - if (!(code in backups) || !code) { - return; - } - setValue('option', backups[code]); - goto(); + const code = _alert(2, '请输入配置代号', '請輸入配置代號', 'Please put in a name for a configuration'); + const backups = getValue('backup', true) || {}; + if (!(code in backups) || !code) return; + setValue('option', backups[code]); + goto(); }; gE('.hvAADelete', optionBox).onclick = function () { - const code = _alert(2, '请输入配置代号', '請輸入配置代號', 'Please put in a name for a configuration'); - const backups = getValue('backup', true) || {}; - if (!(code in backups) || !code) { - return; - } - delete backups[code]; - setValue('backup', backups); - rmListItem(code); + const code = _alert(2, '请输入配置代号', '請輸入配置代號', 'Please put in a name for a configuration'); + const backups = getValue('backup', true) || {}; + if (!(code in backups) || !code) return; + delete backups[code]; + setValue('backup', backups); + // goto(); + rmListItem(code); }; gE('.hvAAExport', optionBox).onclick = function () { - const t = getValue('option'); - gE('.hvAAConfig').value = typeof t === 'string' ? t : JSON.stringify(t); + const t = getValue('option'); + gE('.hvAAConfig').value = typeof t === 'string' ? t : JSON.stringify(t); }; gE('.hvAAImport', optionBox).onclick = function () { - const option = JSON.parse(gE('.hvAAConfig').value); - if (!option) { - return; - } - if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { - setValue('option', option); - goto(); - } + const option = JSON.parse(gE('.hvAAConfig').value); + if (!option) return; + if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { + setValue('option', option); + goto(); + } }; + // gE('.hvAAReset', optionBox).onclick = function () { - if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { - delValue('option'); - } + if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) delValue('option'); }; gE('.hvAAApply', optionBox).onclick = function () { - if (gE('select[name="attackStatus"] option[value="-1"]:checked', optionBox)) { - _alert(0, '请选择攻击模式', '請選擇攻擊模式', 'Please select the attack mode'); - gE('.hvAATabmenu>span[name="Main"]').click(); - gE('#attackStatus', optionBox).style.border = '1px solid red'; - setTimeout(() => { - gE('#attackStatus', optionBox).style.border = ''; - }, 0.5 * _1s); - return; - } - const arenaPrev = g('option').idleArenaValue; - const _option = { - version: g('version'), - }; - let inputs = gE('input,select', 'all', optionBox); - let itemName; let itemArray; let itemValue; let - i; - for (i = 0; i < inputs.length; i++) { - if (inputs[i].className === 'hvAADebug') { - continue; - } else if (inputs[i].className === 'hvAANumber') { - itemName = inputs[i].name; - itemValue = (inputs[i].value || inputs[i].placeholder) * 1; - if (isNaN(itemValue)) { - continue; - } - } else if (inputs[i].type === 'text' || inputs[i].type === 'hidden') { - itemName = inputs[i].name; - itemValue = inputs[i].value || inputs[i].placeholder; - if (itemValue === '') { - continue; - } - } else if (inputs[i].type === 'checkbox') { - itemName = inputs[i].id; - itemValue = inputs[i].checked; - if (itemValue === false) { - continue; - } - } else if (inputs[i].type === 'select-one') { - itemName = inputs[i].name; - itemValue = inputs[i].value; - } - itemArray = itemName.split('_'); - if (itemArray.length === 1) { - _option[itemName] = itemValue; - } else { - if (!(itemArray[0] in _option)) { - _option[itemArray[0]] = {}; - } - if (inputs[i].className === 'customizeInput') { - if (typeof _option[itemArray[0]][itemArray[1]] === 'undefined') { - _option[itemArray[0]][itemArray[1]] = []; + if (gE('select[name="attackStatus"] option[value="-1"]:checked', optionBox)) { + _alert(0, '请选择攻击模式', '請選擇攻擊模式', 'Please select the attack mode'); + gE('.hvAATabmenu>span[name="Main"]').click(); + gE('#attackStatus', optionBox).style.border = '1px solid red'; + setTimeout(() => { + gE('#attackStatus', optionBox).style.border = ''; + }, 0.5 * 1000); + return; + } + const _option = { + version: g('version'), + }; + let inputs = gE('input,select', 'all', optionBox); + let itemName; let itemArray; let itemValue; let + i; + for (i = 0; i < inputs.length; i++) { + if (inputs[i].className === 'hvAADebug') { + continue; + } else if (inputs[i].className === 'hvAANumber') { + itemName = inputs[i].name; + itemValue = (inputs[i].value || inputs[i].placeholder) * 1; + if (isNaN(itemValue)) continue; + } else if (inputs[i].type === 'text' || inputs[i].type === 'hidden') { + itemName = inputs[i].name; + itemValue = inputs[i].value || inputs[i].placeholder; + if (itemValue === '') continue; + } else if (inputs[i].type === 'checkbox') { + itemName = inputs[i].id; + itemValue = inputs[i].checked; + if (itemValue === false) continue; + } else if (inputs[i].type === 'select-one') { + itemName = inputs[i].name; + itemValue = inputs[i].value; + } + itemArray = itemName.split('_'); + if (itemArray.length === 1) { + _option[itemName] = itemValue; + } else { + if (!(itemArray[0] in _option)) _option[itemArray[0]] = {}; + if (inputs[i].className === 'customizeInput') { + if (typeof _option[itemArray[0]][itemArray[1]] === 'undefined') _option[itemArray[0]][itemArray[1]] = []; + _option[itemArray[0]][itemArray[1]].push(itemValue); + } else { + _option[itemArray[0]][itemArray[1]] = itemValue; + } } - _option[itemArray[0]][itemArray[1]].push(itemValue); - } else { - _option[itemArray[0]][itemArray[1]] = itemValue; - } - } - } - inputs = gE('.hvAAQuickSite input[type="text"]', 'all', optionBox); - for (i = 0; 3 * i < inputs.length; i++) { - if (i === 0 && inputs.length !== 0) { - _option.quickSite = []; } - if (inputs[3 * i + 1].value === '') { - continue; + inputs = gE('.hvAAQuickSite input[type="text"]', 'all', optionBox); + for (i = 0; 3 * i < inputs.length; i++) { + if (i === 0 && inputs.length !== 0) _option.quickSite = []; + if (inputs[3 * i + 1].value === '') continue; + _option.quickSite.push({ + fav: inputs[3 * i].value, + name: inputs[3 * i + 1].value, + url: inputs[3 * i + 2].value, + }); } - _option.quickSite.push({ - fav: inputs[3 * i].value, - name: inputs[3 * i + 1].value, - url: inputs[3 * i + 2].value, - }); - } - setValue('option', _option); - optionBox.style.display = 'none'; - // 更改设置后实时刷新竞技场数据 - const arenaNew = _option.idleArenaValue; - if(arenaNew === arenaPrev){ + setValue('option', _option); + optionBox.style.display = 'none'; goto(); - return; - } - if(_option.idleArena && _option.idleArenaValue){ - const arena = getValue('arena', true); - arena.isOptionUpdated = undefined; - setValue('arena', arena); - goto(); - } }; gE('.hvAACancel', optionBox).onclick = function () { - optionBox.style.display = 'none'; + optionBox.style.display = 'none'; }; if (g('option')) { - let i; let j; let - k; - const _option = g('option'); - const inputs = gE('input,select', 'all', optionBox); - let itemName; let itemArray; let itemValue; let - _html; - for (i = 0; i < inputs.length; i++) { - if (inputs[i].className === 'hvAADebug') { - continue; + let i; let j; let + k; + const _option = g('option'); + const inputs = gE('input,select', 'all', optionBox); + let itemName; let itemArray; let itemValue; let + _html; + for (i = 0; i < inputs.length; i++) { + if (inputs[i].className === 'hvAADebug') continue; + itemName = inputs[i].name || inputs[i].id; + if (typeof _option[itemName] !== 'undefined') { + itemValue = _option[itemName]; + } else { + itemArray = itemName.split('_'); + itemValue = ''; + if (itemArray.length === 2 && typeof _option[itemArray[0]] === 'object' && inputs[i].className !== 'hvAACustomize' && typeof _option[itemArray[0]][itemArray[1]] !== 'undefined') { + itemValue = _option[itemArray[0]][itemArray[1]]; + } + } + if (inputs[i].type === 'text' || inputs[i].type === 'hidden' || inputs[i].type === 'select-one' || inputs[i].type === 'number') { + inputs[i].value = itemValue; + } else if (inputs[i].type === 'checkbox') { + inputs[i].checked = itemValue; + } } - itemName = inputs[i].name || inputs[i].id; - if (typeof _option[itemName] !== 'undefined') { - itemValue = _option[itemName]; - } else { - itemArray = itemName.split('_'); - itemValue = ''; - if (itemArray.length === 2 && typeof _option[itemArray[0]] === 'object' && inputs[i].className !== 'hvAACustomize' && typeof _option[itemArray[0]][itemArray[1]] !== 'undefined') { - itemValue = _option[itemArray[0]][itemArray[1]]; - } + const customize = gE('.customize', 'all', optionBox); + for (i = 0; i < customize.length; i++) { + itemName = customize[i].getAttribute('name'); + if (itemName in _option) { + for (j in _option[itemName]) { + const group = customize[i].appendChild(cE('div')); + group.className = 'customizeGroup'; + group.innerHTML = `${j * 1 + 1}. `; + for (k = 0; k < _option[itemName][j].length; k++) { + const input = group.appendChild(cE('input')); + input.type = 'text'; + input.className = 'customizeInput'; + input.name = `${itemName}_${j}`; + input.value = _option[itemName][j][k]; + } + } + } } - if (inputs[i].type === 'text' || inputs[i].type === 'hidden' || inputs[i].type === 'select-one' || inputs[i].type === 'number') { - inputs[i].value = itemValue; - } else if (inputs[i].type === 'checkbox') { - inputs[i].checked = itemValue; + if (_option.quickSite) { + _html = '图标圖標ICON名称名稱Name链接鏈接Link'; + _option.quickSite.forEach((i) => { + _html = `${_html}`; + }); + gE('.hvAAQuickSite>table>tbody', optionBox).innerHTML = _html; } - } - const customize = gE('.customize', 'all', optionBox); - for (i = 0; i < customize.length; i++) { - itemName = customize[i].getAttribute('name'); - if (itemName in _option) { - for (j in _option[itemName]) { - const group = customize[i].appendChild(cE('div')); - group.className = 'customizeGroup'; - group.innerHTML = `${j * 1 + 1}. `; - for (k = 0; k < _option[itemName][j].length; k++) { - const input = group.appendChild(cE('input')); - input.type = 'text'; - input.className = 'customizeInput'; - input.name = `${itemName}_${j}`; - input.value = _option[itemName][j][k]; + if (getValue('backup')) { + const backups = getValue('backup', true); + _html = ''; + for (i in backups) { + _html = `${_html}
    • ${i}
    • `; } - } - } - } - if (_option.quickSite) { - _html = '图标圖標ICON名称名稱Name链接鏈接Link'; - _option.quickSite.forEach((i) => { - _html = `${_html}`; - }); - gE('.hvAAQuickSite>table>tbody', optionBox).innerHTML = _html; - } - if (getValue('backup')) { - const backups = getValue('backup', true); - _html = ''; - for (i in backups) { - _html = `${_html}
    • ${i}
    • `; + gE('.hvAABackupList', optionBox).innerHTML = _html; } - gE('.hvAABackupList', optionBox).innerHTML = _html; - } } - } +} - function customizeBox() { // 自定义条件界面 +function customizeBox() { // 自定义条件界面 const customizeBox = gE('body').appendChild(cE('div')); customizeBox.className = 'customizeBox'; const statusOption = [ - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', ].join(''); customizeBox.innerHTML = [ - '??', - `${String.fromCharCode(0x21F1.toString(10))}`, - '', - ``, - '', - ``, - '', + '??', + `${String.fromCharCode(0x21F1.toString(10))}`, + '', + ``, + '', + ``, + '', ].join(' '); const funcSelect = function (e) { - let box; - if (gE('#hvAAInspectBox')) { - box = gE('#hvAAInspectBox'); - } else { - box = gE('body').appendChild(cE('div')); - box.id = 'hvAAInspectBox'; - } - let { target } = e; - let find = attr(target); - while (!find) { - target = target.parentNode; - if (target.id === 'csp' || target.tagName === 'BODY') { - box.style.display = 'none'; - return; + let box; + if (gE('#hvAAInspectBox')) { + box = gE('#hvAAInspectBox'); + } else { + box = gE('body').appendChild(cE('div')); + box.id = 'hvAAInspectBox'; + } + let { target } = e; + let find = attr(target); + while (!find) { + target = target.parentNode; + if (target.id === 'csp' || target.tagName === 'BODY') { + box.style.display = 'none'; + return; + } + find = attr(target); } - find = attr(target); - } - box.textContent = find; - box.style.display = 'block'; - box.style.left = `${e.pageX - e.offsetX + target.offsetWidth}px`; - box.style.top = `${e.pageY - e.offsetY + target.offsetHeight}px`; + box.textContent = find; + box.style.display = 'block'; + box.style.left = `${e.pageX - e.offsetX + target.offsetWidth}px`; + box.style.top = `${e.pageY - e.offsetY + target.offsetHeight}px`; }; gE('.hvAAInspect', customizeBox).onclick = function () { - if (this.title === 'on') { - this.title = 'off'; - gE('#csp').removeEventListener('mousemove', funcSelect); - } else { - this.title = 'on'; - gE('#csp').addEventListener('mousemove', funcSelect); - } + if (this.title === 'on') { + this.title = 'off'; + gE('#csp').removeEventListener('mousemove', funcSelect); + } else { + this.title = 'on'; + gE('#csp').addEventListener('mousemove', funcSelect); + } }; gE('.groupAdd', customizeBox).onclick = function () { - const target = g('customizeTarget'); - const selects = gE('select', 'all', customizeBox); - let groupChoose = selects[0].value; - let group; - if (groupChoose === 'new') { - groupChoose = gE('option', 'all', selects[0]).length; - group = target.appendChild(cE('div')); - group.className = 'customizeGroup'; - group.innerHTML = `${groupChoose}. `; - selects[0].click(); - } else { - group = gE('.customizeGroup', 'all', target)[groupChoose - 1]; - } - const input = group.appendChild(cE('input')); - input.type = 'text'; - input.className = 'customizeInput'; - input.name = `${target.getAttribute('name')}_${groupChoose - 1}`; - input.value = `${selects[1].value},${selects[2].value},${selects[3].value}`; + const target = g('customizeTarget'); + const selects = gE('select', 'all', customizeBox); + let groupChoose = selects[0].value; + let group; + if (groupChoose === 'new') { + groupChoose = gE('option', 'all', selects[0]).length; + group = target.appendChild(cE('div')); + group.className = 'customizeGroup'; + group.innerHTML = `${groupChoose}. `; + selects[0].click(); + } else { + group = gE('.customizeGroup', 'all', target)[groupChoose - 1]; + } + const input = group.appendChild(cE('input')); + input.type = 'text'; + input.className = 'customizeInput'; + input.name = `${target.getAttribute('name')}_${groupChoose - 1}`; + input.value = `${selects[1].value},${selects[2].value},${selects[3].value}`; }; function attr(target) { - const onmouseover = target.getAttribute('onmouseover'); - if (target.className === 'btsd') { - return `Skill Id: ${target.id}`; - } if (onmouseover && onmouseover.match('common.show_itemc_box')) { - return `Item Id: ${onmouseover.match(/(\d+)\)/)[1]}`; - } if (onmouseover && onmouseover.match('equips.set')) { - return `Equip Id: ${onmouseover.match(/(\d+)/)[1]}`; - } if (onmouseover && onmouseover.match('battle.set_infopane_effect')) { - return `Buff Img: ${target.src.match(/\/e\/(.*?).png/)[1]}`; - } + const onmouseover = target.getAttribute('onmouseover'); + if (target.className === 'btsd') { + return `Skill Id: ${target.id}`; + } if (onmouseover && onmouseover.match('common.show_itemc_box')) { + return `Item Id: ${onmouseover.match(/(\d+)\)/)[1]}`; + } if (onmouseover && onmouseover.match('equips.set')) { + return `Equip Id: ${onmouseover.match(/(\d+)/)[1]}`; + } if (onmouseover && onmouseover.match('battle.set_infopane_effect')) { + return `Buff Img: ${target.src.match(/\/e\/(.*?).png/)[1]}`; + } } - } +} - function setAlarm(e) { // 发出警报 +function setAlarm(e) { // 发出警报 e = e || 'Common'; - if (g('option').notification) { - setNotification(e); - } - if (g('option').alert && g('option').audioEnable && g('option').audioEnable[e]) { - setAudioAlarm(e); - } - } + if (g('option').notification) setNotification(e); + if (g('option').alert && g('option').audioEnable && g('option').audioEnable[e]) setAudioAlarm(e); +} - function setAudioAlarm(e) { // 发出音频警报 +function setAudioAlarm(e) { // 发出音频警报 let audio; if (gE(`#hvAAAlert-${e}`)) { - audio = gE(`#hvAAAlert-${e}`); + audio = gE(`#hvAAAlert-${e}`); } else { - audio = gE('body').appendChild(cE('audio')); - audio.id = `hvAAAlert-${e}`; - const fileType = '.ogg'; // var fileType = (/Chrome|Safari/.test(navigator.userAgent)) ? '.mp3' : '.wav'; - audio.src = (g('option').audio && g('option').audio[e]) ? g('option').audio[e] : `https://github.com/dodying/UserJs/raw/master/HentaiVerse/hvAutoAttack/${e}${fileType}`; - audio.controls = true; - audio.loop = (e === 'Riddle'); + audio = gE('body').appendChild(cE('audio')); + audio.id = `hvAAAlert-${e}`; + const fileType = '.ogg'; // var fileType = (/Chrome|Safari/.test(navigator.userAgent)) ? '.mp3' : '.wav'; + audio.src = (g('option').audio && g('option').audio[e]) ? g('option').audio[e] : `https://github.com/dodying/UserJs/raw/master/HentaiVerse/hvAutoAttack/${e}${fileType}`; + audio.controls = true; + audio.loop = (e === 'Riddle'); } audio.play(); function pauseAudio(e) { - audio.pause(); - document.removeEventListener(e.type, pauseAudio, true); + audio.pause(); + document.removeEventListener(e.type, pauseAudio, true); } document.addEventListener('mousemove', pauseAudio, true); - } +} - function setNotification(e) { // 发出桌面通知 - const notification = [ - { - Common: { - text: '未知', - time: 5, - }, - Error: { - text: '某些错误发生了', - time: 10, +/*function setNotification(type) { + const lang = g('lang'); + const notifications = { + zh: { + Common: { text: '未知', time: 5 }, + Error: { text: '某些错误发生了', time: 10 }, + Defeat: { text: '游戏失败\n玩家可自行查看战斗Log寻找失败原因', time: 5 }, + Riddle: { text: '小马答题\n紧急!\n紧急!\n紧急!', time: 30 }, + Victory: { text: '游戏胜利\n页面将在3秒后刷新', time: 3 }, + Test: { text: '测试文本', time: 3 }, }, - Defeat: { - text: '游戏失败\n玩家可自行查看战斗Log寻找失败原因', - time: 5, + tw: { + Common: { text: '未知', time: 5 }, + Error: { text: '某些錯誤發生了', time: 10 }, + Defeat: { text: '遊戲失敗\n玩家可自行查看戰鬥Log尋找失敗原因', time: 5 }, + Riddle: { text: '小馬答題\n緊急!\n緊急!\n緊急!', time: 30 }, + Victory: { text: '遊戲勝利\n頁面將在3秒後刷新', time: 3 }, + Test: { text: '測試文本', time: 3 }, }, - Riddle: { - text: '小马答题\n紧急!\n紧急!\n紧急!', - time: 30, + en: { + Common: { text: 'Unknown', time: 5 }, + Error: { text: 'Some errors have occurred', time: 10 }, + Defeat: { text: 'You have been defeated.\nYou can check the battle log.', time: 5 }, + Riddle: { text: 'Riddle\nURGENT\nURGENT\nURGENT', time: 30 }, + Victory: { text: 'You\'re victorious.\nThis page will refresh in 3 seconds.', time: 3 }, + Test: { text: 'Test text', time: 3 }, }, - Victory: { - text: '游戏胜利\n页面将在3秒后刷新', - time: 3, - }, - Test: { - text: '测试文本', - time: 3, + }; + + const langKey = 'zh'; + const notification = notifications[langKey][type]; + + if (!('Notification' in window)) { + console.log('当前浏览器不支持通知'); + return; + } + + if (Notification.permission === 'granted') { + createNotification(notification); + } else if (Notification.permission !== 'denied') { + Notification.requestPermission().then(permission => { + if (permission === 'granted') { + createNotification(notification); + } else { + console.log('通知权限未授予'); + } + }); + } else { + console.log('通知被拒绝或未获得'); + } + + function createNotification({ text, time }) { + const n = new Notification('通知', { + icon: '/y/hentaiverse.png', + body: text, + requireInteraction: true // 通知不会自动消失 + }); + } +}*/ + + +function setNotification(e) { // 发出桌面通知 + const notification = [ + { + Common: { + text: '未知', + time: 5, + }, + Error: { + text: '某些错误发生了', + time: 10, + }, + Defeat: { + text: '游戏失败\n玩家可自行查看战斗Log寻找失败原因', + time: 5, + }, + Riddle: { + text: '小马答题\n紧急!\n紧急!\n紧急!', + time: 30, + }, + Victory: { + text: '游戏胜利\n页面将在3秒后刷新', + time: 3, + }, + Test: { + text: '测试文本', + time: 3, + }, + }, { + Common: { + text: '未知', + time: 5, + }, + Error: { + text: '某些錯誤發生了', + time: 10, + }, + Defeat: { + text: '遊戲失敗\n玩家可自行查看戰鬥Log尋找失敗原因', + time: 5, + }, + Riddle: { + text: '小馬答題\n緊急!\n緊急!\n緊急!', + time: 30, + }, + Victory: { + text: '遊戲勝利\n頁面將在3秒後刷新', + time: 3, + }, + Test: { + text: '測試文本', + time: 3, + }, + }, { + Common: { + text: 'unknown', + time: 5, + }, + Error: { + text: 'Some errors have occurred', + time: 10, + }, + Defeat: { + text: 'You have been defeated.\nYou can check the battle log.', + time: 5, + }, + Riddle: { + text: 'Riddle\nURGENT\nURGENT\nURGENT', + time: 30, + }, + Victory: { + text: 'You\'re victorious.\nThis page will refresh in 3 seconds.', + time: 3, + }, + Test: { + text: 'testText', + time: 3, + }, }, - }, { - Common: { - text: '未知', - time: 5, - }, - Error: { - text: '某些錯誤發生了', - time: 10, - }, - Defeat: { - text: '遊戲失敗\n玩家可自行查看戰鬥Log尋找失敗原因', - time: 5, - }, - Riddle: { - text: '小馬答題\n緊急!\n緊急!\n緊急!', - time: 30, - }, - Victory: { - text: '遊戲勝利\n頁面將在3秒後刷新', - time: 3, - }, - Test: { - text: '測試文本', - time: 3, - }, - }, { - Common: { - text: 'unknown', - time: 5, - }, - Error: { - text: 'Some errors have occurred', - time: 10, - }, - Defeat: { - text: 'You have been defeated.\nYou can check the battle log.', - time: 5, - }, - Riddle: { - text: 'Riddle\nURGENT\nURGENT\nURGENT', - time: 30, - }, - Victory: { - text: 'You\'re victorious.\nThis page will refresh in 3 seconds.', - time: 3, - }, - Test: { - text: 'testText', - time: 3, - }, - }, ][g('lang')][e]; if (typeof GM_notification !== 'undefined') { - GM_notification({ - text: notification.text, - image: `${window.location.origin}/y/hentaiverse.png`, - highlight: true, - timeout: 1000 * notification.time, - }); + GM_notification({ + text: notification.text, + image: `${window.location.origin}/y/hentaiverse.png`, + highlight: true, + timeout: 1000 * notification.time, + }); } if (window.Notification && window.Notification.permission !== 'denied') { - window.Notification.requestPermission((status) => { - if (status === 'granted') { - const n = new window.Notification(notification.text, { - icon: '/y/hentaiverse.png', - }); - setTimeout(() => { - if (n) { - n.close(); - } - }, 1000 * notification.time); - - var nClose = function (e) { - if (n) { - n.close(); + window.Notification.requestPermission((status) => { + if (status === 'granted') { + const n = new window.Notification(notification.text, { + icon: '/y/hentaiverse.png', + }); + setTimeout(() => { + if (n) n.close(); + }, 1000 * notification.time); + + var nClose = function (e) { + if (n) n.close(); + document.removeEventListener(e.type, nClose, true); + }; + document.addEventListener('mousemove', nClose, true); + // document.addEventListener('click', nClose, true); } - document.removeEventListener(e.type, nClose, true); - }; - document.addEventListener('mousemove', nClose, true); - // document.addEventListener('click', nClose, true); - } - }); + }); } - } +} - function checkCondition(parms) { - if (typeof parms === 'undefined') { - return true; - } + +function checkCondition(parms) { + if (typeof parms === 'undefined') return true; let i; let j; let - k; + k; const result = []; const returnValue = function (str) { - if (str.match(/^_/)) { - const arr = str.split('_'); - return func[arr[1]](...[...arr].splice(2)); - } if (str.match(/^'.*?'$|^".*?"$/)) { - return str.substr(1, str.length - 2); - } if (isNaN(str * 1)) { - const paramList = str.split('.'); - let result; - for (let key of paramList) { - if (!result) { - result = g(key) ?? getValue(key) ?? (g('battle') ?? getValue('battle', true))[key]; - continue; - } - result = result[key] - } - return result; - } - return str * 1; + if (str.match(/^_/)) { + const arr = str.split('_'); + return func[arr[1]](...[...arr].splice(2)); + } if (str.match(/^'.*?'$|^".*?"$/)) { + return str.substr(1, str.length - 2); + } if (isNaN(str * 1)) { + return g(str); + } + return str * 1; }; var func = { - isCd(id) { - return isOn(id) ? 0 : 1; - }, - buffTurn(img) { - let buff = gE(`#pane_effects>img[src*="${img}"]`); - if (!buff) { - return 0; - } - buff = buff.getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; - return isNaN(buff) ? Infinity : buff; - }, + isCd(id) { + return isOn(id) ? 1 : 0; + }, + buffTurn(img) { + let buff = gE(`#pane_effects>img[src*="${img}"]`); + if (!buff) { + return 0; + } + buff = buff.getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; + return isNaN(buff) ? Infinity : buff; + }, }; for (i in parms) { - for (j = 0; j < parms[i].length; j++) { - if (!Array.isArray(parms[i])) { - continue; - } - k = parms[i][j].split(','); - const kk = k.toString(); - k[0] = returnValue(k[0]); - k[2] = returnValue(k[2]); - - if (k[0] === undefined || k[0] === null || (typeof k[0] !== "string" && isNaN(k[0]))) { - Debug.log(kk[0], k[0]); - } - if (k[2] === undefined || k[2] === null || (typeof k[2] !== "string" && isNaN(k[2]))) { - Debug.log(kk[2], k[2]); - } - - switch (k[1]) { - case '1': - result[i] = k[0] > k[2]; - break; - case '2': - result[i] = k[0] < k[2]; - break; - case '3': - result[i] = k[0] >= k[2]; - break; - case '4': - result[i] = k[0] <= k[2]; - break; - case '5': - result[i] = k[0] === k[2]; - break; - case '6': - result[i] = k[0] !== k[2]; - break; - } - if (result[i] === false) { - j = parms[i].length; + for (j = 0; j < parms[i].length; j++) { + if (!Array.isArray(parms[i])) continue; + k = parms[i][j].split(','); + k[0] = returnValue(k[0]); + k[2] = returnValue(k[2]); + switch (k[1]) { + case '1': + result[i] = k[0] > k[2]; + break; + case '2': + result[i] = k[0] < k[2]; + break; + case '3': + result[i] = k[0] >= k[2]; + break; + case '4': + result[i] = k[0] <= k[2]; + break; + case '5': + result[i] = k[0] === k[2]; + break; + case '6': + result[i] = k[0] !== k[2]; + break; + } + if (result[i] === false) j = parms[i].length; } - } - if (result[i] === true) { - return true; - } + if (result[i] === true) return true; } return false; - } - - // 答题// - function riddleAlert() { // 答题警报 +} +// 答题// +function riddleAlert() { // 答题警报 if (window.opener) { - gE('#riddleanswer+img').onclick = function () { - riddleSubmit(gE('#riddleanswer').value); - }; + gE('#riddleanswer+img').onclick = function () { + riddleSubmit(gE('#riddleanswer').value); + }; } setAlarm('Riddle'); const answers = ['A', 'B', 'C']; document.onkeydown = function (e) { - gE('#hvAAAlert-Riddle')?.pause(); - if (/^[abc]$/i.test(e.key)) { - riddleSubmit(e.key.toUpperCase()); - this.onkeydown = null; - } else if (/^[123]$/.test(e.key)) { - riddleSubmit(answers[e.key - 1]); - this.onkeydown = null; - } + gE('#hvAAAlert-Riddle').pause(); + if (/^[abc]$/i.test(e.key)) { + riddleSubmit(e.key.toUpperCase()); + this.onkeydown = null; + } else if (/^[123]$/.test(e.key)) { + riddleSubmit(answers[e.key - 1]); + this.onkeydown = null; + } }; if (g('option').riddleRadio) { - const bar = gE('body').appendChild(cE('div')); - bar.className = 'answerBar'; - answers.forEach((answer) => { - const button = bar.appendChild(cE('div')); - button.value = answer; - button.onclick = function () { - riddleSubmit(this.value); - }; - }); + const bar = gE('body').appendChild(cE('div')); + bar.className = 'answerBar'; + answers.forEach((answer) => { + const button = bar.appendChild(cE('div')); + button.value = answer; + button.onclick = function () { + riddleSubmit(this.value); + }; + }); } const checkTime = function () { - let time; - if (typeof g('time') === 'undefined') { - const timeDiv = gE('#riddlecounter>div>div', 'all'); - if (timeDiv.length === 0) { - return; - } - time = ''; - for (let j = 0; j < timeDiv.length; j++) { - time = (timeDiv[j].style.backgroundPosition.match(/(\d+)px$/)[1] / 12).toString() + time; + let time; + if (typeof g('time') === 'undefined') { + const timeDiv = gE('#riddlecounter>div>div', 'all'); + if (timeDiv.length === 0) return; + time = ''; + for (let j = 0; j < timeDiv.length; j++) { + time = (timeDiv[j].style.backgroundPosition.match(/(\d+)px$/)[1] / 12).toString() + time; + } + g('time', time * 1); + } else { + time = g('time'); + time--; + g('time', time); } - g('time', time * 1); - } else { - time = g('time'); - time--; - g('time', time); - } - document.title = time; - if (time <= g('option').riddleAnswerTime) { - riddleSubmit(gE('#riddleanswer').value || answers[parseInt(Math.random() * 3)]); - } + document.title = time; + if (time <= g('option').riddleAnswerTime) riddleSubmit(gE('#riddleanswer').value || answers[parseInt(Math.random() * 3)]); }; for (let i = 0; i < 30; i++) { - setTimeout(checkTime, i * _1s); + setTimeout(checkTime, i * 1000); } function riddleSubmit(answer) { - if (!window.opener) { - gE('#riddleanswer').value = answer; - gE('#riddleanswer+img').click(); - } else { - $ajax.fetch(window.location.href, `riddleanswer=${answer}`).then(() => { // 待续 - window.opener.document.location.href = window.location.href; - window.close(); - }).catch(e=>console.error(e)); - } - } - } - - // 战斗外// - function checkIsHV() { - if (window.location.host !== 'e-hentai.org') { // is in HV - setValue('url', window.location.origin); - return true; - } - setValue('lastEH', time(0)); - const isEngage = window.location.href === 'https://e-hentai.org/news.php?encounter'; - const encounter = getEncounter(); - let href = getValue('url') ?? (document.referrer.match('hentaiverse.org') ? new URL(document.referrer).origin : 'https://hentaiverse.org'); - const eventpane = gE('#eventpane'); - const now = time(0); - let url; - if (eventpane) { // 新一天或遭遇战 - url = gE('#eventpane>div>a')?.href.split('/')[3]; - encounter.unshift({ href: url, time: now }); - setEncounter(encounter); - } else { - if (encounter.length) { - if (now - encounter[0]?.time > 0.5 * _1h) { // 延长最新一次的time, 避免因漏记录导致连续来回跳转 - encounter[0].time = now; - setEncounter(encounter); - } - for (let e of encounter) { - if (e.encountered) { - continue; - } - url = e.href; - break; + if (!window.opener) { + gE('#riddleanswer').value = answer; + gE('#riddleanswer+img').click(); + } else { + post(window.location.href, () => { // 待续 + window.opener.document.location.href = window.location.href; + window.close(); + }, `riddleanswer=${answer}`); } - } - } - - if (!url) { - if (isEngage && !getValue('battle')) { - // 自动跳转,同时先刷新遭遇时间,延长下一次遭遇 - $ajax.openNoFetch(getValue('lastHref')); - } - return; } +} +// 战斗外// +function repairCheck() { + let json; let checkOnload; let checkLength; + let len = 0; + let lastID; + const eqps = []; + checkOnload = function () { + if (json) { + setTimeout(checkOnload, 200); + return; + } + post('?s=Forge&ss=re', (data) => { + post(gE('#mainpane>script[src]', data).src, (data1) => { + json = JSON.parse(data1.match(/{.*}/)[0]); + gE('.eqp>[id]', 'all', data).forEach((i) => { + eqps.push(i.id.match(/\d+/)[0]); + }); + len = 0; + if (eqps.length === 0) { + checkLength(); + return; + } + for (let i in eqps) { + const id = eqps[i]; + if (json[id].d.match(/Condition: \d+ \/ \d+ \((\d+)%\)/)[1] <= g('option').repairValue) { + if (id === lastID) { + return; + } + lastID = id; // 记录最后一次需要修理的装备id,然后再次检测是否修理成功 + post('?s=Forge&ss=re', checkOnload, `select_item=${id}`); + } else { + checkLength(); + } + } + }, null, 'text'); + }); + }; + checkLength = function () { + len++; + if (len >= eqps.length && g('option').idleArena) setTimeout(idleArena, (g('option').idleArenaTime * (Math.random() * 20 + 90) / 100) * 1000); + }; + checkOnload(); +} - // 减少因在恒定世界处于战斗中时打开eh触发了遭遇而导致的错失 - // 缓存当前链接,等战斗结束时再自动打开,下次打开链接时: - // 1. 若新的遭遇未出现,进入已缓存的战斗链接 - // 2. 若新的遭遇已出现,则前一次已超时失效错过,重新获取新的一次 - if (!isEngage) { // 战斗外,非自动跳转 - eventpane.style.cssText += 'color:red;' // 链接标红提醒 - } else if (getValue('battle')) { //战斗中 - eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 - } else { // 战斗外,自动跳转 - $ajax.openNoFetch(`${href}/${url}`); - } - } - - function setEncounter(encounter) { - return g('encounter', setValue('encounter', encounter)); - } - - function getEncounter() { - const getToday = (encounter) => encounter.filter(e => time(2, e.time) === time(2)); - const current = g('encounter') ?? []; - let encounter = getValue('encounter', true) ?? []; - if (JSON.stringify(current) === JSON.stringify(encounter)) { - return getToday(encounter); - } - let dict = {}; - for (let e of current) { - dict[e.href ?? `newDawn`] = e; - } - for (let e of encounter) { - const key = e.href ?? `newDawn`; - dict[key] ??= e; - dict[key].time = Math.max(dict[key].time, e.time); - dict[key].encountered = (e.encountered || dict[key].encountered) ? Math.max(dict[key].encountered ?? 0, e.encountered ?? 0) : undefined; - } - return getToday(Object.values(dict)).sort((x, y) => x.time < y.time ? 1 : x.time > y.time ? -1 : 0); - } - - function quickSite() { // 快捷站点 +function quickSite() { // 快捷站点 const quickSiteBar = gE('body').appendChild(cE('div')); quickSiteBar.className = 'quickSiteBar'; - quickSiteBar.innerHTML = '<<贴吧Forums'; + quickSiteBar.innerHTML = '<<贴吧Forums'; if (g('option').quickSite) { - g('option').quickSite.forEach((site) => { - quickSiteBar.innerHTML = `${quickSiteBar.innerHTML}${(site.fav) ? `` : ''}${site.name}`; - }); + g('option').quickSite.forEach((site) => { + quickSiteBar.innerHTML = `${quickSiteBar.innerHTML}${(site.fav) ? `` : ''}${site.name}`; + }); } gE('.quickSiteBarToggle', quickSiteBar).onclick = function () { - const spans = gE('span', 'all', quickSiteBar); - for (let i = 1; i < spans.length; i++) { - spans[i].style.display = (this.textContent === '<<') ? 'none' : 'block'; - } - this.textContent = (this.textContent === '<<') ? '>>' : '<<'; + const spans = gE('span', 'all', quickSiteBar); + for (let i = 1; i < spans.length; i++) { + spans[i].style.display = (this.textContent === '<<') ? 'none' : 'block'; + } + this.textContent = (this.textContent === '<<') ? '>>' : '<<'; }; - } +} - function autoSwitchIsekai() { +function autoSwitchIsekai() { + const herf = window.location.href; + let isIsekai = herf.indexOf('isekai') !== -1; + let domain = herf.slice(0, herf.indexOf('.org') + 4); if (!g('option').isekai) { - // 若不启用自动跳转 - return; - } - window.location.href = `${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`; - } - - async function asyncSetAbilityData() { try { - logSwitchAsyncTask(arguments); - const html = await $ajax.fetch('?s=Character&ss=ab'); - const doc = $doc(html); - let ability = {}; - await Promise.all(Array.from(gE('#ability_treelist>div>img', 'all', doc)).map(async img => { try { - const _ = img.getAttribute('onclick')?.match(/(\?s=(.*)tree=(.*))'/); - const [href, type] = _ ? [_[1], _[3]] : ['?s=Character&ss=ab&tree=general', 'general']; - const html = await $ajax.fetch(href); - const doc = $doc(html); - const slots = Array.from(gE('.ability_slotbox>div>div', 'all', doc)).forEach(slot => { - const id = slot.id.match(/_(\d*)/)[1]; - const parent = slot.parentNode.parentNode.parentNode; - ability[id] = { - name: gE('.fc2', parent).innerText, - type: type, - level: Array.from(gE('.aw1,.aw2,.aw3,.aw4,.aw5,.aw6,.aw7,.aw8,.aw9,.aw10', parent).children).map(div => div.style.cssText.indexOf('f.png') === -1 ? 0 : 1).reduce((x, y) => x + y), - } - }); - } catch (e) {console.error(e)}})); - setValue('ability', ability); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - async function asyncSetEnergyDrinkHathperk() { try { - logSwitchAsyncTask(arguments); - const html = await $ajax.fetch('https://e-hentai.org/hathperks.php'); - if(!html) { - return; - } - const doc = $doc(html); - const perks = gE('.stuffbox>table>tbody>tr', 'all', doc); - if (!perks) { - return; - } - setValue('staminaHathperk', perks[25].innerHTML.includes('Obtained')); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - async function asyncSetStamina() { try { - logSwitchAsyncTask(arguments); - const html = await $ajax.fetch(window.location.href); - setValue('staminaTime', Math.floor(time(0) / 1000 / 60 / 60)); - setValue('stamina', gE('#stamina_readout .fc4.far>div', $doc(html)).textContent.match(/\d+/)[0] * 1); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - async function asyncGetItems() { try { - logSwitchAsyncTask(arguments); - const html = await $ajax.fetch('?s=Character&ss=it'); - const items = {}; - for (let each of gE('.nosel.itemlist>tbody', $doc(html)).children) { - const name = each.children[0].children[0].innerText; - const id = each.children[0].children[0].getAttribute('id').split('_')[1]; - const count = each.children[1].innerText; - items[id] = [name, count]; - } - g('items', items); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - async function asyncCheckSupply() { try { - if (!g('option').checkSupply) { - return true; - } - logSwitchAsyncTask(arguments); - const items = g('items'); - const thresholdList = g('option').checkItem; - const checkList = g('option').isCheck; - const needs = []; - for (let id in checkList) { - const item = items[id]; - if (!item) { - continue; - } - const [name, count] = item; - const threshold = thresholdList[id] ?? 0; - if ((count ?? 0) >= threshold) { - continue; - } - needs.push(`\n${name}(${count}<${threshold})`); - } - if (needs.length) { - console.log(`Needs supply:${needs}`); - } - logSwitchAsyncTask(arguments); - return !needs.length; - } catch (e) {console.error(e)}} - - async function asyncCheckRepair() { try { - if (!g('option').repair) { - return true; - } - logSwitchAsyncTask(arguments); - const doc = $doc(await $ajax.fetch('?s=Forge&ss=re')); - const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); - const eqps = (await Promise.all(Array.from(gE('.eqp>[id]', 'all', doc)).map(async eqp => { try { - const id = eqp.id.match(/\d+/)[0]; - const condition = 1 * json[id].d.match(/Condition: \d+ \/ \d+ \((\d+)%\)/)[1]; - if (condition > g('option').repairValue) { + // 若不启用自动跳转 return; - } - return gE('.messagebox_error', $doc(await $ajax.fetch(`?s=Forge&ss=re`, `select_item=${id}`)))?.innerText ? undefined : id; - } catch (e) {console.error(e)}}))).filter(e => e); - if (eqps.length) { - console.log('eqps need repair: ', eqps); - } - logSwitchAsyncTask(arguments); - return !eqps.length; - } catch (e) {console.error(e)}} - - function checkStamina(low, cost) { - let stamina = getValue('stamina'); - const lastTime = getValue('staminaTime'); - let timeNow = Math.floor(time(0) / _1h); - stamina += lastTime ? timeNow - lastTime : 0; - const stmNR = stamina + 24 - (timeNow % 24); - cost ??= 0; - const stmNRChecked = !cost || stmNR - cost >= g('option').staminaLowWithReNat; - console.log('stamina:', stamina,'\nstamina with nature recover:', stmNR, '\nnext arena stamina cost: ', cost.toString()); - if (stamina - cost >= (low ?? g('option').staminaLow) && stmNRChecked) { - return 1; - } - let checked = 0; - if (!stmNRChecked) { - checked = -1; - } - if (isIsekai || !g('option').restoreStamina) { - return checked; - } - const items = g('items'); - if (!items) { - return checked; } - const recover = items[11402] ? 5 : items[11401] ? getValue('staminaHathperk') ? 20 : 10 : 0; - if (recover && stamina <= (100 - recover)) { - $ajax.open(window.location.href, 'recover=stamina'); - return checked; - } - } - - async function updateEncounter(engage, isInBattle) { try { - const encounter = getEncounter(); - const encountered = encounter.filter(e => e.encountered && e.href); - const count = encounter.filter(e => e.href).length; - - const now = time(0); - const last = encounter[0]?.time ?? getValue('lastEH', true) ?? 0; // 上次遭遇 或 上次打开EH 或 0 - let cd; - if (encountered.length >= 24) { - cd = Math.floor(encounter[0].time / _1d + 1) * _1d - now; - } else if (!last) { - cd = 0; - } else { - cd = _1h / 2 + last - now; - } - cd = Math.max(0, cd); - const ui = gE('.encounterUI') ?? (() => { - const ui = gE('body').appendChild(cE('a')); - ui.className = 'encounterUI'; - ui.title = `${time(3, last)}\nEncounter Time: ${count}`; - if (!isInBattle) { - ui.href = 'https://e-hentai.org/news.php?encounter'; - } - return ui; - })(); - - const missed = count - encountered.length; - if (count === 24) { - ui.style.cssText += 'color:orange!important;'; - } else if (!cd) { - ui.style.cssText += 'color:red!important;'; - } else { - ui.style.cssText += 'color:unset!important;'; - } - ui.innerHTML = `${formatTime(cd).slice(0, 2).map(cdi => cdi.toString().padStart(2, '0')).join(`:`)}[${encounter.length ? (count >= 24 ? `☯` : count) : `✪`}${missed ? `-${missed}` : ``}]`; - if (engage && !cd) { - onEncounter(); - return true; - } - let interval = cd > _1h ? _1m : (!g('option').encounterQuickCheck || cd > _1m) ? _1s : 80; - interval = (g('option').encounterQuickCheck && cd > _1m) ? (interval - cd % interval) / 4 : interval; // 让倒计时显示更平滑 - setTimeout(() => updateEncounter(engage), interval); - } catch (e) {console.error(e)}} - - function onEncounter() { - if (getValue('disabled') || getValue('battle') || !checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { - return; - } - setEncounter(getEncounter()); // 离开页面前保存 - if(!window.top.location.href.endsWith(`?s=Battle`)){ - setValue('lastHref', window.top.location.href); + if (isIsekai) { + window.location.href = domain; + return; } - $ajax.openNoFetch('https://e-hentai.org/news.php?encounter'); - } + window.location.href = `${domain}/isekai/`; +} - async function startUpdateArena(idleStart, startIdleArena=true) { try { - const now = time(0); - console.log('startUpdateArena now', now, idleStart); - if (!idleStart) { - await updateArena(); +function idleArena() { // 闲置竞技场 + let arena = getValue('arena', true) || {}; + if (arena.date !== g('dateNow')) { + arena = { + date: g('dateNow'), + gr: g('option').idleArenaGrTime, + token: { + length: 0, + }, + }; + // iframe打开四个网站,设定四个判断值,同时true才继续 + const getToken = function (data, e) { + const imgs = gE('img[src*="startchallenge.png"]', 'all', data); + if (e.target.responseURL.match(/ss=gr$/)) { + arena.token.gr = gE('img[src*="startgrindfest.png"]', data).getAttribute('onclick').match(/init_battle\(1, '(.*?)'\)/)[1]; + } else { + imgs.forEach((_) => { + const temp = _.getAttribute('onclick').match(/init_battle\((\d+),\d+,'(.*?)'\)/); + arena.token[temp[1]] = temp[2]; + }); + } + arena.token.length++; + }; + post('?s=Battle&ss=gr', getToken); + post('?s=Battle&ss=ar', getToken); + post('?s=Battle&ss=ar&page=2', getToken); + post('?s=Battle&ss=rb', getToken); + var checkOnload = function () { + if (arena.token.length < 4) { + setTimeout(checkOnload, 200); + } else { + setValue('arena', arena); + setTimeout(idleArena, 200); + } + }; + checkOnload(); + return; } - let timeout = g('option').idleArenaTime * _1s; - console.log('startUpdateArena timeout', timeout); - if (idleStart) { - timeout -= time(0) - idleStart; + if (arena.isOk) { + setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * 1000) + return; } - if(startIdleArena){ - setTimeout(idleArena, timeout); + if (g('option').restoreStamina && gE('#stamina_readout .fc4.far>div').textContent.match(/\d+/)[0] * 1 <= g('option').staminaLow && gE('#stamina_readout .fc4.far>div').textContent.match(/\d+/)[0] * 1 < 85) { + post(window.location.href, goto, 'recover=stamina'); + return; } - const last = getValue('arena', true)?.date ?? now; - setTimeout(startUpdateArena, Math.max(0, Math.floor(last / _1d + 1) * _1d - now)); - } catch (e) {console.error(e)}} - - async function updateArena(forceUpdateToken = false) { try { - let arena = getValue('arena', true) ?? {}; - const isToday = arena.date && time(2, arena.date) === time(2); - if (forceUpdateToken || !isToday || !arena.isOptionUpdated) { - arena.token = {}; - arena.sites ??= [ - '?s=Battle&ss=gr', - '?s=Battle&ss=ar', - '?s=Battle&ss=ar&page=2', - '?s=Battle&ss=rb' - ] - await Promise.all(arena.sites.map(async site => { try { - const doc = $doc(await $ajax.fetch(site)); - if (site === '?s=Battle&ss=gr') { - arena.token.gr = gE('img[src*="startgrindfest.png"]', doc).getAttribute('onclick').match(/init_battle\(1, '(.*?)'\)/)[1]; - return; + arena.array = arena.array || g('option').idleArenaValue.split(','); + let href; let + id; + while (arena.array.length > 0) { + id = arena.array[0] * 1; + if (isNaN(id)) { + href = 'gr'; + id = 'gr'; + } else if (id >= 105) { + href = 'rb'; + } else if (id >= 19) { + href = 'ar&page=2'; + } else { + href = 'ar'; } - gE('img[src*="startchallenge.png"]', 'all', doc).forEach((_) => { - const temp = _.getAttribute('onclick').match(/init_battle\((\d+),\d+,'(.*?)'\)/); - arena.token[temp[1]] = temp[2]; - }); - } catch (e) {console.error(e)}})); - } - if(!isToday){ - arena.date = time(0); - arena.gr = g('option').idleArenaGrTime; - arena.arrayDone = []; - } - if (!isToday || !arena.isOptionUpdated) { - arena.array = g('option').idleArenaValue.split(',') ?? []; - arena.array.reverse(); - } - return setValue('arena', arena); - } catch (e) {console.error(e)}} - - function checkBattleReady(method, condition = {}) { - if (getValue('disabled')) { - setTimeout(method, _1s); - return; - } - if (condition.checkEncounter && getEncounter()[0]?.href && !getEncounter()[0]?.encountered) { - Debug.log(getEncounter()); - return; - } - const staminaChecked = checkStamina(condition.staminaLow, condition.staminaCost); - console.log("staminaChecked", condition.staminaLow, condition.staminaCost, staminaChecked); - if (staminaChecked) { // 1: succeed, -1: failed with nature recover - return staminaChecked === 1; - } - setTimeout(method, Math.floor(time(0) / _1h + 1) * _1h - time(0)); - } - - async function idleArena() { try { // 闲置竞技场 - let arena = getValue('arena', true); - console.log('arena:', getValue('arena', true)); - if (arena.array.length === 0) { - setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); - return; - } - logSwitchAsyncTask(arguments); - const array = [...arena.array]; - let id; - const RBundone = []; - while (array.length > 0) { - id = array.pop() * 1; - id = isNaN(id) ? 'gr' : id; - if(arena.arrayDone?.includes(id)){ - id = undefined; - continue; - } - if (id in arena.token) { - break; - } - if (id >= 105) { - arena.token = (await updateArena(true)).token; - if (id in arena.token) { - break; + if (!(id in arena.token)) { + arena.array.splice(0, 1); + } else { + break; } - } - id = undefined; - } - if (!id) { - setValue('arena', arena); - logSwitchAsyncTask(arguments); - return; - } - let staminaCost = { - 1: 2, 3: 4, 5: 6, 8: 8, 9: 10, - 11: 12, 12: 15, 13: 20, 15: 25, 16: 30, - 17: 35, 19: 40, 20: 45, 21: 50, 23: 55, - 24: 60, 26: 65, 27: 70, 28: 75, 29: 80, - 32: 85, 33: 90, 34: 95, 35: 100, - 105: 1, 106: 1, 107: 1, 108: 1, 109: 1, 110: 1, 111: 1, 112: 1, - gr: arena.gr - } - let stamina = getValue('stamina'); - const lastTime = getValue('staminaTime'); - let timeNow = Math.floor(time(0) / 1000 / 60 / 60); - stamina += lastTime ? timeNow - lastTime : 0; - for (let key in staminaCost) { - staminaCost[key] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) } - staminaCost.gr += 1 - - let href, cost; - let token = arena.token[id]; - const key = id; - if (key === 'gr') { - if (arena.gr <= 0) { + document.title = _alert(-1, '闲置竞技场', '閒置競技場開始', 'Idle Arena start'); + if (arena.array[0] === 'gr' && arena.gr <= 0) { + arena.array.splice(0, 1); setValue('arena', arena); idleArena(); - arena.arrayDone.push('gr'); return; - } - arena.gr--; - href = 'gr'; - key = 1; - cost = staminaCost.gr; - } else if (key >= 105) { - href = 'rb'; - } else if (key >= 19) { - href = 'ar&page=2'; + } if (arena.array[0] === 'gr' && arena.gr > 0) { + arena.gr--; } else { - href = 'ar'; - } - cost ??= staminaCost[key]; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true })) { - logSwitchAsyncTask(arguments); - return; - } - document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); - if(key !== 'gr'){ - arena.arrayDone.push(key); + arena.array.splice(0, 1); } + if (arena.array.length === 0) arena.isOk = true; setValue('arena', arena); - $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} + const token = arena.token[id]; + if (id === 'gr') id = 1; + post(`?s=Battle&ss=${href}`, goto, `initid=${String(id)}&inittoken=${token}`); +} - // 战斗中// - function onBattle() { // 主程序 - let battle = getValue('battle', true); - if (!battle || !battle.roundAll) { // 修复因多个页面/世界同时读写造成缓存数据异常的情况 - battle = JSON.parse(JSON.stringify(g('battle'))); - battle.monsterStatus = battle.monsterStatus.map(ms => { - return { - order: ms.order, - hp: ms.hp - } - }) - battle.monsterStatus.sort(objArrSort('order')); +function encounterCheck() { // encounter + const timeNow = time(0); + const encounter = (getValue('encounter') && getValue('encounter', true).dateNow === g('dateNow')) ? getValue('encounter', true) : { + dateNow: g('dateNow'), + time: 0, }; - Debug.log('onBattle', `\n`, JSON.stringify(battle, null, 4)); - //人物状态 - if (gE('#vbh')) { - g('hp', gE('#vbh>div>img').offsetWidth / 500 * 100); - g('mp', gE('#vbm>div>img').offsetWidth / 210 * 100); - g('sp', gE('#vbs>div>img').offsetWidth / 210 * 100); - g('oc', gE('#vcp>div>div') ? (gE('#vcp>div>div', 'all').length - gE('#vcp>div>div#vcr', 'all').length) * 25 : 0); - } else { - g('hp', gE('#dvbh>div>img').offsetWidth / 418 * 100); - g('mp', gE('#dvbm>div>img').offsetWidth / 418 * 100); - g('sp', gE('#dvbs>div>img').offsetWidth / 418 * 100); - g('oc', gE('#dvrc').childNodes[0].textContent * 1); - } - - // 战斗战况 - if (!gE('.hvAALog')) { - const div = gE('#hvAABox2').appendChild(cE('div')); - div.className = 'hvAALog'; + if (!encounter.lastTime || (timeNow - encounter.lastTime >= 30 * 60 * 1000 && encounter.time < 24)) { + if (g('option').restoreStamina && gE('#stamina_readout .fc4.far>div').textContent.match(/\d+/)[0] * 1 <= g('option').staminaLow) { + post(window.location.href, goto, 'recover=stamina'); + return; + } + encounter.lastTime = timeNow; + setValue('encounter', encounter); + openUrl('https://e-hentai.org/news.php?encounter'); + return; } - const status = [ - '物理物理Physical', - 'Fire', - 'Cold', - 'Elec', - 'Wind', - 'Divine', - 'Forbidden', - ]; - function getBattleTypeDisplay(isTitle) { - const battleInfoList = { - 'gr': { - name: ['压榨', '壓榨', 'Grindfest'], - title: 'GF', - }, - 'iw': { - name: ['道具', '道具', 'Item World'], - title: 'IW', - }, - 'ar': { - name: ['竞技', '競技', 'Arena'], - title: 'AR', - list: [ - ['第一滴血', '第一滴血', 'First Blood', 1, 2], - ['经验曲线', '經驗曲綫', 'Learning Curves', 10, 4], - ['毕业典礼', '畢業典禮', 'Graduation', 20, 6], - ['荒凉之路', '荒涼之路', 'Road Less Traveled', 30, 8], - ['浪迹天涯', '浪跡天涯', 'A Rolling Stone', 40, 10], - ['鲜肉一族', '鮮肉一族', 'Fresh Meat', 50, 12], - ['乌云密布', '烏雲密佈', 'Dark Skies', 60, 15], - ['风暴成形', '風暴成形', 'Growing Storm', 70, 20], - ['力量流失', '力量流失', 'Power Flux', 80, 25], - ['杀戮地带', '殺戮地帶', 'Killzone', 90, 30], - ['最终阶段', '最終階段', 'Endgame', 100, 35], - ['无尽旅程', '無盡旅程', 'Longest Journey', 110, 40], - ['梦陨之时', '夢隕之時', 'Dreamfall', 120, 45], - ['流亡之途', '流亡之途', 'Exile', 130, 50], - ['封印之力', '封印之力', 'Sealed Power', 140, 55], - ['崭新之翼', '嶄新之翼', 'New Wings', 150, 60], - ['弑神之路', '弑神之路', 'To Kill a God', 165, 65], - ['死亡前夜', '死亡前夜', 'Eve of Death', 180, 70], - ['命运三女神与树', '命運三女神與樹', 'The Trio and the Tree', 200, 75], - ['世界末日', '世界末日', 'End of Days', 225, 80], - ['永恒黑暗', '永恆黑暗', 'Eternal Darkness', 250, 85], - ['与龙共舞', '與龍之舞', 'A Dance with Dragons', 300, 90], - ['额外游戏内容', '額外游戲内容', 'Post Game Content', 400, 95], - ['神秘小马领域', '神秘小馬領域', 'Secret Pony Level', 500, 100], - ], - condition: (bt) => bt[4] === battle.roundAll, - content: (bt) => bt[3], - }, - 'rb': { - name: ['浴血', '浴血', 'Ring of Blood'], - title: 'RB', - list: [ - ['九死一树', '九死一樹', 'Triple Trio and the Tree', 250, 'Yggdrasil'], - ['飞天意面怪', '飛行義大利麵怪物', 'Flying Spaghetti Monster', 200], - ['隐形粉红独角兽', '隱形粉紅獨角獸', 'Invisible Pink Unicorn', 150], - ['现实生活', '現實生活', 'Real Life', 100], - ['长门有希', '長門有希', 'Yuki Nagato', 75], - ['朝仓凉子', '朝倉涼子', 'Ryouko Asakura', 75], - ['朝比奈实玖瑠', '朝比奈實玖瑠', 'Mikuru Asahina', 75], - ['泉此方', '泉此方', 'Konata', 75], - ], - condition: (bt) => monsterNames.indexOf(bt[4] ?? bt[2]) !== -1, - content: (bt) => bt[3], - }, - 'ba': { - name: ['遭遇', '遭遇', 'Random Encounter'], - title: 'BA', - content: (_) => getEncounter().filter(e => e.encountered).length, - }, - 'tw': { - name: ['塔楼', '塔樓', 'The Tower'], - title: 'TW', - list: [ - ['PFUDOR×20', 'PFUDOR×20', 'PFUDOR×20', 40], - ['IWBTH×15', 'IWBTH×15', 'IWBTH×15', 34], - ['任天堂×10', '任天堂×10', 'Nintendo×10', 27], - ['地狱×7', '地獄×7', 'Hell×7', 20], - ['噩梦×4', '噩夢×4', 'Nightmare×4', 14], - ['困难×2', '困難×2', 'Hard×2', 7], - ['普通×1', '普通×1', 'Normal×1', 1], - ], - condition: (bt) => bt[3] && bt[3] <= battle.tower, - content: (_) => battle.tower, - end: battle.tower > 40 ? `+${(battle.tower - 40) * 5}%DMG&HP` : '', - } - } - const type = battle.roundType; - let subtype, title; - const monsterNames = Array.from(gE('div.btm3>div>div', 'all')).map(monster => monster.innerHTML); - const lang = g('lang') * 1; - const info = battleInfoList[type]; - switch (type) { - case 'ar': - case 'rb': - case 'tw': - case 'ba': - for (let sub of (info.list ?? [[]])) { - if (info.condition && !info.condition(sub)) { - continue; - } - title = `${info.title}${info.content(sub)}`; - if (!sub[lang]) { - break; - } - subtype = `${sub[lang] ? `
      ${sub[lang]}` : ``}${info.end ? `
      ${info.end}` : ``}`; - break; - } - break; - case 'iw': - case 'gr': - title = `${info.title}`; - break; - default: - break; - } - return isTitle ? title : `${(info?.name ?? ['未知', '未知', 'Unknown'])[lang]}:[${title}]${subtype ?? ''}`; + let lastEncounter; + if (gE('.lastEncounter')) { + lastEncounter = gE('.lastEncounter'); + } else { + lastEncounter = gE('body').appendChild(cE('a')); + lastEncounter.className = 'lastEncounter'; + lastEncounter.title = `${time(3, encounter.lastTime)}\nEncounter TIme: ${encounter.time}`; + lastEncounter.href = 'https://e-hentai.org/news.php?encounter'; + lastEncounter.onclick = function () { + if (encounter.time >= 24 && _alert(1, '是否重置', '是否重置', 'Whether to reset')) delValue('encounter'); + }; } - - const currentTurn = (battle.turn ?? 0) + 1; - - gE('.hvAALog').innerHTML = [ - `攻击模式攻擊模式Attack Mode: ${status[g('attackStatus')]}`, - `${isIsekai ? '异世界異世界Isekai' : '恒定世界恆定世界Persistent'}`, // 战役模式显示 - `${getBattleTypeDisplay()}`, // 战役模式显示 - `R${battle.roundNow}/${battle.roundAll}:T${currentTurn}`, - `TPS: ${g('runSpeed')}`, - `敌人敌人Monsters: ${g('monsterAlive')}/${g('monsterAll')}`, - ].join(`
      `); - if (!battle.roundAll) { - pauseChange(); - Debug.shiftLog(); + lastEncounter.innerHTML = `${Math.floor((timeNow - encounter.lastTime) / 1000 / 60)}分钟前分鐘前 mins before`; + setTimeout(encounterCheck, 1 * 60 * 1000 * (Math.random() * 20 + 90) / 100); +} +// 战斗中// +function main() { // 主程序 + if (getValue('disabled')) { // 如果禁用 + document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); + gE('#hvAABox2>button').innerHTML = '继续繼續Continue'; + return; } - document.title = `${getBattleTypeDisplay(true)}:R${battle.roundNow}/${battle.roundAll}:T${currentTurn}@${g('runSpeed')}tps,${g('monsterAlive')}/${g('monsterAll')}`; - setValue('battle', battle); - if (!battle.monsterStatus || battle.monsterStatus.length !== g('monsterAll')) { - fixMonsterStatus(); + if (getValue('monsterStatus') && getValue('monsterStatus', true).length === g('monsterAll')) { + g('monsterStatus', getValue('monsterStatus', true)); + } else { + fixMonsterStatus(); } - countMonsterHP(); - displayMonsterWeight(); - displayPlayStatePercentage(); - - if (getValue('disabled')) { // 如果禁用 - document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - gE('#hvAABox2>button').innerHTML = '继续繼續Continue'; - return; + g('turn', g('turn') + 1); + if (gE('#vbh')) { + g('hp', gE('#vbh>div>img').offsetWidth / 500 * 100); + g('mp', gE('#vbm>div>img').offsetWidth / 210 * 100); + g('sp', gE('#vbs>div>img').offsetWidth / 210 * 100); + g('oc', gE('#vcp>div>div') ? (gE('#vcp>div>div', 'all').length - gE('#vcp>div>div#vcr', 'all').length) * 25 : 0); + } else { + g('hp', gE('#dvbh>div>img').offsetWidth / 418 * 100); + g('mp', gE('#dvbm>div>img').offsetWidth / 418 * 100); + g('sp', gE('#dvbs>div>img').offsetWidth / 418 * 100); + g('oc', gE('#dvrc').textContent); } - battle = getValue('battle', true); - g('battle').turn = currentTurn; - battle.turn = currentTurn; - setValue('battle', battle); - + battleInfo(); // 战斗战况 killBug(); // 解决 HentaiVerse 可能出现的 bug - + countMonsterHP(); // 统计敌人血量 if (g('option').autoFlee && checkCondition(g('option').fleeCondition)) { - gE('1001').click(); - SetExitBattleTimeout('Flee'); - return; - } - var taskList = { - 'Pause': autoPause, - 'Rec': autoRecover, - 'Def': autoDefend, - 'Scroll': useScroll, - 'Channel': useChannelSkill, - 'Buff': useBuffSkill, - 'Infus': useInfusions, - 'Debuff': useDeSkill, - 'Focus': autoFocus, - 'SS': autoSS, - 'Skill': autoSkill, - 'Atk': attack, - }; - const names = g('option').battleOrderName?.split(',') ?? []; - for (let i = 0; i < names.length; i++) { - if(taskList[names[i]]()){ + gE('1001').click(); + setTimeout(goto, 3 * 1000); return; - } - delete taskList[names[i]]; } - for (let name in taskList) { - if (taskList[name]()) { - return; - } - } - } - function getMonsterID(s) { - if (s.order !== undefined) { - return (s.order + 1) % 10; - } // case is monsterStatus - return (s + 1) % 10; // case is order - } + g('end', false); + var taskList = [useGem, deadSoon, autoPause, autoDefend, useScroll, useChannelSkill, useBuffSkill, useInfusions, useDeSkill, autoFocus, autoSS, autoSkill, attack] - /** - * 按照技能范围,获取包含原目标且范围内最终权重(finweight)之和最低的范围的中心目标 - * @param {int} id id from g('battle').monsterStatus.sort(objArrSort('finWeight')); - * @param {int} range radius, 0 for single-target and all-targets, 1 for treble-targets, ..., n for (2n+1) targets - * @param {(target) => bool} excludeCondition target with id - * @returns - */ - function getRangeCenterID(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined) { - if (!range) { - return getMonsterID(target); + for (let i in taskList) { + const task = taskList[i]; + if (g('end', task())) return; } - const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (g('option').centralExtraRatio / 100) ?? 0 : 0)); +} + +/** + * 按照技能范围,获取包含原目标且范围内最终权重(finweight)之和最低的范围的中心目标 + * @param {int} id id from g('monsterStatus').sort(objArrSort('finWeight')); + * @param {int} range radius, 0 for single-target and all-targets, 1 for treble-targets, ..., n for (2n+1) targets + * @param {(target) => bool} excludeCondition target with id + * @returns + */ +function getRangeCenter(target, range = 0, excludeCondition = undefined) { + if (range === 0) { + return target; + } + let minRank, maxWeight; let order = target.order; let newOrder = order; // sort by order to fix id - let msTemp = JSON.parse(JSON.stringify(g('battle').monsterStatus)); - msTemp.sort(objArrSort('order')); - let unreachableWeight = g('option').unreachableWeight; - let minRank; + g('monsterStatus').sort(objArrSort('order')); + for (let i = order - 2 * range; i <= order + 2 * range; i++) { + if (i < 0 || i >= g('monsterStatus').length) { + continue; + } + let weight = g('monsterStatus')[i].finWeight; + weight = (weight == Infinity) ? 0 : weight + maxWeight = maxWeight > weight ? maxWeight : weight; + } + maxWeight *= ((range === 0) ? 1 : (range * 2)) for (let i = order - range; i <= order + range; i++) { - if (i < 0 || i >= msTemp.length || msTemp[i].isDead) { - continue; // 无法选中 - } - let rank = 0; - for (let j = i - range; j <= (i + range); j++) { - let cew = j === i ? centralExtraWeight : 0; // cew <= 0, 增加未命中权重,降低命中权重 - let mon = msTemp[j]; - if (j < 0 || j >= msTemp.length // 超出范围 - || mon.isDead // 死亡目标 - || (excludeCondition && excludeCondition(mon))) { // 特殊排除判定 - rank += unreachableWeight - cew; - continue; + let rank = 0; + if (i < 0 || i >= g('monsterStatus').length) { + continue; + } + if (g('monsterStatus')[i].isDead) { + continue; + } + for (let j = i - range; j <= (i + range); j++) { + if (j < 0 || j >= g('monsterStatus').length) { + rank += maxWeight + continue; + } + let mon = g('monsterStatus')[j] + if (mon.isDead) { + rank += maxWeight + continue; + } + if (excludeCondition && excludeCondition(mon)) { + rank += maxWeight + continue; + } + rank += mon.finWeight + } + if (rank < minRank) { + newOrder = i; } - rank += mon.finWeight + cew; // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 - } - if (rank < minRank) { - newOrder = i; - } } - return getMonsterID(newOrder); - } + target = g('monsterStatus')[newOrder] + // reset to sorted by finWeight + g('monsterStatus').sort(objArrSort('finWeight')); + return target +} - function autoPause() { +function autoPause() { if (g('option').autoPause && checkCondition(g('option').pauseCondition)) { - pauseChange(); - return true; + pauseChange(); + return true; } return false; - } +} - function autoDefend() { +function autoDefend() { if (g('option').defend && checkCondition(g('option').defendCondition)) { - gE('#ckey_defend').click(); - return true; + gE('#ckey_defend').click(); + return true; } return false; - } +} - function pauseChange() { // 暂停状态更改 +function pauseChange() { // 暂停状态更改 if (getValue('disabled')) { - if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '暂停暫停Pause'; - } - document.title = getValue('disabled'); - delValue(0); - if (!gE('#navbar')) { // in battle - onBattle(); - } + if (gE('.pauseChange')) gE('.pauseChange').innerHTML = '暂停暫停Pause'; + delValue(0); + main(); } else { - if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '继续繼續Continue'; - } - setValue('disabled', document.title); - document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - } - } - - function SetExitBattleTimeout(alarm){ - setAlarm(alarm); - if(alarm === 'SkipDefeated') return; - delValue(1); - if(g('option').ExitBattleWaitTime) { - setTimeout(() => { - $ajax.open(getValue('lastHref')); - }, g('option').ExitBattleWaitTime * _1s); - return; + if (gE('.pauseChange')) gE('.pauseChange').innerHTML = '继续繼續Continue'; + setValue('disabled', true); } - $ajax.open(getValue('lastHref')); - } +} - function reloader() { - let obj; let a; let cost; - const battleUnresponsive = { - 'Alert': { Method: setAlarm }, - 'Reload': { Method: goto }, - 'Alt': { Method: gotoAlt } - } - function clearBattleUnresponsive(){ - Object.keys(battleUnresponsive).forEach(t=>clearTimeout(battleUnresponsive[t].Timeout)); - } +function reloader() { + let delayAlert; let delayReload; let obj; let a; let + cost; const eventStart = cE('a'); eventStart.id = 'eventStart'; eventStart.onclick = function () { - a = unsafeWindow.info; - for(let t in g('option').battleUnresponsive) { - if (g('option').battleUnresponsive[t]) { - battleUnresponsive[t].Timeout = setTimeout(battleUnresponsive[t].Method, Math.max(1, g('option').battleUnresponsiveTime[t]) * _1s); - } - } - if (g('option').recordUsage) { - obj = { - mode: a.mode, - }; - if (a.mode === 'items') { - obj.item = gE(`#pane_item div[id^="ikey"][onclick*="skill('${a.skill}')"]`).textContent; - } else if (a.mode === 'magic') { - obj.magic = gE(a.skill).textContent; - cost = gE(a.skill).getAttribute('onmouseover').match(/\('.*', '.*', '.*', (\d+), (\d+), \d+\)/); - obj.mp = cost[1] * 1; - obj.oc = cost[2] * 1; + a = unsafeWindow.info; + if (g('option').delayAlert) delayAlert = setTimeout(setAlarm, g('option').delayAlertTime * 1000); + if (g('option').delayReload) delayReload = setTimeout(goto, g('option').delayReloadTime * 1000); + if (g('option').recordUsage) { + obj = { + mode: a.mode, + }; + if (a.mode === 'items') { + obj.item = gE(`#pane_item div[id^="ikey"][onclick*="skill('${a.skill}')"]`).textContent; + } else if (a.mode === 'magic') { + obj.magic = gE(a.skill).textContent; + cost = gE(a.skill).getAttribute('onmouseover').match(/\('.*', '.*', '.*', (\d+), (\d+), \d+\)/); + obj.mp = cost[1] * 1; + obj.oc = cost[2] * 1; + } } - } }; gE('body').appendChild(eventStart); const eventEnd = cE('a'); eventEnd.id = 'eventEnd'; eventEnd.onclick = function () { - const timeNow = time(0); - g('runSpeed', (1000 / (timeNow - g('timeNow'))).toFixed(2)); - g('timeNow', timeNow); - const monsterDead = gE('img[src*="nbardead"]', 'all').length; - g('monsterAlive', g('monsterAll') - monsterDead); - const bossDead = gE('div.btm1[style*="opacity"] div.btm2[style*="background"]', 'all').length; - g('bossAlive', g('bossAll') - bossDead); - const battleLog = gE('#textlog>tbody>tr>td', 'all'); - if (g('option').recordUsage) { - obj.log = battleLog; - recordUsage(obj); - } - if (g('monsterAlive') && !gE('#btcp')) { - clearBattleUnresponsive(); - onBattle(); - return; - } - if (g('option').dropMonitor) { - dropMonitor(battleLog); - } - if (g('option').recordUsage) { - recordUsage2(); - } - if (g('battle').roundNow !== g('battle').roundAll) { // Next Round - if(g('option').NewRoundWaitTime){ - setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); - } else { - onNewRound(); - } - return; - - async function onNewRound(){ - try { - const html = await $ajax.fetch(window.location.href); - - gE('#pane_completion').removeChild(gE('#btcp')); - clearBattleUnresponsive(); - const doc = $doc(html) - if (gE('#riddlecounter', doc)) { - if (g('option').riddlePopup && !window.opener) { - window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); - return; - } - goto(); - return; + const timeNow = time(0); + g('runSpeed', (1000 / (timeNow - g('timeNow'))).toFixed(2)); + g('timeNow', timeNow); + if (g('option').delayAlert) clearTimeout(delayAlert); + if (g('option').delayReload) clearTimeout(delayReload); + const monsterDead = gE('img[src*="nbardead"]', 'all').length; + g('monsterAlive', g('monsterAll') - monsterDead); + const bossDead = gE('div.btm1[style*="opacity"] div.btm2[style*="background"]', 'all').length; + g('bossAlive', g('bossAll') - bossDead); + const battleLog = gE('#textlog>tbody>tr>td', 'all'); + if (g('option').recordUsage) { + obj.log = battleLog; + recordUsage(obj); + } + if (gE('#btcp')) { + if (g('option').dropMonitor) dropMonitor(battleLog); + if (g('option').recordUsage) recordUsage2(); + if (g('monsterAlive') > 0) { // Defeat + setAlarm('Defeat'); + delValue(2); + } else if (g('roundNow') !== g('roundAll')) { // Next Round + gE('#pane_completion').removeChild(gE('#btcp')); + post(window.location.href, (data) => { + if (gE('#riddlecounter', data)) { + if (g('option').riddlePopup && !window.opener) { + window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); + return; + } + goto(); + return; + } + gE('#battle_main').replaceChild(gE('#battle_right', data), gE('#battle_right')); + gE('#battle_main').replaceChild(gE('#battle_left', data), gE('#battle_left')); + unsafeWindow.battle = new unsafeWindow.Battle(); + unsafeWindow.battle.clear_infopane(); + newRound(); + main(); + }); + } else if (g('roundNow') === g('roundAll')) { // Victory + setAlarm('Victory'); + delValue(2); + setTimeout(goto, 3 * 1000); } - ['#battle_right', '#battle_left'].forEach(selector=>{ gE('#battle_main').replaceChild(gE(selector, doc), gE(selector)); }) - unsafeWindow.battle = new unsafeWindow.Battle(); - unsafeWindow.battle.clear_infopane(); - Debug.log('______________newRound', true); - newRound(true); - onBattle(); - } catch(e) { e=>console.error(e) } + } else { + main(); } - } - - if (g('monsterAlive') > 0) { // Defeat - SetExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); - } - if (g('battle').roundNow === g('battle').roundAll) { // Victory - SetExitBattleTimeout('Victory'); - } - clearBattleUnresponsive(); }; gE('body').appendChild(eventEnd); window.sessionStorage.delay = g('option').delay; window.sessionStorage.delay2 = g('option').delay2; const fakeApiCall = cE('script'); fakeApiCall.textContent = `api_call = ${function (b, a, d) { - const delay = window.sessionStorage.delay * 1; - const delay2 = window.sessionStorage.delay2 * 1; - window.info = a; - b.open('POST', `${MAIN_URL}json`); - b.setRequestHeader('Content-Type', 'application/json'); - b.withCredentials = true; - b.onreadystatechange = d; - b.onload = function () { - document.getElementById('eventEnd').click(); - }; - document.getElementById('eventStart').click(); - if (a.mode === 'magic' && a.skill >= 200) { - if (delay <= 0) { - b.send(JSON.stringify(a)); - } else { - setTimeout(() => { + const delay = window.sessionStorage.delay * 1; + const delay2 = window.sessionStorage.delay2 * 1; + window.info = a; + b.open('POST', `${MAIN_URL}json`); + b.setRequestHeader('Content-Type', 'application/json'); + b.withCredentials = true; + b.onreadystatechange = d; + b.onload = function () { + document.getElementById('eventEnd').click(); + }; + document.getElementById('eventStart').click(); + if (a.mode === 'magic' && a.skill >= 200) { + if (delay <= 0) { + b.send(JSON.stringify(a)); + } else { + setTimeout(() => { + b.send(JSON.stringify(a)); + }, delay * (Math.random() * 50 + 50) / 100); + } + } else if (delay2 <= 0) { b.send(JSON.stringify(a)); - }, delay * (Math.random() * 50 + 50) / 100); + } else { + setTimeout(() => { + b.send(JSON.stringify(a)); + }, delay2 * (Math.random() * 50 + 50) / 100); } - } else if (delay2 <= 0) { - b.send(JSON.stringify(a)); - } else { - setTimeout(() => { - b.send(JSON.stringify(a)); - }, delay2 * (Math.random() * 50 + 50) / 100); - } }.toString()}`; gE('head').appendChild(fakeApiCall); const fakeApiResponse = cE('script'); fakeApiResponse.textContent = `api_response = ${function (b) { - if (b.readyState === 4) { - if (b.status === 200) { - const a = JSON.parse(b.responseText); - if (a.login !== undefined) { - top.window.location.href = login_url; - } else { - if (a.error || a.reload) { - window.location.href = window.location.search; + if (b.readyState === 4) { + if (b.status === 200) { + const a = JSON.parse(b.responseText); + if (a.login !== undefined) { + top.window.location.href = login_url; + } else { + if (a.error || a.reload) window.location.href = window.location.search; + return a; + } + } else { + window.location.href = window.location.search; } - return a; - } - } else { - window.location.href = window.location.search; } - } - return false; + return false; }.toString()}`; gE('head').appendChild(fakeApiResponse); - } +} - function newRound(isNew) { // New Round - let battle = isNew ? {} : getValue('battle', true); - if (!battle) { - battle = JSON.parse(JSON.stringify(g('battle') ?? {})); - battle.monsterStatus?.sort(objArrSort('order')); - }; - setValue('battle', battle); - if (window.location.hash !== '') { - goto(); - } +function newRound() { // New Round + g('turn', 0); + if (window.location.hash !== '') goto(); g('monsterAll', gE('div.btm1', 'all').length); const monsterDead = gE('img[src*="nbardead"]', 'all').length; g('monsterAlive', g('monsterAll') - monsterDead); @@ -3070,827 +2043,819 @@ try { const bossDead = gE('div.btm1[style*="opacity"] div.btm2[style*="background"]', 'all').length; g('bossAlive', g('bossAll') - bossDead); const battleLog = gE('#textlog>tbody>tr>td', 'all'); - if (!battle.roundType) { - const temp = battleLog[battleLog.length - 1].textContent; - const types = { - 'ar': { - reg: /^Initializing arena challenge/, - extra: (i) => i <= 35, - }, - 'rb': { - reg: /^Initializing arena challenge/, - extra: (i) => i >= 105, - }, - 'iw': { reg: /^Initializing Item World/ }, - 'gr': { reg: /^Initializing Grindfest/ }, - 'tw': { reg: /^Initializing The Tower/ }, - 'ba': { - reg: /^Initializing random encounter/, - extra: (_) => { - const encounter = getEncounter(); - if (encounter[0] && encounter[0].time >= time(0) - 0.5 * _1h) { - encounter[0].encountered = time(0); - setEncounter(encounter); + g('roundType', (function () { + if (getValue('roundType')) { + return getValue('roundType'); + } + let roundType; + const temp = battleLog[battleLog.length - 1].textContent; + if (!temp.match(/^Initializing/)) { + roundType = ''; + } else if (temp.match(/^Initializing arena challenge/) && temp.match(/\d+/)[0] * 1 <= 35) { + roundType = 'ar'; + } else if (temp.match(/^Initializing arena challenge/) && temp.match(/\d+/)[0] * 1 >= 105) { + roundType = 'rb'; + } else if (temp.match(/^Initializing random encounter/)) { + roundType = 'ba'; + if (g('option').encounter) { + const encounter = getValue('encounter', true); + encounter.lastTime = time(0); + encounter.time++; + setValue('encounter', encounter); } - return true; - } - }, - } - battle.tower = (temp.match(/\(Floor (\d+)\)/) ?? [null])[1] * 1; - const id = (temp.match(/\d+/) ?? [null])[0] * 1; - battle.roundType = undefined; - for (let name in types) { - const type = types[name]; - if (!temp.match(type.reg)) { - continue; - } - if (type.extra && !type.extra(id)) { - continue; + } else if (temp.match(/^Initializing Item World/)) { + roundType = 'iw'; + } else if (temp.match(/^Initializing Grindfest/)) { + roundType = 'gr'; + } else if (temp.match(/^Initializing The Tower/)) { + roundType = 'tw'; + } else { + roundType = ''; } - battle.roundType = name; - break; - } - } + setValue('roundType', roundType); + return roundType; + }())); if (/You lose \d+ Stamina/.test(battleLog[0].textContent)) { - const staminaLostLog = getValue('staminaLostLog', true) || {}; - staminaLostLog[time(3)] = battleLog[0].textContent.match(/You lose (\d+) Stamina/)[1] * 1; - setValue('staminaLostLog', staminaLostLog); - const losedStamina = battleLog[0].textContent.match(/\d+/)[0] * 1; - if (losedStamina >= g('option').staminaLose) { - setAlarm('Error'); - if (!_alert(1, '当前Stamina过低\n或Stamina损失过多\n是否继续?', '當前Stamina過低\n或Stamina損失過多\n是否繼續?', 'Continue?\nYou either have too little Stamina or have lost too much')) { - pauseChange(); - return; + const staminaLostLog = getValue('staminaLostLog', true) || {}; + staminaLostLog[time(3)] = battleLog[0].textContent.match(/You lose (\d+) Stamina/)[1] * 1; + setValue('staminaLostLog', staminaLostLog); + const losedStamina = battleLog[0].textContent.match(/\d+/)[0] * 1; + if (losedStamina >= g('option').staminaLose) { + setAlarm('Error'); + if (!_alert(1, '当前Stamina过低\n或Stamina损失过多\n是否继续?', '當前Stamina過低\n或Stamina損失過多\n是否繼續?', 'Continue?\nYou either have too little Stamina or have lost too much')) { + pauseChange(); + return; + } } - } } - - const roundPrev = battle.roundNow; - if (battleLog[battleLog.length - 1].textContent.match('Initializing')) { - const monsterStatus = []; - let order = 0; - const monsterNames = Array.from(gE('div.btm3>div>div', 'all')).map(monster => monster.innerText); - const monsterLvs = Array.from(gE('div.btm2>div>div', 'all')).map(monster => monster.innerText); - const monsterDB = getValue('monsterDB', true) ?? {}; - const monsterMID = getValue('monsterMID', true) ?? {}; - const oldDB = JSON.stringify(monsterDB); - const oldMID = JSON.stringify(monsterMID); - for (let i = battleLog.length - 2; i > battleLog.length - 2 - g('monsterAll'); i--) { - let mid = battleLog[i].textContent.match(/MID=(\d+)/)[1] * 1; - let name = battleLog[i].textContent.match(/MID=(\d+) \((.*)\) LV/)[2]; - let lv = battleLog[i].textContent.match(/LV=(\d+)/)[1] * 1; - let hp = battleLog[i].textContent.match(/HP=(\d+)$/)[1] * 1; - if (isNaN(hp)) { - hp = getHPFromMonsterDB(monsterDB, monsterNames[order], monsterLvs[order]) ?? monsterStatus[monsterStatus.length - 1].hp; - } - if (name && lv && mid) { - monsterDB[name] ??= {}; - if (monsterDB[name].mid && monsterDB[name].mid !== mid) { // 名称被其他mid被占用 - monsterMID[monsterDB[name].mid] = JSON.parse(JSON.stringify(monsterDB[name])); // 将之前mid的数据进行另外备份 - monsterDB[name] = {}; // 重置该名称的数据 - } - if (monsterMID[mid]) { - monsterDB[name] = JSON.parse(JSON.stringify(monsterMID[mid])); // 将之前备份的mid的数据进行恢复 - delete monsterMID[mid]; - } - monsterDB[name].mid = mid; - monsterDB[name][lv] = hp; - } - monsterStatus[order] = { - order: order, - hp, - }; - order++; - } - if(g('option').cacheMonsterHP){ - if (oldDB !== JSON.stringify(monsterDB)) { - setValue('monsterDB', monsterDB); - } - if (oldMID !== JSON.stringify(monsterMID)) { - setValue('monsterMID', monsterMID); - } - } - battle.monsterStatus = monsterStatus; - - const round = battleLog[battleLog.length - 1].textContent.match(/\(Round (\d+) \/ (\d+)\)/); - if (round && battle.roundType !== 'ba') { - battle.roundNow = round[1] * 1; - battle.roundAll = round[2] * 1; - } else { - battle.roundNow = 1; - battle.roundAll = 1; - } - } else if (!battle.monsterStatus || battle.monsterStatus.length !== gE('div.btm2', 'all').length) { - battle.roundNow = 1; - battle.roundAll = 1; - } - - if(roundPrev !== battle.roundNow) { - battle.turn = 0; - } - setValue('battle', battle); - - g('roundLeft', battle.roundAll - battle.roundNow); + const monsterStatus = []; + let id = 0; + for (let i = battleLog.length - 2; i > battleLog.length - 2 - g('monsterAll'); i--) { + let hp = battleLog[i].textContent.match(/HP=(\d+)$/)[1] * 1; + if (isNaN(hp)) hp = monsterStatus[monsterStatus.length - 1].hp; + monsterStatus[id] = { + order: id, + id: (id === 9) ? 0 : id + 1, + hp, + }; + id = id + 1; + } + setValue('monsterStatus', monsterStatus); + g('monsterStatus', monsterStatus); + let roundNow; let + roundAll; + const round = battleLog[battleLog.length - 1].textContent.match(/\(Round (\d+) \/ (\d+)\)/); + if (g('roundType') !== 'ba' && round !== null) { + roundNow = round[1] * 1; + roundAll = round[2] * 1; + } else { + roundNow = 1; + roundAll = 1; + } + setValue('roundNow', roundNow); + setValue('roundAll', roundAll); + } else if (!getValue('monsterStatus') || getValue('monsterStatus', true).length !== gE('div.btm2', 'all').length) { + setValue('roundNow', 1); + setValue('roundAll', 1); + fixMonsterStatus(); + } + g('roundNow', getValue('roundNow') * 1); + g('roundAll', getValue('roundAll') * 1); + g('roundLeft', getValue('roundAll') - g('roundNow')); g('skillOTOS', { - OFC: 0, - FRD: 0, - T3: 0, - T2: 0, - T1: 0, + OFC: 0, + FRD: 0, + T3: 0, + T2: 0, + T1: 0, }); - } +} - function killBug() { // 在 HentaiVerse 发生导致 turn 损失的 bug 时发出警告并移除问题元素: https://ehwiki.org/wiki/HentaiVerse_Bugs_%26_Errors#Combat +function killBug() { // 在 HentaiVerse 发生导致 turn 损失的 bug 时发出警告并移除问题元素: https://ehwiki.org/wiki/HentaiVerse_Bugs_%26_Errors#Combat const bugLog = gE('#textlog > tbody > tr > td[class="tlb"]', 'all'); const isBug = /(Slot is currently not usable)|(Item does not exist)|(Inventory slot is empty)|(You do not have a powerup gem)/; for (let i = 0; i < bugLog.length; i++) { - if (bugLog[i].textContent.match(isBug)) { - bugLog[i].className = 'tlbWARN'; - setTimeout(() => { // 间隔时间以避免持续刷新 - window.location.href = window.location;// 刷新移除问题元素 - }, 700); - } else { - bugLog[i].className = 'tlbQRA'; - } + if (bugLog[i].textContent.match(isBug)) { + bugLog[i].className = 'tlbWARN'; + setTimeout(() => { // 间隔时间以避免持续刷新 + window.location.href = window.location;// 刷新移除问题元素 + }, 700); + } else { + bugLog[i].className = 'tlbQRA'; + } } - } +} - function countMonsterHP() { // 统计敌人血量 - let i, j; +function battleInfo() { // 战斗战况 + if (!gE('.hvAALog')) { + const div = gE('#hvAABox2').appendChild(cE('div')); + div.className = 'hvAALog'; + } + const status = [ + '物理物理Physical', + 'Fire', + 'Cold', + 'Elec', + 'Wind', + 'Divine', + 'Forbidden', + ]; + function battleInfoType(type) { // 战役模式显示 + switch (type) { + case 'ar': return 'Arena'; + case 'ba': return 'Random Encounter'; + case 'rb': return 'Ring of Blood'; + case 'tw': return 'The Tower'; + case 'iw': return 'Item World'; + case 'gf': return 'GrindFest'; + } + } + gE('.hvAALog').innerHTML = [ + `Turns: ${g('turn')}`, + `
      Speed: ${g('runSpeed')} t/s`, + `
      Round: ${g('roundNow')}/${g('roundAll')}`, + `
      攻击模式攻擊模式Attack Mode: ${status[g('attackStatus')]}`, + `
      敌人敌人Monsters: ${g('monsterAlive')}/${g('monsterAll')}`, + `
      战役模式戰役模式Type: ${battleInfoType(g('roundType'))}`, // 战役模式显示 + ].join(''); + document.title = `${g('turn')}||${g('runSpeed')}||${g('roundNow')}/${g('roundAll')}||${g('monsterAlive')}/${g('monsterAll')}`; +} + +function countMonsterHP() { // 统计敌人血量 const monsterHp = gE('div.btm4>div.btm5:nth-child(1)', 'all'); - let battle = getValue('battle', true); - const monsterStatus = battle.monsterStatus; + const monsterStatus = g('monsterStatus'); + let i; let + j; const hpArray = []; for (i = 0; i < monsterHp.length; i++) { - if (gE('img[src*="nbardead.png"]', monsterHp[i])) { - monsterStatus[i].isDead = true; - monsterStatus[i].hpNow = Infinity; - } else { - monsterStatus[i].isDead = false; - monsterStatus[i].hpNow = Math.floor(monsterStatus[i].hp * parseFloat(gE('img', monsterHp[i]).style.width) / 120 + 1); - hpArray.push(monsterStatus[i].hpNow); - } + if (gE('img[src*="nbardead.png"]', monsterHp[i])) { + monsterStatus[i].isDead = true; + monsterStatus[i].hpNow = Infinity; + } else { + monsterStatus[i].isDead = false; + monsterStatus[i].hpNow = Math.floor(monsterStatus[i].hp * parseFloat(gE('img', monsterHp[i]).style.width) / 120) + 1; + hpArray.push(monsterStatus[i].hpNow); + } + } + setValue('monsterStatus', monsterStatus); + const hpLowest = Math.min.apply(null, hpArray); + const hpMost = Math.max.apply(null, hpArray); + const deadWeight = g('option').ruleReverse ? -Infinity : Infinity + for (i = 0; i < monsterStatus.length; i++) { + monsterStatus[i].finWeight = (monsterStatus[i].isDead) ? deadWeight : ((g('option').ruleReverse) ? hpMost / monsterStatus[i].hpNow * 10 : monsterStatus[i].hpNow / hpLowest * 10); } - battle.monsterStatus = monsterStatus; - const skillLib = { - Sle: { - name: 'Sleep', - img: 'sleep', - }, - Bl: { - name: 'Blind', - img: 'blind', - }, - Slo: { - name: 'Slow', - img: 'slow', - }, - Im: { - name: 'Imperil', - img: 'imperil', - }, - MN: { - name: 'MagNet', - img: 'magnet', - }, - Si: { - name: 'Silence', - img: 'silence', - }, - Dr: { - name: 'Drain', - img: 'drainhp', - }, - We: { - name: 'Weaken', - img: 'weaken', - }, - Co: { - name: 'Confuse', - img: 'confuse', - }, - CM: { - name: 'Coalesced Mana', - img: 'coalescemana', - }, - Stun: { - name: 'Stunned', - img: 'wpn_stun', - }, - PA: { - name: 'Penetrated Armor', - img: 'wpn_ap', - }, - BW: { - name: 'Bleeding Wound', - img: 'wpn_bleed', - }, + Sle: { + name: 'Sleep', + img: 'sleep', + }, + Bl: { + name: 'Blind', + img: 'blind', + }, + Slo: { + name: 'Slow', + img: 'slow', + }, + Im: { + name: 'Imperil', + img: 'imperil', + }, + MN: { + name: 'MagNet', + img: 'magnet', + }, + Si: { + name: 'Silence', + img: 'silence', + }, + Dr: { + name: 'Drain', + img: 'drainhp', + }, + We: { + name: 'Weaken', + img: 'weaken', + }, + Co: { + name: 'Confuse', + img: 'confuse', + }, + CM: { + name: 'Coalesced Mana', + img: 'coalescemana', + }, + Stun: { + name: 'Stunned', + img: 'wpn_stun', + }, + PA: { + name: 'Penetrated Armor', + img: 'wpn_ap', + }, + BW: { + name: 'Bleeding Wound', + img: 'wpn_bleed', + }, }; const monsterBuff = gE('div.btm6', 'all'); - const hpMin = Math.min.apply(null, hpArray); - const yggdrasilExtraWeight = g('option').YggdrasilExtraWeight; - const unreachableWeight = g('option').unreachableWeight; - const baseHpRatio = g('option').baseHpRatio ?? 1; - // 权重越小,优先级越高 - for (i = 0; i < monsterStatus.length; i++) { // 死亡的排在最后(优先级最低) - if (monsterStatus[i].isDead) { - monsterStatus[i].finWeight = unreachableWeight; - continue; - } - let weight = baseHpRatio * Math.log10(monsterStatus[i].hpNow / hpMin); // > 0 生命越低权重越低优先级越高 - monsterStatus[i].hpWeight = weight; - if (yggdrasilExtraWeight && ('Yggdrasil' === gE('div.btm3>div>div', monsterBuff[i].parentNode).innerText || '世界树 Yggdrasil' === gE('div.btm3>div>div', monsterBuff[i].parentNode).innerText)) { // 默认设置下,任何情况都优先击杀群体大量回血的boss"Yggdrasil" - weight += yggdrasilExtraWeight; // yggdrasilExtraWeight.defalut -1000 - } - for (j in skillLib) { - if (gE(`img[src*="${skillLib[j].img}"]`, monsterBuff[i])) { - weight += g('option').weight[j]; + for (i = 0; i < monsterBuff.length; i++) { + for (j in skillLib) { + monsterStatus[i].finWeight += (gE(`img[src*="${skillLib[j].img}"]`, monsterBuff[i])) ? ((g('option').ruleReverse) ? -g('option').weight[j] : g('option').weight[j]) : 0; } - } - monsterStatus[i].finWeight = weight; } monsterStatus.sort(objArrSort('finWeight')); - battle.monsterStatus = monsterStatus; - g('battle', battle); - } + g('monsterStatus', monsterStatus); +} + +function useGem() { // 自动使用宝石 + if (!gE('#ikey_p')) { + return false; + } + const Gem = gE('#ikey_p').textContent; + if (Gem === 'Health Gem' && g('hp') <= g('option').hp1) { + gE('#ikey_p').click(); + return true; + } else if (Gem === 'Mana Gem' && g('mp') <= g('option').mp1) { + gE('#ikey_p').click(); + return true; + } else if (Gem === 'Spirit Gem' && g('sp') <= g('option').sp1) { + gE('#ikey_p').click(); + return true; + } else if (Gem === 'Mystic Gem') { + gE('#ikey_p').click(); + return true; + } + return false; +} - function autoRecover() { // 自动回血回魔 +function deadSoon() { // 自动回血回魔 if (!g('option').item) { - return false; + return false; } if (!g('option').itemOrderValue) { - return false; + return false; } const name = g('option').itemOrderName.split(','); const order = g('option').itemOrderValue.split(','); for (let i = 0; i < name.length; i++) { - if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(order[i])) { - isOn(order[i]).click(); - return true; - } + if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(order[i])) { + isOn(order[i]).click(); + return true; + } } return false; - } +} - function useScroll() { // 自动使用卷轴 +function useScroll() { // 自动使用卷轴 if (!g('option').scrollSwitch) { - return false; + return false; } if (!g('option').scroll) { - return false; + return false; } if (!checkCondition(g('option').scrollCondition)) { - return false; + return false; } if (!g('option').scrollRoundType) { - return false; + return false; } - if (!g('option').scrollRoundType[g('battle').roundType]) { - return false; + if (!g('option').scrollRoundType[g('roundType')]) { + return false; } const scrollLib = { - Go: { - name: 'Scroll of the Gods', - id: 13299, - mult: '3', - img1: 'absorb', - img2: 'shadowveil', - img3: 'sparklife', - }, - Av: { - name: 'Scroll of the Avatar', - id: 13199, - mult: '2', - img1: 'haste', - img2: 'protection', - }, - Pr: { - name: 'Scroll of Protection', - id: 13111, - mult: '1', - img1: 'protection', - }, - Sw: { - name: 'Scroll of Swiftness', - id: 13101, - mult: '1', - img1: 'haste', - }, - Li: { - name: 'Scroll of Life', - id: 13221, - mult: '1', - img1: 'sparklife', - }, - Sh: { - name: 'Scroll of Shadows', - id: 13211, - mult: '1', - img1: 'shadowveil', - }, - Ab: { - name: 'Scroll of Absorption', - id: 13201, - mult: '1', - img1: 'absorb', - }, + Go: { + name: 'Scroll of the Gods', + id: 13299, + mult: '3', + img1: 'absorb', + img2: 'shadowveil', + img3: 'sparklife', + }, + Av: { + name: 'Scroll of the Avatar', + id: 13199, + mult: '2', + img1: 'haste', + img2: 'protection', + }, + Pr: { + name: 'Scroll of Protection', + id: 13111, + mult: '1', + img1: 'protection', + }, + Sw: { + name: 'Scroll of Swiftness', + id: 13101, + mult: '1', + img1: 'haste', + }, + Li: { + name: 'Scroll of Life', + id: 13221, + mult: '1', + img1: 'sparklife', + }, + Sh: { + name: 'Scroll of Shadows', + id: 13211, + mult: '1', + img1: 'shadowveil', + }, + Ab: { + name: 'Scroll of Absorption', + id: 13201, + mult: '1', + img1: 'absorb', + }, }; const scrollFirst = (g('option').scrollFirst) ? '_scroll' : ''; let isUsed; for (const i in scrollLib) { - if (g('option').scroll[i] && gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`) && checkCondition(g('option')[`scroll${i}Condition`])) { - for (let j = 1; j <= scrollLib[i].mult; j++) { - if (gE(`#pane_effects>img[src*="${scrollLib[i][`img${j}`]}${scrollFirst}"]`)) { - isUsed = true; - break; - } - isUsed = false; - } - if (!isUsed) { - gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`).click(); - return true; + if (g('option').scroll[i] && gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`) && checkCondition(g('option')[`scroll${i}Condition`])) { + for (let j = 1; j <= scrollLib[i].mult; j++) { + if (gE(`#pane_effects>img[src*="${scrollLib[i][`img${j}`]}${scrollFirst}"]`)) { + isUsed = true; + break; + } + isUsed = false; + } + if (!isUsed) { + gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`).click(); + return true; + } } - } } return false; - } +} - function useChannelSkill() { // 自动施法Channel技能 +function useChannelSkill() { // 自动施法Channel技能 if (!g('option').channelSkillSwitch) { - return false; + return false; } if (!g('option').channelSkill) { - return false; + return false; } if (!gE('#pane_effects>img[src*="channeling"]')) { - return false; + return false; } const skillLib = { - Pr: { - name: 'Protection', - id: '411', - img: 'protection', - }, - SL: { - name: 'Spark of Life', - id: '422', - img: 'sparklife', - }, - SS: { - name: 'Spirit Shield', - id: '423', - img: 'spiritshield', - }, - Ha: { - name: 'Haste', - id: '412', - img: 'haste', - }, - AF: { - name: 'Arcane Focus', - id: '432', - img: 'arcanemeditation', - }, - He: { - name: 'Heartseeker', - id: '431', - img: 'heartseeker', - }, - Re: { - name: 'Regen', - id: '312', - img: 'regen', - }, - SV: { - name: 'Shadow Veil', - id: '413', - img: 'shadowveil', - }, - Ab: { - name: 'Absorb', - id: '421', - img: 'absorb', - }, + Pr: { + name: 'Protection', + id: '411', + img: 'protection', + }, + SL: { + name: 'Spark of Life', + id: '422', + img: 'sparklife', + }, + SS: { + name: 'Spirit Shield', + id: '423', + img: 'spiritshield', + }, + Ha: { + name: 'Haste', + id: '412', + img: 'haste', + }, + AF: { + name: 'Arcane Focus', + id: '432', + img: 'arcanemeditation', + }, + He: { + name: 'Heartseeker', + id: '431', + img: 'heartseeker', + }, + Re: { + name: 'Regen', + id: '312', + img: 'regen', + }, + SV: { + name: 'Shadow Veil', + id: '413', + img: 'shadowveil', + }, + Ab: { + name: 'Absorb', + id: '421', + img: 'absorb', + }, }; let i; let - j; + j; const skillPack = g('option').buffSkillOrderValue.split(','); if (g('option').channelSkill) { - for (i = 0; i < skillPack.length; i++) { - j = skillPack[i]; - if (g('option').channelSkill[j] && !gE(`#pane_effects>img[src*="${skillLib[j].img}"]`) && isOn(skillLib[j].id)) { - gE(skillLib[j].id).click(); - return true; + for (i = 0; i < skillPack.length; i++) { + j = skillPack[i]; + if (g('option').channelSkill[j] && !gE(`#pane_effects>img[src*="${skillLib[j].img}"]`) && isOn(skillLib[j].id)) { + gE(skillLib[j].id).click(); + return true; + } } - } } if (g('option').channelSkill2 && g('option').channelSkill2OrderValue) { - const order = g('option').channelSkill2OrderValue.split(','); - for (i = 0; i < order.length; i++) { - if (isOn(order[i])) { - gE(order[i]).click(); - return true; + const order = g('option').channelSkill2OrderValue.split(','); + for (i = 0; i < order.length; i++) { + if (isOn(order[i])) { + gE(order[i]).click(); + return true; + } } - } } const buff = gE('#pane_effects>img', 'all'); if (buff.length > 0) { - const name2Skill = { - 'Protection': 'Pr', - 'Spark of Life': 'SL', - 'Spirit Shield': 'SS', - 'Hastened': 'Ha', - 'Arcane Focus': 'AF', - 'Heartseeker': 'He', - 'Regen': 'Re', - 'Shadow Veil': 'SV', - }; - for (i = 0; i < buff.length; i++) { - const spellName = buff[i].getAttribute('onmouseover').match(/'(.*?)'/)[1]; - const buffLastTime = buff[i].getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; - if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { - continue; - } else { - if (spellName === 'Cloak of the Fallen' && !gE('#pane_effects>img[src*="sparklife"]') && isOn('422')) { - gE('422').click(); - return true; - } if (spellName in name2Skill && isOn(skillLib[name2Skill[spellName]].id)) { - gE(skillLib[name2Skill[spellName]].id).click(); - return true; - } + const name2Skill = { + Protection: 'Pr', + 'Spark of Life': 'SL', + 'Spirit Shield': 'SS', + Hastened: 'Ha', + 'Arcane Focus': 'AF', + Heartseeker: 'He', + Regen: 'Re', + 'Shadow Veil': 'SV', + }; + for (i = 0; i < buff.length; i++) { + const spellName = buff[i].getAttribute('onmouseover').match(/'(.*?)'/)[1]; + const buffLastTime = buff[i].getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; + if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { + continue; + } else { + if (spellName === 'Cloak of the Fallen' && !gE('#pane_effects>img[src*="sparklife"]') && isOn('422')) { + gE('422').click(); + return true; + } if (spellName in name2Skill && isOn(skillLib[name2Skill[spellName]].id)) { + gE(skillLib[name2Skill[spellName]].id).click(); + return true; + } + } } - } } return false; - } +} - function useBuffSkill() { // 自动施法BUFF技能 +function useBuffSkill() { // 自动施法BUFF技能 const skillLib = { - Pr: { - name: 'Protection', - id: '411', - img: 'protection', - }, - SL: { - name: 'Spark of Life', - id: '422', - img: 'sparklife', - }, - SS: { - name: 'Spirit Shield', - id: '423', - img: 'spiritshield', - }, - Ha: { - name: 'Haste', - id: '412', - img: 'haste', - }, - AF: { - name: 'Arcane Focus', - id: '432', - img: 'arcanemeditation', - }, - He: { - name: 'Heartseeker', - id: '431', - img: 'heartseeker', - }, - Re: { - name: 'Regen', - id: '312', - img: 'regen', - }, - SV: { - name: 'Shadow Veil', - id: '413', - img: 'shadowveil', - }, - Ab: { - name: 'Absorb', - id: '421', - img: 'absorb', - }, + Pr: { + name: 'Protection', + id: '411', + img: 'protection', + }, + SL: { + name: 'Spark of Life', + id: '422', + img: 'sparklife', + }, + SS: { + name: 'Spirit Shield', + id: '423', + img: 'spiritshield', + }, + Ha: { + name: 'Haste', + id: '412', + img: 'haste', + }, + AF: { + name: 'Arcane Focus', + id: '432', + img: 'arcanemeditation', + }, + He: { + name: 'Heartseeker', + id: '431', + img: 'heartseeker', + }, + Re: { + name: 'Regen', + id: '312', + img: 'regen', + }, + SV: { + name: 'Shadow Veil', + id: '413', + img: 'shadowveil', + }, + Ab: { + name: 'Absorb', + id: '421', + img: 'absorb', + }, }; if (!g('option').buffSkillSwitch) { - return false; + return false; } if (!g('option').buffSkill) { - return false; + return false; } if (!checkCondition(g('option').buffSkillCondition)) { - return false; + return false; } - let i; + const skillPack = g('option').buffSkillOrderValue.split(','); - for (i = 0; i < skillPack.length; i++) { - let buff = skillPack[i]; - if (g('option').buffSkill[buff] && checkCondition(g('option')[`buffSkill${buff}Condition`]) && !gE(`#pane_effects>img[src*="${skillLib[buff].img}"]`) && isOn(skillLib[buff].id)) { - gE(skillLib[buff].id).click(); - return true; - } + for (let i = 0; i < skillPack.length; i++) { + let buff = skillPack[i]; + if (g('option').buffSkill[buff] && checkCondition(g('option')[`buffSkill${buff}Condition`]) && !gE(`#pane_effects>img[src*="${skillLib[buff].img}"]`) && isOn(skillLib[buff].id)) { + gE(skillLib[buff].id).click(); + return true; + } } const draughtPack = { - HD: { - id: 11191, - img: 'healthpot', - }, - MD: { - id: 11291, - img: 'manapot', - }, - SD: { - id: 11391, - img: 'spiritpot', - }, - FV: { - id: 19111, - img: 'flowers', - }, - BG: { - id: 19131, - img: 'gum', - }, + HD: { + id: 11191, + img: 'healthpot', + }, + MD: { + id: 11291, + img: 'manapot', + }, + SD: { + id: 11391, + img: 'spiritpot', + }, + FV: { + id: 19111, + img: 'flowers', + }, + BG: { + id: 19131, + img: 'gum', + }, }; - for (i in draughtPack) { - if (!gE(`#pane_effects>img[src*="${draughtPack[i].img}"]`) && g('option').buffSkill && g('option').buffSkill[i] && checkCondition(g('option')[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="${draughtPack[i].id}"]`)) { - gE(`.bti3>div[onmouseover*="${draughtPack[i].id}"]`).click(); - return true; - } + for (let i in draughtPack) { + if (!gE(`#pane_effects>img[src*="${draughtPack[i].img}"]`) && g('option').buffSkill && g('option').buffSkill[i] && checkCondition(g('option')[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="${draughtPack[i].id}"]`)) { + gE(`.bti3>div[onmouseover*="${draughtPack[i].id}"]`).click(); + return true; + } } return false; - } +} - function useInfusions() { // 自动使用魔药 +function useInfusions() { // 自动使用魔药 if (g('attackStatus') === 0) { - return false; + return false; } if (!g('option').infusionSwitch) { - return false; + return false; } if (!checkCondition(g('option').infusionCondition)) { - return false; + return false; } const infusionLib = [null, { - id: 12101, - img: 'fireinfusion', - }, { - id: 12201, - img: 'coldinfusion', - }, { - id: 12301, - img: 'elecinfusion', + id: 12101, + img: 'fireinfusion', }, { - id: 12401, - img: 'windinfusion', - }, { - id: 12501, - img: 'holyinfusion', - }, { - id: 12601, - img: 'darkinfusion', - }]; + id: 12201, + img: 'coldinfusion', + }, { + id: 12301, + img: 'elecinfusion', + }, { + id: 12401, + img: 'windinfusion', + }, { + id: 12501, + img: 'holyinfusion', + }, { + id: 12601, + img: 'darkinfusion', + }]; if (gE(`.bti3>div[onmouseover*="${infusionLib[g('attackStatus')].id}"]`) && !gE(`#pane_effects>img[src*="${infusionLib[[g('attackStatus')]].img}"]`)) { - gE(`.bti3>div[onmouseover*="${infusionLib[g('attackStatus')].id}"]`).click(); - return true; + gE(`.bti3>div[onmouseover*="${infusionLib[g('attackStatus')].id}"]`).click(); + return true; } return false; - } +} - function autoFocus() { +function autoFocus() { if (g('option').focus && checkCondition(g('option').focusCondition)) { - gE('#ckey_focus').click(); - return true; + gE('#ckey_focus').click(); + return true; } return false; - } - - function autoSS() { +} +function autoSS() { if ((g('option').turnOnSS && checkCondition(g('option').turnOnSSCondition) && !gE('#ckey_spirit[src*="spirit_a"]')) || (g('option').turnOffSS && checkCondition(g('option').turnOffSSCondition) && gE('#ckey_spirit[src*="spirit_a"]'))) { - gE('#ckey_spirit').click(); - return true; + gE('#ckey_spirit').click(); + return true; } return false; - } +} - /** - * INNAT / WEAPON SKILLS - * - * 优先释放先天和武器技能 - */ - function autoSkill() { +/** + * INNAT / WEAPON SKILLS + * + * 优先释放先天和武器技能 + */ +function autoSkill() { if (!g('option').skillSwitch) { - return false; + return false; } if (!gE('#ckey_spirit[src*="spirit_a"]')) { - return false; + return false; } const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); + console.log(skillOrder) const skillLib = { - OFC: { - id: '1111', - oc: 8, - }, - FRD: { - id: '1101', - oc: 4, - }, - T3: { - id: `2${g('option').fightingStyle}03`, - oc: 2, - }, - T2: { - id: `2${g('option').fightingStyle}02`, - oc: 2, - }, - T1: { - id: `2${g('option').fightingStyle}01`, - oc: 2, - }, + OFC: { + id: '1111', + oc: 8, + }, + FRD: { + id: '1101', + oc: 4, + }, + T3: { + id: `2${g('option').fightingStyle}03`, + oc: 2, + }, + T2: { + id: `2${g('option').fightingStyle}02`, + oc: 2, + }, + T1: { + id: `2${g('option').fightingStyle}01`, + oc: 1, + }, }; const rangeSkills = { - 2101: 2, - 2403: 2, - 1111: 4, + 2101: 2, + 2403: 2, + 1111: 4, } - const monsterStatus = g('battle').monsterStatus; + for (let i in skillOrder) { - let skill = skillOrder[i]; - let range = 0; - if (!checkCondition(g('option')[`skill${skill}Condition`])) { - continue; - } - if (!isOn(skillLib[skill].id)) { - continue; - } - if (g('oc') < skillLib[skill].oc) { - continue; - } - if (g('option').skillOTOS && g('option').skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { - continue; - } - g('skillOTOS')[skill]++; - gE(skillLib[skill].id).click(); - if (skillLib[skill].id in rangeSkills) { - range = rangeSkills[skillLib[skill].id]; - } - if (!g('option').mercifulBlow || g('option').fightingStyle !== '2' || skill !== 'T3') { - continue; - } - // Merciful Blow - for (let j = 0; j < monsterStatus.length; j++) { - if (monsterStatus[j].hpNow / monsterStatus[j].hp < 0.25 && gE(`#mkey_${getMonsterID(monsterStatus[j])} img[src*="wpn_bleed"]`)) { - gE(`#mkey_${getRangeCenterID(monsterStatus[j])}`).click(); - return true; + let skill = skillOrder[i]; + let range = 0; + if (!checkCondition(g('option')[`skill${skill}Condition`])) { + continue; + } + if (!isOn(skillLib[skill].id)) { + continue; + } + if (g('oc') <= skillLib[skill].oc) { + continue; + } + if (g('option').skillOTOS && g('option').skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { + continue; + } + g('skillOTOS')[skill]++; + console.log('释放技能ID:'+skillLib[skill].id) + gE(skillLib[skill].id).click(); + + if (skillLib[skill].id in rangeSkills) { + range = rangeSkills[skillLib[skill].id]; + } + if (!g('option').mercifulBlow || g('option').fightingStyle !== '2' || skill !== 'T3') { + break; + } + // Merciful Blow + for (let j = 0; j < g('monsterStatus').length; j++) { + if (g('monsterStatus')[j].hpNow / g('monsterStatus')[j].hp < 0.25 && gE(`#mkey_${g('monsterStatus')[j].id} img[src*="wpn_bleed"]`)) { + gE(`#mkey_${getRangeCenter(g('monsterStatus')[j]).id}`).click(); + return true; + } } - } } - gE(`#mkey_${getRangeCenterID(monsterStatus[0])}`).click(); + gE(`#mkey_${getRangeCenter(g('monsterStatus')[0]).id}`).click(); return true; - } +} - function useDeSkill() { // 自动施法DEBUFF技能 +function useDeSkill() { // 自动施法DEBUFF技能 if (!g('option').debuffSkillSwitch) { // 总开关是否开启 - return false; + return false; } // 先处理特殊的 “先给全体上buff” - let skillPack = ['We', 'Im']; + let skillPack = ['Im', 'We']; for (let i = 0; i < skillPack.length; i++) { - if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 - continue; - } - if (!checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`])) { // 检查条件 - continue; - } - skillPack.splice(i, 1); - i--; + if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 + continue; + } + if (!checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`])) { // 检查条件 + continue; + } + skillPack.splice(i, 1); + i--; } - skillPack.sort((x, y) => g('option').debuffSkillOrderValue.indexOf(x) - g('option').debuffSkillOrderValue.indexOf(y)) let toAllCount = skillPack.length; if (g('option').debuffSkill) { // 是否有启用的buff(不算两个特殊的) - skillPack = skillPack.concat(g('option').debuffSkillOrderValue.split(',')); + skillPack = skillPack.concat(g('option').debuffSkillOrderValue.split(',')); } for (let i in skillPack) { - let buff = skillPack[i]; - if (i >= toAllCount && !skillPack[i]) { // 检查buff是否启用 - continue; - } - if (!checkCondition(g('option')[`debuffSkill${buff}Condition`])) { // 检查条件 - continue; - } - let succeed = useDebuffSkill(skillPack[i], i < toAllCount); - // 前 toAllCount 个都是先给全体上的 - if (succeed) { - return true; - } + let buff = skillPack[i]; + if (!g('option').debuffSkill[buff] && i >= toAllCount) { // 检查buff是否启用 + continue; + } + if (!checkCondition(g('option')[`debuffSkill${buff}Condition`])) { // 检查条件 + continue; + } + // 前 toAllCount 个都是先给全体上的 + if (useDebuffSkill(skillPack[i], i < toAllCount)) { + return true; + } } return false; - } +} - function useDebuffSkill(buff, isAll = false) { +function useDebuffSkill(buff, isAll = false) { const skillLib = { - Sle: { - name: 'Sleep', - id: '222', - img: 'sleep', - }, - Bl: { - name: 'Blind', - id: '231', - img: 'blind', - }, - Slo: { - name: 'Slow', - id: '221', - img: 'slow', - }, - Im: { - name: 'Imperil', - id: '213', - img: 'imperil', - range: { 4204: [0, 0, 0, 1] }, - }, - MN: { - name: 'MagNet', - id: '233', - img: 'magnet', - }, - Si: { - name: 'Silence', - id: '232', - img: 'silence', - }, - Dr: { - name: 'Drain', - id: '211', - img: 'drainhp', - }, - We: { - name: 'Weaken', - id: '212', - img: 'weaken', - range: { 4202: [0, 0, 0, 1] }, - }, - Co: { - name: 'Confuse', - id: '223', - img: 'confuse', - }, + Sle: { + name: 'Sleep', + id: '222', + img: 'sleep', + }, + Bl: { + name: 'Blind', + id: '231', + img: 'blind', + }, + Slo: { + name: 'Slow', + id: '221', + img: 'slow', + }, + Im: { + name: 'Imperil', + id: '213', + img: 'imperil', + range: 1, + }, + MN: { + name: 'MagNet', + id: '233', + img: 'magnet', + }, + Si: { + name: 'Silence', + id: '232', + img: 'silence', + }, + Dr: { + name: 'Drain', + id: '211', + img: 'drainhp', + }, + We: { + name: 'Weaken', + id: '212', + img: 'weaken', + range: 1, + }, + Co: { + name: 'Confuse', + id: '223', + img: 'confuse', + }, }; - if (!isOn(skillLib[buff].id)) { // 技能不可用 - return false; + return false; } - const monsterStatus = g('battle').monsterStatus; - let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); + + let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${target.id}>.btm6`)) + + g('monsterStatus').sort(objArrSort('finWeight')); let primaryTarget; - let max = isAll ? monsterStatus.length : 1; + let max = isAll ? g('monsterStatus').length : 1; for (let i = 0; i < max; i++) { - let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; - if (monsterStatus[i].isDead) { - continue; - } - if (isDebuffed(target)) { // 检查是否已有该buff - continue; - } - primaryTarget = target; - break; + if (g('monsterStatus')[i].isDead) { + continue; + } + let target = g('monsterStatus')[i]; + if (isDebuffed(target)) { // 检查是否已有该buff + continue; + } + primaryTarget = target; + break; } if (primaryTarget === undefined) { - return false; + return false; } - let range = 0; - let ab; - for (ab in skillLib[buff].range) { - const ranges = skillLib[buff].range[ab][skillLib[buff].skill * 1]; - if (!ranges) { - continue; - } - range = ranges[getValue('ability', true)[ab].level]; - break; - } - let id = getRangeCenterID(primaryTarget, range, isDebuffed); + let id = getRangeCenter(primaryTarget, skillLib[buff].range, isDebuffed).id; const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); - // 已有buff小于6个 - // 未开启debuff失败警告 - // buff剩余持续时间大于等于警报时间 if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && imgs[imgs.length - 1].getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1 >= g('option').debuffSkillTurn[buff])) { - gE(skillLib[buff].id).click(); - gE(`#mkey_${id}`).click(); - return true; + gE(skillLib[buff].id).click(); + gE(`#mkey_${id}`).click(); + return true; } + // 已有buff小于6个 + // 未开启debuff失败警告 + // buff剩余持续时间大于等于警报时间 _alert(0, '无法正常施放DEBUFF技能,请尝试手动打怪', '無法正常施放DEBUFF技能,請嘗試手動打怪', 'Can not cast de-skills normally, continue the script?\nPlease try attack manually.'); pauseChange(); return true; - } +} - function attack() { // 自动打怪 +function attack() { // 自动打怪 // 如果 // 1. 开启了自动以太水龙头 // 2. 目标怪在魔力合流状态中 @@ -3899,390 +2864,245 @@ try { // 使用物理普通攻击,跳过Offensive Magic // 否则按照属性攻击模式释放Spell > Offensive Magic - const updateAbility = { - 4301: { //火 - 111: [0, 1, 1, 2, 2, 2, 2, 2], - 112: [0, 0, 2, 2, 2, 2, 3, 3], - 113: [0, 0, 0, 0, 3, 4, 4, 4] - }, - 4302: { //冰 - 121: [0, 1, 1, 2, 2, 2, 2, 2], - 122: [0, 0, 2, 2, 2, 2, 3, 3], - 123: [0, 0, 0, 0, 3, 4, 4, 4] - }, - 4303: { //雷 - 131: [0, 1, 1, 2, 2, 2, 2, 2], - 132: [0, 0, 2, 2, 2, 2, 3, 3], - 133: [0, 0, 0, 0, 3, 4, 4, 4] - }, - 4304: { //雷 - 141: [0, 1, 1, 2, 2, 2, 2, 2], - 142: [0, 0, 2, 2, 2, 2, 3, 3], - 143: [0, 0, 0, 0, 3, 4, 4, 4] - }, - //暗 - 4401: { 161: [0, 1, 2] }, - 4402: { 162: [0, 2, 3] }, - 4403: { 163: [0, 3, 4, 4] }, - //圣 - 4501: { 151: [0, 1, 2] }, - 4502: { 152: [0, 2, 3] }, - 4503: { 153: [0, 3, 4, 4] }, - } - let range = 0; // Spell > Offensive Magic - const attackStatus = g('attackStatus'); - const monsterStatus = g('battle').monsterStatus; - if (attackStatus === 0) { - if (g('option').fightingStyle === '1') { // 二天一流 - range = 1; - } + if (g('attackStatus') === 0) { + if (g('option').fightingStyle === 0) { + range = 2; + } } else { - if (g('option').etherTap && gE(`#mkey_${getMonsterID(monsterStatus[0])}>div.btm6>img[src*="coalescemana"]`) && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || gE('#pane_effects>img[src*="wpn_et"][id*="effect_expire"]')) && checkCondition(g('option').etherTapCondition)) { - `pass` - } - else { - const skill = 1 * (() => { - let lv = 3; - for (let condition of [g('option').highSkillCondition, g('option').middleSkillCondition, undefined]) { - let id = `1${attackStatus}${lv--}`; - if (checkCondition(condition) && isOn(id)) return id; - } - })(); - gE(skill)?.click(); - for (let ab in updateAbility) { - const ranges = updateAbility[ab][skill]; - if (!ranges) { - continue; - } - range = ranges[getValue('ability', true)[ab]?.level ?? 0]; - break; + if (g('option').etherTap && gE(`#mkey_${g('monsterStatus')[0].id}>div.btm6>img[src*="coalescemana"]`) && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || gE('#pane_effects>img[src*="wpn_et"][id*="effect_expire"]')) && checkCondition(g('option').etherTapCondition)) { + `pass` + } + else { + if (checkCondition(g('option').highSkillCondition) && isOn(`1${g('attackStatus')}3`)) { + gE(`1${g('attackStatus')}3`).click(); + range = 3; // 7~10 + } else if (checkCondition(g('option').middleSkillCondition) && isOn(`1${g('attackStatus')}2`)) { + gE(`1${g('attackStatus')}2`).click(); + range = 2; // 5/7 + } else if (isOn(`1${g('attackStatus')}1`)) { + gE(`1${g('attackStatus')}1`).click(); + range = 1; // 3/5 + } } - } } - gE(`#mkey_${getRangeCenterID(monsterStatus[0], range, !attackStatus)}`).click(); + // else Weapon Attack + gE(`#mkey_${getRangeCenter(g('monsterStatus')[0], range).id}`).click(); return true; - } - - function getHPFromMonsterDB(mdb, name, lv) { - let hp = (mdb && mdb[name]) ? mdb[name][lv] : undefined; - // TODO: 根据lv模糊推测 - return hp; - } +} - function fixMonsterStatus() { // 修复monsterStatus - // document.title = _alert(-1, 'monsterStatus错误,正在尝试修复', 'monsterStatus錯誤,正在嘗試修復', 'monsterStatus Error, trying to fix'); +function fixMonsterStatus() { // 修复monsterStatus + document.title = _alert(-1, 'monsterStatus错误,正在尝试修复', 'monsterStatus錯誤,正在嘗試修復', 'monsterStatus Error, trying to fix'); const monsterStatus = []; - const monsterNames = Array.from(gE('div.btm3>div>div', 'all')).map(monster => monster.innerText); - const monsterLvs = Array.from(gE('div.btm2>div>div', 'all')).map(monster => monster.innerText); - const monsterDB = getValue('monsterDB', true); - gE('div.btm2', 'all').forEach((monster, order) => { - monsterStatus.push({ - order: order, - hp: getHPFromMonsterDB(monsterDB, monsterNames[order], monsterLvs[order]) ?? ((monster.style.background === '') ? 1000 : 100000), - }); - }); - const battle = getValue('battle', true); - battle.monsterStatus = monsterStatus; - setValue('battle', battle); - } - - function displayMonsterWeight() { - - const status = g('battle').monsterStatus.filter(m => !m.isDead); - let rank = 0; - - const weights = []; - status.forEach(s => { - if (weights.indexOf(s.finWeight) !== -1) { - return; - } - weights.push(s.finWeight); - }) - const sec = Math.max(1, weights.length - 1); - const max = 360 * 2 / 3; - const colorTextList = []; - if (g('option').weightBackground) { - status.forEach(s => { - const rank = weights.indexOf(s.finWeight); - let colorText = (g('option').weightBackground[rank + 1] ?? [])[0]; - colorTextList[rank] = colorText; - }); - } - status.forEach(s => { - const rank = weights.indexOf(s.finWeight); - const id = getMonsterID(s); - if (!gE(`#mkey_${id}`) || !gE(`#mkey_${id}>.btm3`)) { - return; - } - if (g('option').displayWeightBackground) { - if (g('option').weightBackground) { - let colorText = colorTextList[rank]; - let remainAttemp = 10; // 避免无穷递归 - while(remainAttemp > 0 && colorText && colorText.indexOf(``, colorTextList[i]); - } - remainAttemp--; - } - try { - colorText = eval(colorText.replace('', rank).replace('', weights.length)); - } - catch { - } - gE(`#mkey_${id}`).style.cssText += `background: ${colorText};`; - } - } - gE(`#mkey_${id}>.btm3`).style.cssText += 'display: flex; flex-direction: row;' - if (g('option').displayWeight) { - gE(`#mkey_${id}>.btm3`).innerHTML += `
      [${rank}|-${-rank + weights.length - 1}|${s.finWeight.toPrecision(s.finWeight >= 1 ? 5 : 4)}]
      `; - } - }); - } - - function displayPlayStatePercentage() { - const barHP = gE('#vbh') ?? gE('#dvbh'); - const barMP = gE('#vbm') ?? gE('#dvbm'); - const barSP = gE('#vbs') ?? gE('#dvbs'); - const barOC = gE('#dvbc'); - const textHP = gE('#vrhd') ?? gE('#dvrhd'); - const textMP = gE('#vrm') ?? gE('#dvrm'); - const textSP = gE('#vrs') ?? gE('#dvrs'); - const textOC = gE('#dvrc'); - - const percentages = [barHP, barMP, barSP, barOC].filter(bar => bar).map(bar => Math.floor((gE('div>img', bar).offsetWidth / bar.offsetWidth) * 100)); - [textHP, textMP, textSP, textOC].filter(bar => bar).forEach((text, i) => { - const value = text.innerHTML * 1; - const percentage = value ? percentages[i] : 0; - const inner = `[${percentage.toString()}%]`; - const percentageDiv = gE('div', text); - if (percentageDiv) { - percentageDiv.innerHTML = inner; - return; - } - text.innerHTML += `
      ${inner}
      ` + gE('div.btm2', 'all').forEach((monster, i) => { + monsterStatus.push({ + order: i, + id: (i === 9) ? 0 : i + 1, + hp: (monster.style.background === '') ? 1000 : 100000, + }); }); - } + setValue('monsterStatus', monsterStatus); + goto(); +} - function dropMonitor(battleLog) { // 掉落监测 +function dropMonitor(battleLog) { // 掉落监测 const drop = getValue('drop', true) || { - '#startTime': time(3), - '#EXP': 0, - '#Credit': 0, + '#startTime': time(3), + '#EXP': 0, + '#Credit': 0, }; let item; let name; let amount; let - regexp; + regexp; for (let i = 0; i < battleLog.length; i++) { - if (/^You gain \d+ (EXP|Credit)/.test(battleLog[i].textContent)) { - regexp = battleLog[i].textContent.match(/^You gain (\d+) (EXP|Credit)/); - if (regexp) { - drop[`#${regexp[2]}`] += regexp[1] * 1; - } - } else if (gE('span', battleLog[i])) { - item = gE('span', battleLog[i]); - name = item.textContent.match(/^\[(.*?)\]$/)[1]; - if (item.style.color === 'rgb(255, 0, 0)') { - const quality = ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless']; - for (let j = g('option').dropQuality; j < quality.length; j++) { - if (name.match(quality[j])) { - name = `Equipment of ${name.match(/^\w+/)[0]}`; - drop[name] = (name in drop) ? drop[name] + 1 : 1; - break; + if (/^You gain \d+ (EXP|Credit)/.test(battleLog[i].textContent)) { + regexp = battleLog[i].textContent.match(/^You gain (\d+) (EXP|Credit)/); + if (regexp) drop[`#${regexp[2]}`] += regexp[1] * 1; + } else if (gE('span', battleLog[i])) { + item = gE('span', battleLog[i]); + name = item.textContent.match(/^\[(.*?)\]$/)[1]; + if (item.style.color === 'rgb(255, 0, 0)') { + const quality = ['Crude', 'Fair', 'Average', 'Superior', 'Exquisite', 'Magnificent', 'Legendary', 'Peerless']; + for (let j = g('option').dropQuality; j < quality.length; j++) { + if (name.match(quality[j])) { + name = `Equipment of ${name.match(/^\w+/)[0]}`; + drop[name] = (name in drop) ? drop[name] + 1 : 1; + break; + } + } + } else if (item.style.color === 'rgb(186, 5, 180)') { + regexp = name.match(/^(\d+)x (Crystal of \w+)$/); + if (regexp) { + name = regexp[2]; + amount = regexp[1] * 1; + } else { + name = name.match(/^(Crystal of \w+)$/)[1]; + amount = 1; + } + drop[name] = (name in drop) ? drop[name] + amount : amount; + } else if (item.style.color === 'rgb(168, 144, 0)') { + drop['#Credit'] = drop['#Credit'] + name.match(/\d+/)[0] * 1; + } else { + drop[name] = (name in drop) ? drop[name] + 1 : 1; } - } - } else if (item.style.color === 'rgb(186, 5, 180)') { - regexp = name.match(/^(\d+)x (Crystal of \w+)$/); - if (regexp) { - name = regexp[2]; - amount = regexp[1] * 1; - } else { - name = name.match(/^(Crystal of \w+)$/)[1]; - amount = 1; - } - drop[name] = (name in drop) ? drop[name] + amount : amount; - } else if (item.style.color === 'rgb(168, 144, 0)') { - drop['#Credit'] = drop['#Credit'] + name.match(/\d+/)[0] * 1; - } else { - drop[name] = (name in drop) ? drop[name] + 1 : 1; + } else if (battleLog[i].textContent === 'You are Victorious!') { + break; } - } else if (battleLog[i].textContent === 'You are Victorious!') { - break; - } } - const battle = g('battle'); - if (g('option').recordEach && battle.roundNow === battle.roundAll) { - const old = getValue('dropOld', true) || []; - drop.__name = getValue('battleCode'); - drop['#endTime'] = time(3); - old.push(drop); - setValue('dropOld', old); - delValue('drop'); + if (g('option').recordEach && g('roundNow') === g('roundAll')) { + const old = getValue('dropOld', true) || []; + drop.__name = getValue('battleCode'); + drop['#endTime'] = time(3); + old.push(drop); + setValue('dropOld', old); + delValue('drop'); } else { - setValue('drop', drop); + setValue('drop', drop); } - } +} - function recordUsage(parm) { +function recordUsage(parm) { const stats = getValue('stats', true) || { - self: { - _startTime: time(3), - _turn: 0, - _round: 0, - _battle: 0, - _monster: 0, - _boss: 0, - evade: 0, - miss: 0, - focus: 0, - }, - restore: { // 回复量 - }, - items: { // 物品使用次数 - }, - magic: { // 技能使用次数 - }, - damage: { // 技能攻击造成的伤害 - }, - hurt: { // 受到攻击造成的伤害 - mp: 0, - oc: 0, - _avg: 0, - _count: 0, - _total: 0, - _mavg: 0, - _mcount: 0, - _mtotal: 0, - _pavg: 0, - _pcount: 0, - _ptotal: 0, - }, - proficiency: { // 熟练度 - }, + self: { + _startTime: time(3), + _turn: 0, + _round: 0, + _battle: 0, + _monster: 0, + _boss: 0, + evade: 0, + miss: 0, + focus: 0, + }, + restore: { // 回复量 + }, + items: { // 物品使用次数 + }, + magic: { // 技能使用次数 + }, + damage: { // 技能攻击造成的伤害 + }, + hurt: { // 受到攻击造成的伤害 + mp: 0, + oc: 0, + _avg: 0, + _count: 0, + _total: 0, + _mavg: 0, + _mcount: 0, + _mtotal: 0, + _pavg: 0, + _pcount: 0, + _ptotal: 0, + }, + proficiency: { // 熟练度 + }, }; let text; let magic; let point; let - reg; - const battle = g('battle'); + reg; if (g('monsterAlive') === 0) { - stats.self._turn += battle.turn; - stats.self._round += 1; - if (battle.roundNow === battle.roundAll) { - stats.self._battle += 1; - } + stats.self._turn += g('turn'); + stats.self._round += 1; + if (g('roundNow') === g('roundAll')) stats.self._battle += 1; } if (parm.mode === 'magic') { - magic = parm.magic; - stats.magic[magic] = (magic in stats.magic) ? stats.magic[magic] + 1 : 1; - stats.hurt.mp += parm.mp; - stats.hurt.oc += parm.oc; + magic = parm.magic; + stats.magic[magic] = (magic in stats.magic) ? stats.magic[magic] + 1 : 1; + stats.hurt.mp += parm.mp; + stats.hurt.oc += parm.oc; } else if (parm.mode === 'items') { - stats.items[parm.item] = (parm.item in stats.items) ? stats.items[parm.item] + 1 : 1; + stats.items[parm.item] = (parm.item in stats.items) ? stats.items[parm.item] + 1 : 1; } else { - stats.self[parm.mode] = (parm.mode in stats.self) ? stats.self[parm.mode] + 1 : 1; + stats.self[parm.mode] = (parm.mode in stats.self) ? stats.self[parm.mode] + 1 : 1; } const debug = false; let log = false; for (let i = 0; i < parm.log.length; i++) { - if (parm.log[i].className === 'tls') { - break; - } - text = parm.log[i].textContent; - if (debug) { - console.log(text); - } - if (text.match(/you for \d+ \w+ damage/)) { - reg = text.match(/you for (\d+) (\w+) damage/); - magic = reg[2].replace('ing', ''); - point = reg[1] * 1; - stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; - stats.hurt._count++; - stats.hurt._total += point; - stats.hurt._avg = Math.round(stats.hurt._total / stats.hurt._count); - if (magic.match(/pierc|crush|slash/)) { - stats.hurt._pcount++; - stats.hurt._ptotal += point; - stats.hurt._pavg = Math.round(stats.hurt._ptotal / stats.hurt._pcount); - } else { - stats.hurt._mcount++; - stats.hurt._mtotal += point; - stats.hurt._mavg = Math.round(stats.hurt._mtotal / stats.hurt._mcount); + if (parm.log[i].className === 'tls') break; + text = parm.log[i].textContent; + if (debug) console.log(text); + if (text.match(/you for \d+ \w+ damage/)) { + reg = text.match(/you for (\d+) (\w+) damage/); + magic = reg[2].replace('ing', ''); + point = reg[1] * 1; + stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; + stats.hurt._count++; + stats.hurt._total += point; + stats.hurt._avg = Math.round(stats.hurt._total / stats.hurt._count); + if (magic.match(/pierc|crush|slash/)) { + stats.hurt._pcount++; + stats.hurt._ptotal += point; + stats.hurt._pavg = Math.round(stats.hurt._ptotal / stats.hurt._pcount); + } else { + stats.hurt._mcount++; + stats.hurt._mtotal += point; + stats.hurt._mavg = Math.round(stats.hurt._mtotal / stats.hurt._mcount); + } + } else if (text.match(/^[\w ]+ [a-z]+s [\w+ -]+ for \d+( .*)? damage/) || text.match(/^You .* for \d+ .* damage/)) { // text.match(/for \d+ .* damage/) + reg = text.match(/for (\d+)( .*)? damage/); + magic = text.match(/^[\w ]+ [a-z]+s [\w+ -]+ for/) ? text.match(/^([\w ]+) [a-z]+s [\w+ -]+ for/)[1].replace(/^Your /, '') : text.match(/^You (\w+)/)[1]; + point = reg[1] * 1; + stats.damage[magic] = (magic in stats.damage) ? stats.damage[magic] + point : point; + } else if (text.match(/Vital Theft hits .*? for \d+ damage/)) { + magic = 'Vital Theft'; + point = text.match(/Vital Theft hits .*? for (\d+) damage/)[1] * 1; + stats.damage[magic] = (magic in stats.damage) ? stats.damage[magic] + point : point; + } else if (text.match(/You (evade|parry|block) the attack|misses the attack against you|(casts|uses) .* misses the attack/)) { + stats.self.evade++; + } else if (text.match(/(resists your spell|Your spell is absorbed|(evades|parries) your (attack|spell))|Your attack misses its mark|Your spell fails to connect/)) { + stats.self.miss++; + } else if (text.match(/You gain the effect Focusing/)) { + stats.self.focus++; + } else if (text.match(/^Recovered \d+ points of/) || text.match(/You are healed for \d+ Health Points/) || text.match(/You drain \d+ HP from/)) { + magic = (parm.mode === 'defend') ? 'defend' : text.match(/You drain \d+ HP from/) ? 'drain' : parm.magic || parm.item; + point = text.match(/\d+/)[0] * 1; + stats.restore[magic] = (magic in stats.restore) ? stats.restore[magic] + point : point; + } else if (text.match(/(restores|drain) \d+ points of/)) { + reg = text.match(/^(.*) restores (\d+) points of (\w+)/) || text.match(/^You (drain) (\d+) points of (\w+)/); + magic = reg[1]; + point = reg[2] * 1; + stats.restore[magic] = (magic in stats.restore) ? stats.restore[magic] + point : point; + } else if (text.match(/absorbs \d+ points of damage from the attack into \d+ points of \w+ damage/)) { + reg = text.match(/(.*) absorbs (\d+) points of damage from the attack into (\d+) points of (\w+) damage/); + point = reg[2] * 1; + magic = parm.log[i - 1].textContent.match(/you for (\d+) (\w+) damage/)[2].replace('ing', ''); + stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; + point = reg[3] * 1; + magic = `${reg[1].replace('Your ', '')}_${reg[4]}`; + stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; + } else if (text.match(/You gain .* proficiency/)) { + reg = text.match(/You gain ([\d.]+) points of (.*?) proficiency/); + magic = reg[2]; + point = reg[1] * 1; + stats.proficiency[magic] = (magic in stats.proficiency) ? stats.proficiency[magic] + point : point; + stats.proficiency[magic] = stats.proficiency[magic].toFixed(3) * 1; + } else if (text.trim() === '' || text.match(/You (gain |cast |use |are Victorious|have reached Level|have obtained the title|do not have enough MP)/) || text.match(/Cooldown|has expired|Spirit Stance|gains the effect|insufficient Spirit|Stop beating dead ponies| defeat |Clear Bonus|brink of defeat|Stop \w+ing|Spawned Monster| drop(ped|s) |defeated/)) { + // nothing; + } else if (debug) { + log = true; + setAudioAlarm('Error'); + console.log(text); } - } else if (text.match(/^[\w ]+ [a-z]+s [\w+ -]+ for \d+( .*)? damage/) || text.match(/^You .* for \d+ .* damage/)) { - reg = text.match(/for (\d+)( .*)? damage/); - magic = text.match(/^[\w ]+ [a-z]+s [\w+ -]+ for/) ? text.match(/^([\w ]+) [a-z]+s [\w+ -]+ for/)[1].replace(/^Your /, '') : text.match(/^You (\w+)/)[1]; - point = reg[1] * 1; - stats.damage[magic] = (magic in stats.damage) ? stats.damage[magic] + point : point; - } else if (text.match(/Vital Theft hits .*? for \d+ damage/)) { - magic = 'Vital Theft'; - point = text.match(/Vital Theft hits .*? for (\d+) damage/)[1] * 1; - stats.damage[magic] = (magic in stats.damage) ? stats.damage[magic] + point : point; - } else if (text.match(/You (evade|parry|block) the attack|misses the attack against you|(casts|uses) .* misses the attack/)) { - stats.self.evade++; - } else if (text.match(/(resists your spell|Your spell is absorbed|(evades|parries) your (attack|spell))|Your attack misses its mark|Your spell fails to connect/)) { - stats.self.miss++; - } else if (text.match(/You gain the effect Focusing/)) { - stats.self.focus++; - } else if (text.match(/^Recovered \d+ points of/) || text.match(/You are healed for \d+ Health Points/) || text.match(/You drain \d+ HP from/)) { - magic = (parm.mode === 'defend') ? 'defend' : text.match(/You drain \d+ HP from/) ? 'drain' : parm.magic || parm.item; - point = text.match(/\d+/)[0] * 1; - stats.restore[magic] = (magic in stats.restore) ? stats.restore[magic] + point : point; - } else if (text.match(/(restores|drain) \d+ points of/)) { - reg = text.match(/^(.*) restores (\d+) points of (\w+)/) || text.match(/^You (drain) (\d+) points of (\w+)/); - magic = reg[1]; - point = reg[2] * 1; - stats.restore[magic] = (magic in stats.restore) ? stats.restore[magic] + point : point; - } else if (text.match(/absorbs \d+ points of damage from the attack into \d+ points of \w+ damage/)) { - reg = text.match(/(.*) absorbs (\d+) points of damage from the attack into (\d+) points of (\w+) damage/); - point = reg[2] * 1; - magic = parm.log[i - 1].textContent.match(/you for (\d+) (\w+) damage/)[2].replace('ing', ''); - stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; - point = reg[3] * 1; - magic = `${reg[1].replace('Your ', '')}_${reg[4]}`; - stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; - } else if (text.match(/You gain .* proficiency/)) { - reg = text.match(/You gain ([\d.]+) points of (.*?) proficiency/); - magic = reg[2]; - point = reg[1] * 1; - stats.proficiency[magic] = (magic in stats.proficiency) ? stats.proficiency[magic] + point : point; - stats.proficiency[magic] = stats.proficiency[magic].toFixed(3) * 1; - } else if (text.trim() === '' || text.match(/You (gain |cast |use |are Victorious|have reached Level|have obtained the title|do not have enough MP)/) || text.match(/Cooldown|has expired|Spirit Stance|gains the effect|insufficient Spirit|Stop beating dead ponies| defeat |Clear Bonus|brink of defeat|Stop \w+ing|Spawned Monster| drop(ped|s) |defeated/)) { - // nothing; - } else if (debug) { - log = true; - setAudioAlarm('Error'); - console.log(text); - } } if (debug && log) { - console.table(stats); - pauseChange(); + console.table(stats); + pauseChange(); } setValue('stats', stats); - } +} - function recordUsage2() { +function recordUsage2() { const stats = getValue('stats', true); stats.self._monster += g('monsterAll'); stats.self._boss += g('bossAll'); - const battle = g('battle'); - if (g('option').recordEach && battle.roundNow === battle.roundAll) { - const old = getValue('statsOld', true) || []; - stats.__name = getValue('battleCode'); - stats.self._endTime = time(3); - old.push(stats); - setValue('statsOld', old); - delValue('stats'); + if (g('option').recordEach && g('roundNow') === g('roundAll')) { + const old = getValue('statsOld', true) || []; + stats.__name = getValue('battleCode'); + stats.self._endTime = time(3); + old.push(stats); + setValue('statsOld', old); + delValue('stats'); } else { - setValue('stats', stats); + setValue('stats', stats); } - } -} catch (e) { - console.log(e); - document.title = e; -} +} \ No newline at end of file