From 0a93fd99839f74f14cd1d456f0b3ecf41d032cb5 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 21 Aug 2025 10:39:56 +0800 Subject: [PATCH 001/216] =?UTF-8?q?=E6=8A=80=E8=83=BDOC=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=BD=93=E5=89=8D=E9=85=8D=E7=BD=AE=E7=9A=84?= =?UTF-8?q?=E6=94=BB=E5=87=BB=E6=B5=81=E6=B4=BE=E6=9D=A5=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E5=85=B7=E4=BD=93=E7=9A=84=E5=80=BC=EF=BC=9B=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E9=97=B2=E7=BD=AE=E7=AB=9E=E6=8A=80=E5=9C=BA?= =?UTF-8?q?=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 869e6349..3519c399 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2529,7 +2529,7 @@ try { arena.arrayDone = []; } if (!isToday || !arena.isOptionUpdated) { - arena.array = g('option').idleArenaValue.split(',') ?? []; + arena.array = g('option').idleArenaValue?.split(',') ?? []; arena.array.reverse(); } return setValue('arena', arena); @@ -3755,6 +3755,7 @@ try { } const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); + const fightStyle = g('option').fightingStyle; const skillLib = { OFC: { id: '1111', @@ -3765,16 +3766,17 @@ try { oc: 4, }, T3: { - id: `2${g('option').fightingStyle}03`, - oc: 2, + id: `2${fightStyle}03`, + // oc: 2203:4 2303:2 2403:3 + oc: fightStyle === 2 ? 4 : fightStyle === 3 ? 2 : fightStyle === 4 ? 3 : undefined, }, T2: { - id: `2${g('option').fightingStyle}02`, - oc: 2, + id: `2${fightStyle}02`, + oc: fightStyle === 1 ? undefined : 2, // 2202:2 2302:2 2402:2 }, T1: { - id: `2${g('option').fightingStyle}01`, - oc: 2, + id: `2${fightStyle}01`, + oc: fightStyle === 1 ? 4 : fightStyle === 2 ? 1 : 2 // 2101:4 2201:1 2301:2 2401:2 2501:2 }, }; const rangeSkills = { @@ -3803,7 +3805,7 @@ try { if (skillLib[skill].id in rangeSkills) { range = rangeSkills[skillLib[skill].id]; } - if (!g('option').mercifulBlow || g('option').fightingStyle !== '2' || skill !== 'T3') { + if (!g('option').mercifulBlow || fightStyle !== '2' || skill !== 'T3') { continue; } // Merciful Blow From c220bcb0f744ed9b3f6da292b9ef37cbc727bec4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 21 Aug 2025 10:41:55 +0800 Subject: [PATCH 002/216] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E4=B8=BA2.90.22.13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3519c399..9484495d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.12 +// @version 2.90.22.13 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From d9665d35d5e63e8ebed60d44784d01cd96aee464 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 21 Aug 2025 11:11:02 +0800 Subject: [PATCH 003/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E7=9A=84=E9=87=8A=E6=94=BE=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=AD=A3=E5=85=B6=E4=BB=96=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=9B=AE=E6=A0=87=E6=97=B6=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E8=8C=83=E5=9B=B4=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 | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9484495d..cef70905 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3757,28 +3757,20 @@ try { const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); const fightStyle = g('option').fightingStyle; const skillLib = { - OFC: { - id: '1111', - oc: 8, - }, - FRD: { - id: '1101', - oc: 4, - }, - T3: { - id: `2${fightStyle}03`, - // oc: 2203:4 2303:2 2403:3 - oc: fightStyle === 2 ? 4 : fightStyle === 3 ? 2 : fightStyle === 4 ? 3 : undefined, - }, - T2: { - id: `2${fightStyle}02`, - oc: fightStyle === 1 ? undefined : 2, // 2202:2 2302:2 2402:2 - }, - T1: { - id: `2${fightStyle}01`, - oc: fightStyle === 1 ? 4 : fightStyle === 2 ? 1 : 2 // 2101:4 2201:1 2301:2 2401:2 2501:2 - }, + OFC: '1111', + FRD: '1101', + T3: `2${fightStyle}03`, + T2: `2${fightStyle}02`, + T1: `2${fightStyle}01` }; + const skillOC = { // default as 2 + '1101': 4, + '1111': 8, + '2101': 4, + '2201': 1, + '2203': 4, + '2403': 3 + } const rangeSkills = { 2101: 2, 2403: 2, @@ -3787,37 +3779,39 @@ try { 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)) { + let id = skillLib[skill]; + if (!isOn(id)) { continue; } - if (g('oc') < skillLib[skill].oc) { + if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { 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 || fightStyle !== '2' || skill !== 'T3') { - continue; - } + gE(id).click(); // 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 target = 0; + if (g('option').mercifulBlow && fightStyle === '2' && skill === 'T3') { + for (let j = 0; j < monsterStatus.length; j++) { + if (monsterStatus[j].hpNow / monsterStatus[j].hp >= 0.25) { + continue; + } + if (!gE(`#mkey_${getMonsterID(monsterStatus[j])} img[src*="wpn_bleed"]`)) { + continue; + } + target = j; + break; } } + const range = id in rangeSkills ? rangeSkills[id] : 0; + gE(`#mkey_${getRangeCenterID(monsterStatus[target], range)}`).click(); + return true; } - gE(`#mkey_${getRangeCenterID(monsterStatus[0])}`).click(); - return true; } function useDeSkill() { // 自动施法DEBUFF技能 From fc9588832edeb0401387917bb228bcddba228f2b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 21 Aug 2025 21:06:05 +0800 Subject: [PATCH 004/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E4=B8=ADiscd=E7=9A=84=E5=80=BC=E4=B8=8EReadm?= =?UTF-8?q?e=E4=B8=AD=E7=A4=BA=E4=BE=8B=E4=B8=8D=E7=9B=B8=E7=AC=A6?= =?UTF-8?q?=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 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index cef70905..efe17f8a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.13 +// @version 2.90.22.14 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2001,8 +2001,8 @@ try { return str * 1; }; var func = { - isCd(id) { - return isOn(id) ? 0 : 1; + isCd(id) { // is cool down done + return isOn(id) ? 1 : 0; }, buffTurn(img) { let buff = gE(`#pane_effects>img[src*="${img}"]`); From eb005c493beea8aaceae39f0a0959e3a9b1856ee Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 12:18:38 +0800 Subject: [PATCH 005/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3iscd=E7=9A=84?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index efe17f8a..a1735a1f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.14 +// @version 2.90.22.15 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -520,7 +520,7 @@ try { if (id * 1 > 10000) { // 使用物品 return gE(`.bti3>div[onmouseover*="${id}"]`); } // 施放技能 - return (gE(id) && gE(id).style.opacity !== '0.5') ? gE(id) : false; + return (gE(id) && gE(id).style.opacity !== 0.5) ? gE(id) : false; } function setLocal(item, value) { From 0c5911542f363fc89c1ce441dd69c68cc4cb341b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 12:20:38 +0800 Subject: [PATCH 006/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a1735a1f..a731b81a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -520,7 +520,7 @@ try { if (id * 1 > 10000) { // 使用物品 return gE(`.bti3>div[onmouseover*="${id}"]`); } // 施放技能 - return (gE(id) && gE(id).style.opacity !== 0.5) ? gE(id) : false; + return (gE(id) && gE(id).style.opacity * 1 !== 0.5) ? gE(id) : false; } function setLocal(item, value) { From 12ab3ca8240cf0eed00c0faa63fe2a03acce6244 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 13:42:49 +0800 Subject: [PATCH 007/216] =?UTF-8?q?=E8=B0=83=E6=95=B4iscd=E5=8F=8A?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E6=A3=80=E6=B5=8B=E7=9B=B8=E5=85=B3=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a731b81a..83c94b9b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.15 +// @version 2.90.22.16 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -520,7 +520,7 @@ try { if (id * 1 > 10000) { // 使用物品 return gE(`.bti3>div[onmouseover*="${id}"]`); } // 施放技能 - return (gE(id) && gE(id).style.opacity * 1 !== 0.5) ? gE(id) : false; + return gE(id) && (gE(id).style.opacity * 1 !== 0.5); } function setLocal(item, value) { @@ -1979,7 +1979,6 @@ try { } let i; let j; let k; - const result = []; const returnValue = function (str) { if (str.match(/^_/)) { const arr = str.split('_'); @@ -2015,7 +2014,9 @@ try { }; for (i in parms) { + let parmResult = true; for (j = 0; j < parms[i].length; j++) { + let result = true; if (!Array.isArray(parms[i])) { continue; } @@ -2033,29 +2034,30 @@ try { switch (k[1]) { case '1': - result[i] = k[0] > k[2]; + result = k[0] > k[2]; break; case '2': - result[i] = k[0] < k[2]; + result = k[0] < k[2]; break; case '3': - result[i] = k[0] >= k[2]; + result = k[0] >= k[2]; break; case '4': - result[i] = k[0] <= k[2]; + result = k[0] <= k[2]; break; case '5': - result[i] = k[0] === k[2]; + result = k[0] === k[2]; break; case '6': - result[i] = k[0] !== k[2]; + result = k[0] !== k[2]; break; } - if (result[i] === false) { - j = parms[i].length; + if (!result) { + parmResult = false; + break; } } - if (result[i] === true) { + if (parmResult) { return true; } } @@ -3391,8 +3393,11 @@ try { 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(); + let id = order[i]; + if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { + if(isOn(id)){ + gE(id).click(); + } return true; } } From 83b592208ec81c0831e9f9bbf4915be9045bc99c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 14:22:18 +0800 Subject: [PATCH 008/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 83c94b9b..43afeb1e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3396,7 +3396,7 @@ try { let id = order[i]; if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { if(isOn(id)){ - gE(id).click(); + gE(id)?.click(); } return true; } From 642b988de0190b7ac834b0864038038e528f8b54 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 14:25:00 +0800 Subject: [PATCH 009/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 43afeb1e..535340eb 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3394,10 +3394,8 @@ try { const order = g('option').itemOrderValue.split(','); for (let i = 0; i < name.length; i++) { let id = order[i]; - if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { - if(isOn(id)){ - gE(id)?.click(); - } + if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id) && gE(id)) { + gE(id).click(); return true; } } From 61c4ebb3708baf0a9c2499287cf07cf4b312dcb1 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 15:40:23 +0800 Subject: [PATCH 010/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 535340eb..9a610d5e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.16 +// @version 2.90.22.17 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3394,8 +3394,8 @@ try { const order = g('option').itemOrderValue.split(','); for (let i = 0; i < name.length; i++) { let id = order[i]; - if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id) && gE(id)) { - gE(id).click(); + if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { + gE(`.bti3>div[onmouseover*="${id}"]`).click(); return true; } } From 6991b8fb4da6753826ef03f341378d7ddfdfb832 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Sep 2025 16:37:03 +0800 Subject: [PATCH 011/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9a610d5e..3eebb6b1 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3395,7 +3395,7 @@ try { for (let i = 0; i < name.length; i++) { let id = order[i]; if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { - gE(`.bti3>div[onmouseover*="${id}"]`).click(); + (gE(`.bti3>div[onmouseover*="${id}"]`) ?? gE(id)).click(); return true; } } From 0c1c4f69327b6c9e20d96377e4c9de7493a19712 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Sep 2025 07:24:45 +0800 Subject: [PATCH 012/216] =?UTF-8?q?=E9=87=8A=E6=94=BE=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8F=AF=E4=BB=A5=E6=8C=89=E7=85=A7option?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3eebb6b1..c55ad5f0 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.17 +// @version 2.90.22.18 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1990,7 +1990,7 @@ try { let result; for (let key of paramList) { if (!result) { - result = (g('battle') ?? getValue('battle', true))[key] ?? g(key) ?? getValue(key); + result = (g('battle') ?? getValue('battle', true))[key] ?? g(key) ?? getValue(key) ?? g('option')?.[key]; continue; } result = result[key] From fbce5ce2a78f93f5869c37c41e1c57c18189572b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Sep 2025 07:29:26 +0800 Subject: [PATCH 013/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c55ad5f0..8a0f4cd4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1747,9 +1747,11 @@ try { '', '', '', - '', '', '', + '', + '', + '', '', '', '', From 71b6763720e6b5a853514c07c72803525b26f238 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Sep 2025 07:39:31 +0800 Subject: [PATCH 014/216] =?UTF-8?q?fightingStyle=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8A=A8=E6=80=81=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8a0f4cd4..119bedda 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -305,6 +305,12 @@ try { setPauseUI(box2); reloader(); g('attackStatus', g('option').attackStatus); + for (let fightingStyle = 1; fightingStyle < 6; fightingStyle++) { + if(gE(`2${fightingStyle}01`)){ + g('fightingStyle', fightingStyle.toString()); + } + } + g('timeNow', time(0)); g('runSpeed', 1); Debug.log('______________newRound', false); @@ -1034,7 +1040,6 @@ try { ' ', '
: {{skillOFCCondition}}
', '
: {{skillFRDCondition}}
', - '
战斗风格戰鬥風格Fighting style:
', '
:
{{skillT3Condition}}
', '
: {{skillT2Condition}}
', '
: {{skillT1Condition}}
', @@ -3760,7 +3765,7 @@ try { } const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); - const fightStyle = g('option').fightingStyle; + const fightStyle = g('fightingStyle'); const skillLib = { OFC: '1111', FRD: '1101', @@ -4001,7 +4006,7 @@ try { const attackStatus = g('attackStatus'); const monsterStatus = g('battle').monsterStatus; if (attackStatus === 0) { - if (g('option').fightingStyle === '1') { // 二天一流 + if (g('fightingStyle') === '1') { // 二天一流 range = 1; } } else { From e44337a84f57253570118a6695d168cc4a346283 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 7 Sep 2025 21:19:53 +0800 Subject: [PATCH 015/216] fix http/https wrong replace --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 119bedda..15b8b436 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.18 +// @version 2.90.22.19 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -61,9 +61,9 @@ try { } try { if(window.location.href.startsWith('https://')) { - MAIN_URL = MAIN_URL.replace(/^http:/, /^https:/); + MAIN_URL = MAIN_URL.replace(/^http:/, 'https:'); } else { - MAIN_URL = MAIN_URL.replace(/^https:/, /^http:/); + MAIN_URL = MAIN_URL.replace(/^https:/, 'http:'); } } catch (e) {} const Debug = { From a55b9dec7f96e88736e9dd277fe27ff91d2bd4bf Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 21 Oct 2025 13:55:26 +0800 Subject: [PATCH 016/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=88=98=E6=96=97?= =?UTF-8?q?=E4=B8=AD=E7=8A=B6=E6=80=81=E6=A0=8F=E7=99=BE=E5=88=86=E7=99=BE?= =?UTF-8?q?=E6=95=B0=E5=80=BC=E7=9A=84=E6=8F=92=E5=85=A5=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 15b8b436..83b50147 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.19 +// @version 2.90.22.20 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4127,18 +4127,24 @@ try { const value = text.innerHTML * 1; const percentage = value ? percentages[i] : 0; const inner = `[${percentage.toString()}%]`; + text.style.cssText = ` + display: grid; + grid-template-columns: 1fr 1fr; + width: 120px; + ` const percentageDiv = gE('div', text); + const style = ` + position: relative; + right: -10px; + filter: brightness(0.2); + text-align: left; + ` if (percentageDiv) { percentageDiv.innerHTML = inner; + percentageDiv.style.cssText = style; return; } - text.innerHTML += `
${inner}
` + text.innerHTML += `
${inner}
` }); } From f398208c88600a0d3587c1d8a77c7ea60bff7f82 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 21 Oct 2025 14:05:44 +0800 Subject: [PATCH 017/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 83b50147..0343be33 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4127,18 +4127,19 @@ try { const value = text.innerHTML * 1; const percentage = value ? percentages[i] : 0; const inner = `[${percentage.toString()}%]`; - text.style.cssText = ` + text.style.cssText += textOC ? ` display: grid; grid-template-columns: 1fr 1fr; width: 120px; - ` + `: ""; const percentageDiv = gE('div', text); const style = ` position: relative; - right: -10px; + top: ${textOC ? 0 : text === textHP ? -16.67 : -16}px; + right: ${textOC ? -10 : text === textMP ? -60 : text === textSP ? 40 : -100}px; filter: brightness(0.2); text-align: left; - ` + ` if (percentageDiv) { percentageDiv.innerHTML = inner; percentageDiv.style.cssText = style; From 4d38713a0c3508aa9be29f92573b1db028b1fca5 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 21 Oct 2025 22:07:44 +0800 Subject: [PATCH 018/216] =?UTF-8?q?=E6=94=B9=E4=B8=BA=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E4=BB=85=E5=9C=A8=E5=BC=80=E5=90=AF=E9=81=AD=E9=81=87=E6=88=98?= =?UTF-8?q?=E6=97=B6=E6=98=BE=E7=A4=BA=E5=80=92=E8=AE=A1=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=8D=E5=BC=80=E5=90=AF=E6=97=B6=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=80=92=E8=AE=A1=E6=97=B6=E7=9A=84=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0343be33..859a648e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.20 +// @version 2.90.22.21 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -856,7 +856,7 @@ try { ' ', '
', - '
', + '
', '
;
', ' 进行的竞技场相对应等级進行的競技場相對應等級The levels of the Arena you want to complete: ', @@ -2431,6 +2431,10 @@ try { } async function updateEncounter(engage, isInBattle) { try { + if(!g('option').encounter && !g('option').encounterDisplay){ + console.log("skip encounter check"); + return; + } if(getValue('disabled')){ await pauseAsync(_1s); return await updateEncounter(engage, isInBattle); From 532275a71e1caacc8c088a25d2c55925a3f475d3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 22 Oct 2025 04:26:39 +0800 Subject: [PATCH 019/216] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E6=97=A7?= =?UTF-8?q?=E7=89=88=E6=9C=ACencounter=E6=95=B0=E6=8D=AE=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E5=92=8C=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 859a648e..bfc29c80 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2212,6 +2212,19 @@ try { for (let e of current) { dict[e.href ?? `newDawn`] = e; } + try { + // if is latest version data + for (let e of encounter) {} + } catch { + // if old versions + const last = encounter.lastTime; + const times = encounter.time; + encounter = []; + for (let i = 0; i <= times; i++) { + encounter.unshift({ href: i===0 ? undefined : i, time: last, encountered: i===0 ? undefined : time(0) }); + } + setEncounter(encounter); + } for (let e of encounter) { const key = e.href ?? `newDawn`; dict[key] ??= e; From 239d310ac5adc347bf61d9f53bc0c43cb7498ced Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 22 Oct 2025 18:26:33 +0800 Subject: [PATCH 020/216] =?UTF-8?q?=E8=B0=83=E6=95=B4debuff=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index bfc29c80..fc2abc6d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.21 +// @version 2.90.22.22 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3849,10 +3849,9 @@ try { let skillPack = ['We', 'Im']; 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; + if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`])) { // 检查条件 + continue; + } } skillPack.splice(i, 1); i--; @@ -3864,13 +3863,12 @@ try { } for (let i in skillPack) { let buff = skillPack[i]; - if (i >= toAllCount && !skillPack[i]) { // 检查buff是否启用 - continue; - } - if (!checkCondition(g('option')[`debuffSkill${buff}Condition`])) { // 检查条件 - continue; + if (i >= toAllCount) { // 非先全体 + if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`])) { // 检查条件 + continue; + } } - let succeed = useDebuffSkill(skillPack[i], i < toAllCount); + let succeed = useDebuffSkill(buff, i < toAllCount); // 前 toAllCount 个都是先给全体上的 if (succeed) { return true; From 10050f5b145e34401c426811d7778eb50152b7d4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 22 Oct 2025 18:39:53 +0800 Subject: [PATCH 021/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=9A=82=E5=81=9C?= =?UTF-8?q?=E6=97=B6=E6=88=98=E6=96=97=E7=BB=93=E6=9D=9F=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E9=99=A4=E6=9A=82=E5=81=9C=E6=97=B6=E6=9C=AA=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E9=80=80=E5=87=BA=E6=88=98=E6=96=97=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 | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index fc2abc6d..379c7739 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.22 +// @version 2.90.22.21 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3056,30 +3056,35 @@ try { } 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(); + async function onNewRound(){ try { + if(getValue('disabled')){ + await pauseAsync(_1s); + return await onNewRound(); + } + if(gE('#btcp').innerHTML.containes("finishbattle.png")){ + goto(); + return; + } + 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; } - ['#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) } - } - } + goto(); + return; + } + ['#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) } + }} if (g('monsterAlive') > 0) { // Defeat SetExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); From ac5161701c3e9b7d63c8d2dedb1e9b8227006578 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 16:31:50 +0800 Subject: [PATCH 022/216] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Ability=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9C=AA=E5=88=9D=E5=A7=8B=E5=8C=96=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=B5=8B=E5=92=8C=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 379c7739..a97f024c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.21 +// @version 2.90.22.22 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3962,7 +3962,10 @@ try { if (!ranges) { continue; } - range = ranges[getValue('ability', true)[ab].level]; + const ability = getValue('ability', true); + if(ability){ + range = ranges[ability[ab].level]; + } break; } let id = getRangeCenterID(primaryTarget, range, isDebuffed); @@ -4047,7 +4050,10 @@ try { if (!ranges) { continue; } - range = ranges[getValue('ability', true)[ab]?.level ?? 0]; + const ability = getValue('ability', true); + if(ability){ + range = ranges[ability[ab].level]; + } break; } } From 30ef52e1eda46fa87c663aeddcf000a6cb6b1cff Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 16:33:38 +0800 Subject: [PATCH 023/216] Bump version to 2.90.22.23 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a97f024c..3c94608d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.22 +// @version 2.90.22.23 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From 2f88ccbb37db33905b239adaec5903177a3a619b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 21:15:40 +0800 Subject: [PATCH 024/216] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dgr=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=BC=80=E5=90=AF=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 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3c94608d..d9da0feb 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.23 +// @version 2.90.22.24 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2637,7 +2637,7 @@ try { let href, cost; let token = arena.token[id]; - const key = id; + let key = id; if (key === 'gr') { if (arena.gr <= 0) { setValue('arena', arena); From 66a66507a6deb0b219f417cab691e9fe0705c574 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 21:25:24 +0800 Subject: [PATCH 025/216] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E5=8E=8B=E6=A6=A8=E5=B1=8A=E7=9A=84stamina=E9=98=88=E5=80=BC?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d9da0feb..732b0a49 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -872,6 +872,7 @@ try { '
含本日自然恢复的阈值含本日自然恢復的閾值Stamina threshold with naturally recovers today.: ;
', '
', '
进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', + '
进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
', '
', '
: ', ' 耐久度耐久度Durability%
', @@ -2657,7 +2658,7 @@ try { href = 'ar'; } cost ??= staminaCost[key]; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true })) { + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: g('option').staminaGrindFest})) { logSwitchAsyncTask(arguments); return; } From 910f2cb849df8af0db2217a904b0b691528d611c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 22:17:41 +0800 Subject: [PATCH 026/216] =?UTF-8?q?=E5=85=A8=E4=BD=93=E4=B8=8Adebuff?= =?UTF-8?q?=E7=9A=84=E7=9B=AE=E6=A0=87=E9=80=89=E6=8B=A9=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E6=8C=89=E7=85=A7=E4=BD=8D=E6=AC=A1=EF=BC=88?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E7=BB=9F=E4=B8=80=E6=9D=83=E9=87=8D=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=89=E8=80=8C=E9=9D=9E=E6=9D=83=E9=87=8D=E9=80=89?= =?UTF-8?q?=E6=8B=A9=EF=BC=88=E4=BB=A5=E4=BF=9D=E9=9A=9C=E5=B0=BD=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=B0=91=E6=AD=A5=E9=AA=A4=E6=94=BE=E5=AE=8C=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 732b0a49..e5f2304f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.24 +// @version 2.90.22.25 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1021,8 +1021,8 @@ try { ' ', ' ', '
', - '
特殊Special
{{debuffSkillWeAllCondition}}', - '
特殊Special
{{debuffSkillImAllCondition}}', + '
特殊Special
{{debuffSkillWeAllCondition}}', + '
特殊Special
{{debuffSkillImAllCondition}}', '
{{debuffSkillSleCondition}}
', '
{{debuffSkillBlCondition}}
', '
{{debuffSkillSloCondition}}
', @@ -2906,7 +2906,7 @@ try { * @param {(target) => bool} excludeCondition target with id * @returns */ - function getRangeCenterID(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined) { + function getRangeCenterID(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { if (!range) { return getMonsterID(target); } @@ -2932,7 +2932,10 @@ try { rank += unreachableWeight - cew; continue; } - rank += mon.finWeight + cew; // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 + // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 + rank += cew; + // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 + rank += forceUseIndex ? -1 : mon.finWeight; } if (rank < minRank) { newOrder = i; @@ -3969,7 +3972,8 @@ try { } break; } - let id = getRangeCenterID(primaryTarget, range, isDebuffed); + let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; + let id = getRangeCenterID(primaryTarget, range, isDebuffed, debuffByIndex); const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); // 已有buff小于6个 // 未开启debuff失败警告 From 178803e9b48b310334393cefddb02749e1bb30c8 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 23 Oct 2025 22:50:04 +0800 Subject: [PATCH 027/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e5f2304f..6e463d61 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3961,19 +3961,19 @@ try { let range = 0; let ab; + const ability = getValue('ability', true); for (ab in skillLib[buff].range) { - const ranges = skillLib[buff].range[ab][skillLib[buff].skill * 1]; + const ranges = skillLib[buff].range[ab]; if (!ranges) { continue; } - const ability = getValue('ability', true); if(ability){ range = ranges[ability[ab].level]; } break; } let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; - let id = getRangeCenterID(primaryTarget, range, isDebuffed, debuffByIndex); + let id = getRangeCenterID(primaryTarget, range, false, isDebuffed, debuffByIndex); const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); // 已有buff小于6个 // 未开启debuff失败警告 From cdcb7837462f7be3bfa5d47b798f6d2c39a03c42 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 24 Oct 2025 20:57:35 +0800 Subject: [PATCH 028/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=80=90=E5=8A=9B?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=9D=A1=E4=BB=B6=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6e463d61..46a47a5d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.25 +// @version 2.90.22.26 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2658,7 +2658,7 @@ try { href = 'ar'; } cost ??= staminaCost[key]; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: g('option').staminaGrindFest})) { + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: href = 'gr' ? g('option').staminaGrindFest : 0})) { logSwitchAsyncTask(arguments); return; } From 7e6e3de21f1f922201969ddde9fb5e3ac9c27408 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 24 Oct 2025 21:12:24 +0800 Subject: [PATCH 029/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=85=A8=E4=BD=93deb?= =?UTF-8?q?uff=E9=80=89=E6=8B=A9=E5=88=9D=E5=A7=8B=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=BA=86=E4=BD=86=E6=9C=AA=E6=8C=89=E7=85=A7?= =?UTF-8?q?=E5=BA=8F=E5=8F=B7=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 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 46a47a5d..323d1fcb 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3940,7 +3940,8 @@ try { if (!isOn(skillLib[buff].id)) { // 技能不可用 return false; } - const monsterStatus = g('battle').monsterStatus; + let monsterStatus = g('battle').monsterStatus; + let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); let primaryTarget; let max = isAll ? monsterStatus.length : 1; @@ -3952,9 +3953,11 @@ try { if (isDebuffed(target)) { // 检查是否已有该buff continue; } - primaryTarget = target; - break; + if(!primaryTarget || (debuffByIndex && primaryTarget.order > target.order)){ + primaryTarget = target; + } } + console.log(primaryTarget, monsterStatus); if (primaryTarget === undefined) { return false; } @@ -3972,7 +3975,6 @@ try { } break; } - let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; let id = getRangeCenterID(primaryTarget, range, false, isDebuffed, debuffByIndex); const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); // 已有buff小于6个 From b464900f8bde40d1dc11c7409059cb8d35d87889 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 24 Oct 2025 21:13:12 +0800 Subject: [PATCH 030/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 - 1 file changed, 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 323d1fcb..377154ac 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3957,7 +3957,6 @@ try { primaryTarget = target; } } - console.log(primaryTarget, monsterStatus); if (primaryTarget === undefined) { return false; } From ef653c971413c3d758042c72484bfa429b9a8918 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 25 Oct 2025 01:07:13 +0800 Subject: [PATCH 031/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 377154ac..f29cc853 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2658,7 +2658,7 @@ try { href = 'ar'; } cost ??= staminaCost[key]; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: href = 'gr' ? g('option').staminaGrindFest : 0})) { + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: href === 'gr' ? g('option').staminaGrindFest : undefined})) { logSwitchAsyncTask(arguments); return; } From 7bbe641a6068084873abc18224ff4de277298e79 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 25 Oct 2025 16:51:05 +0800 Subject: [PATCH 032/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=87=8A=E6=94=BE?= =?UTF-8?q?=E5=85=A8=E4=BD=93buff=E5=AF=BB=E6=89=BE=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f29cc853..285cd7ef 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.26 +// @version 2.90.22.27 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2906,9 +2906,9 @@ try { * @param {(target) => bool} excludeCondition target with id * @returns */ - function getRangeCenterID(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { + function getRangeCenter(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { if (!range) { - return getMonsterID(target); + return { id: getMonsterID(target), rank: Number.MAX_SAFE_INTEGER }; } const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (g('option').centralExtraRatio / 100) ?? 0 : 0)); let order = target.order; @@ -2917,7 +2917,7 @@ try { let msTemp = JSON.parse(JSON.stringify(g('battle').monsterStatus)); msTemp.sort(objArrSort('order')); let unreachableWeight = g('option').unreachableWeight; - let minRank; + let minRank = Number.MAX_SAFE_INTEGER; for (let i = order - range; i <= order + range; i++) { if (i < 0 || i >= msTemp.length || msTemp[i].isDead) { continue; // 无法选中 @@ -2939,9 +2939,10 @@ try { } if (rank < minRank) { newOrder = i; + minRank = rank; } } - return getMonsterID(newOrder); + return { id: getMonsterID(newOrder), rank: minRank}; } function autoPause() { @@ -3401,7 +3402,8 @@ try { } 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" + const name = gE('div.btm3>div>div', monsterBuff[i].parentNode).innerText; + if (yggdrasilExtraWeight && ('Yggdrasil' === name || '世界树 Yggdrasil' === name)) { // 默认设置下,任何情况都优先击杀群体大量回血的boss"Yggdrasil" weight += yggdrasilExtraWeight; // yggdrasilExtraWeight.defalut -1000 } for (j in skillLib) { @@ -3845,7 +3847,7 @@ try { } } const range = id in rangeSkills ? rangeSkills[id] : 0; - gE(`#mkey_${getRangeCenterID(monsterStatus[target], range)}`).click(); + gE(`#mkey_${getRangeCenter(monsterStatus[target], range).id}`).click(); return true; } } @@ -3940,27 +3942,7 @@ try { if (!isOn(skillLib[buff].id)) { // 技能不可用 return false; } - let monsterStatus = g('battle').monsterStatus; - let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; - let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); - let primaryTarget; - let max = isAll ? 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; - } - if(!primaryTarget || (debuffByIndex && primaryTarget.order > target.order)){ - primaryTarget = target; - } - } - if (primaryTarget === undefined) { - return false; - } - + // 获取范围 let range = 0; let ab; const ability = getValue('ability', true); @@ -3974,7 +3956,33 @@ try { } break; } - let id = getRangeCenterID(primaryTarget, range, false, isDebuffed, debuffByIndex); + + // 获取目标 + let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); + let monsterStatus = g('battle').monsterStatus; + let max = isAll ? monsterStatus.length : 1; + let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; + let id; + let minRank = Number.MAX_SAFE_INTEGER; + for (let i = 0; i < max; i++) { + let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; + if (target.isDead || isDebuffed(target)) { + continue; + } + const center = getRangeCenter(target, range, false, isDebuffed, debuffByIndex); + if(!id || center.rank < minRank){ + minRank = center.rank; + id = center.id; + if(!debuffByIndex){ + // 只有按照顺序覆盖全体才需要遍历全部 + break; + } + } + } + if (id === undefined) { + return false; + } + const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); // 已有buff小于6个 // 未开启debuff失败警告 @@ -4064,7 +4072,7 @@ try { } } } - gE(`#mkey_${getRangeCenterID(monsterStatus[0], range, !attackStatus)}`).click(); + gE(`#mkey_${getRangeCenter(monsterStatus[0], range, !attackStatus).id}`).click(); return true; } From d2c7c94dbec2216d10052746cb70f72d599b27e3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 25 Oct 2025 16:52:58 +0800 Subject: [PATCH 033/216] Refactor condition for target range check --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 285cd7ef..26df51e2 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3973,8 +3973,8 @@ try { if(!id || center.rank < minRank){ minRank = center.rank; id = center.id; - if(!debuffByIndex){ - // 只有按照顺序覆盖全体才需要遍历全部 + if(!isAll){ + // 只有覆盖全体才需要遍历全部 break; } } From 5ca7e1a356481328ae32f3e1154edae823b8e35e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 25 Oct 2025 17:48:09 +0800 Subject: [PATCH 034/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=96=B0=E5=85=B3=E5=8D=A1=E6=88=96=E9=80=80=E5=87=BA=E7=9A=84?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E5=87=BD=E6=95=B0=E5=90=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 26df51e2..e8d4b57b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.27 +// @version 2.90.22.28 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3066,7 +3066,7 @@ try { await pauseAsync(_1s); return await onNewRound(); } - if(gE('#btcp').innerHTML.containes("finishbattle.png")){ + if(gE('#btcp')?.innerHTML.includes("finishbattle.png")){ goto(); return; } From e8abff7e3dcdd8b8d6aedf79315ac2f77996d3a9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 25 Oct 2025 17:54:15 +0800 Subject: [PATCH 035/216] =?UTF-8?q?=E6=8C=89=E7=85=A7=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E5=85=A8=E4=BD=93=E4=B8=8Adebuff=E6=97=B6=E6=8C=89=E7=85=A7?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E9=81=8D=E5=8E=86=E8=80=8C=E9=9D=9E=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E6=9D=83=E9=87=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e8d4b57b..acf0d214 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.28 +// @version 2.90.22.29 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3959,9 +3959,14 @@ try { // 获取目标 let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); + let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; let monsterStatus = g('battle').monsterStatus; + if (debuffByIndex){ + monsterStatus = JSON.parse(JSON.stringify(monsterStatus)); + monsterStatus.sort(objArrSort('order')); + } let max = isAll ? monsterStatus.length : 1; - let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; + let id; let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { From d92b19b69fe4c95657ec1f3712a251900090dd3b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 27 Oct 2025 15:31:08 +0800 Subject: [PATCH 036/216] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8D=B7=E8=BD=B4?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index acf0d214..fa53cbcc 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.29 +// @version 2.90.22.30 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3501,20 +3501,22 @@ try { }, }; 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]) { + continue; + } + if(!gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`)){ + continue; + } + if(!checkCondition(g('option')[`scroll${i}Condition`])){ + continue; + } + for (let j = 1; j <= scrollLib[i].mult; j++) { + if (gE(`#pane_effects>img[src*="${scrollLib[i][`img${j}`]}${scrollFirst}"]`)) { + continue; } + gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`).click(); + return true; } } return false; From 827a7dccf0f3c62876f5974b813aa275bd136327 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 27 Oct 2025 16:26:08 +0800 Subject: [PATCH 037/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E5=92=8C=E4=BD=BF=E7=94=A8=E7=89=A9=E5=93=81?= =?UTF-8?q?=EF=BC=8Cquery=E9=A1=B5=E9=9D=A2elem=E6=97=B6=EF=BC=8C=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=8A=80=E8=83=BD>=E6=B2=BB=E7=96=97(311)=E4=BC=9A?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=88=B0=E7=89=A9=E5=93=81>=E5=AE=88?= =?UTF-8?q?=E6=8A=A4=E5=8D=B7=E8=BD=B4(13111)=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 | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index fa53cbcc..dcca6ffc 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.30 +// @version 2.90.22.31 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -524,7 +524,7 @@ try { 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 * 1 !== 0.5); } @@ -3430,7 +3430,7 @@ try { for (let i = 0; i < name.length; i++) { let id = order[i]; if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { - (gE(`.bti3>div[onmouseover*="${id}"]`) ?? gE(id)).click(); + (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); return true; } } @@ -3444,15 +3444,15 @@ try { if (!g('option').scroll) { return false; } - if (!checkCondition(g('option').scrollCondition)) { - return false; - } if (!g('option').scrollRoundType) { return false; } if (!g('option').scrollRoundType[g('battle').roundType]) { return false; } + if (!checkCondition(g('option').scrollCondition)) { + return false; + } const scrollLib = { Go: { name: 'Scroll of the Gods', @@ -3505,7 +3505,7 @@ try { if (!g('option').scroll[i]) { continue; } - if(!gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`)){ + if(!gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`)){ continue; } if(!checkCondition(g('option')[`scroll${i}Condition`])){ @@ -3515,7 +3515,7 @@ try { if (gE(`#pane_effects>img[src*="${scrollLib[i][`img${j}`]}${scrollFirst}"]`)) { continue; } - gE(`.bti3>div[onmouseover*="${scrollLib[i].id}"]`).click(); + gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`).click(); return true; } } @@ -3720,8 +3720,8 @@ try { }, }; 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(); + 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; } } @@ -3758,8 +3758,8 @@ try { 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(); + 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; } return false; From f4fc0d637c9f32a1b59649a02e75011310424279 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 31 Oct 2025 16:48:22 +0800 Subject: [PATCH 038/216] =?UTF-8?q?=E8=B0=83=E6=95=B4gr=E6=AC=A1=E6=95=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=9A=84=E6=97=B6=E6=9C=BA=E5=88=B0=E6=A3=80?= =?UTF-8?q?=E6=B5=8Bstamina=E9=80=9A=E8=BF=87=E4=B9=8B=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index dcca6ffc..6e930a6e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.31 +// @version 2.90.22.32 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2646,7 +2646,6 @@ try { arena.arrayDone.push('gr'); return; } - arena.gr--; href = 'gr'; key = 1; cost = staminaCost.gr; @@ -2663,8 +2662,10 @@ try { return; } document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); - if(key !== 'gr'){ + if (key !== 'gr'){ arena.arrayDone.push(key); + } else { + arena.gr--; } setValue('arena', arena); $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); @@ -3801,7 +3802,7 @@ try { FRD: '1101', T3: `2${fightStyle}03`, T2: `2${fightStyle}02`, - T1: `2${fightStyle}01` + T1: `2${fightStyle}01`, }; const skillOC = { // default as 2 '1101': 4, From f622e2590379cc5364245a135d46d9da5b266451 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 31 Oct 2025 17:41:29 +0800 Subject: [PATCH 039/216] Bump version to 2.90.22.33 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6e930a6e..6caa7df8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.32 +// @version 2.90.22.33 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1041,7 +1041,7 @@ try { ' ', '
: {{skillOFCCondition}}
', '
: {{skillFRDCondition}}
', - '
:
{{skillT3Condition}}
', + '
:
', '
: {{skillT2Condition}}
', '
: {{skillT1Condition}}
', @@ -3817,7 +3817,6 @@ try { 2403: 2, 1111: 4, } - const monsterStatus = g('battle').monsterStatus; for (let i in skillOrder) { let skill = skillOrder[i]; if (!checkCondition(g('option')[`skill${skill}Condition`])) { @@ -3835,26 +3834,41 @@ try { } g('skillOTOS')[skill]++; gE(id).click(); - // Merciful Blow - let target = 0; - if (g('option').mercifulBlow && fightStyle === '2' && skill === 'T3') { - for (let j = 0; j < monsterStatus.length; j++) { - if (monsterStatus[j].hpNow / monsterStatus[j].hp >= 0.25) { - continue; - } - if (!gE(`#mkey_${getMonsterID(monsterStatus[j])} img[src*="wpn_bleed"]`)) { - continue; - } - target = j; - break; - } + let target = getWeaponSkillTarget(id); + if(!target){ + continue; } const range = id in rangeSkills ? rangeSkills[id] : 0; - gE(`#mkey_${getRangeCenter(monsterStatus[target], range).id}`).click(); + gE(`#mkey_${getRangeCenter(target, range).id}`).click(); return true; } } + function getWeaponSkillTarget(id){ + let target = undefined; + const monsterStatus = g('battle').monsterStatus; + if (id !== 2203) { + return monsterStatus[0]; + } + // Merciful Blow + if(g('option').mercifulBlow || g('option').mercifulBlowStrict){ + // get target with conditions (hp < 0.25 and bleeding) + for (let j = 0; j < monsterStatus.length; j++) { + if (monsterStatus[j].hpNow / monsterStatus[j].hp >= 0.25) { + continue; + } + if (!gE(`#mkey_${getMonsterID(monsterStatus[j])} img[src*="wpn_bleed"]`)) { + continue; + } + return monsterStatus[j]; + } + } + if(!g('option').mercifulBlowStrict){ + return monsterStatus[0]; + } + return undefined; + } + function useDeSkill() { // 自动施法DEBUFF技能 if (!g('option').debuffSkillSwitch) { // 总开关是否开启 return false; From 500d69f9230334874a9b845e4f3749f32ad85cdc Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 1 Nov 2025 23:17:01 +0800 Subject: [PATCH 040/216] =?UTF-8?q?=E6=B2=A1=E6=9C=89=E8=A3=85=E5=A4=87?= =?UTF-8?q?=E6=AD=A6=E5=99=A8=E6=97=B6=E7=9A=84=E6=8A=80=E8=83=BD=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6caa7df8..761eaf93 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.33 +// @version 2.90.22.34 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3797,6 +3797,9 @@ try { const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); const fightStyle = g('fightingStyle'); + if(!fightStyle){ + return; + } const skillLib = { OFC: '1111', FRD: '1101', From 14431c699448214c33335000dd4eb9689624a3da Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 1 Nov 2025 23:20:51 +0800 Subject: [PATCH 041/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 761eaf93..53ce3121 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3797,15 +3797,12 @@ try { const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); const fightStyle = g('fightingStyle'); - if(!fightStyle){ - return; - } const skillLib = { OFC: '1111', FRD: '1101', - T3: `2${fightStyle}03`, - T2: `2${fightStyle}02`, - T1: `2${fightStyle}01`, + T3: fightStyle ? `2${fightStyle}03` : undefined, + T2: fightStyle ? `2${fightStyle}02` : undefined, + T1: fightStyle ? `2${fightStyle}01` : undefined, }; const skillOC = { // default as 2 '1101': 4, @@ -3822,6 +3819,9 @@ try { } for (let i in skillOrder) { let skill = skillOrder[i]; + if(!skill){ + return; + } if (!checkCondition(g('option')[`skill${skill}Condition`])) { continue; } From b63d008c2f0f4f45065aecfbca96863875af16b4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 00:59:15 +0800 Subject: [PATCH 042/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3gr=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=88=9D=E6=AC=A1=E6=8C=91=E6=88=98=E6=97=B6=EF=BC=8C=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1token=E5=AF=BC=E8=87=B4=E6=8A=A5=E9=94=99=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=88=E7=9B=B4=E6=8E=A5=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=82=B9=E5=87=BB=E6=8C=89=E9=92=AE=EF=BC=8C?= =?UTF-8?q?=E4=BE=8B=E5=A6=82=E5=BC=82=E4=B8=96=E7=95=8C=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E8=B5=9B=E5=AD=A3=E5=90=8E=E7=9A=84=E7=AC=AC=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E4=BC=9A=E7=BC=BA=E5=A4=B1token=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 53ce3121..0d967fb8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.34 +// @version 2.90.22.35 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2541,7 +2541,10 @@ try { 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]; + const onclickInner = gE('img[src*="startgrindfest.png"]', doc).getAttribute('onclick').match(/init_battle\(1, '(.*?)'\)/); + if(onclickInner){ + arena.token.gr = onclickInner[1]; + } return; } gE('img[src*="startchallenge.png"]', 'all', doc).forEach((_) => { @@ -2668,7 +2671,15 @@ try { arena.gr--; } setValue('arena', arena); - $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); + if(!token && href === 'gr'){ + if(window.location.href.includes(`?s=Battle&ss=gr`)){ + gE('#grindfest>div>div>img').onclick(); + } else { + const html = $ajax.open(`?s=Battle&ss=gr`); + } + } else { + $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); + } logSwitchAsyncTask(arguments); } catch (e) {console.error(e)}} From 222513b8617715db9dd7ee5b1683e7cd22f86c3f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 01:01:20 +0800 Subject: [PATCH 043/216] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=B8=8Bhp=E6=9D=A1=E6=98=BE=E7=A4=BA=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0d967fb8..87c6cb45 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4193,7 +4193,7 @@ try { const barMP = gE('#vbm') ?? gE('#dvbm'); const barSP = gE('#vbs') ?? gE('#dvbs'); const barOC = gE('#dvbc'); - const textHP = gE('#vrhd') ?? gE('#dvrhd'); + const textHP = gE('#vrhd') ?? gE('#dvrhd') ?? gE('#dvrhb'); const textMP = gE('#vrm') ?? gE('#dvrm'); const textSP = gE('#vrs') ?? gE('#dvrs'); const textOC = gE('#dvrc'); From 5246a04c8ffc57c25fd769ed4f3a473948db9f9d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 01:21:42 +0800 Subject: [PATCH 044/216] =?UTF-8?q?=E5=A2=9E=E5=8A=A0sp=E5=B0=8F=E4=BA=8E?= =?UTF-8?q?=E7=AD=89=E4=BA=8E1=E6=97=B6=E5=BC=80=E5=90=AFss=E7=9A=84?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=88=E6=AD=A4=E6=97=B6=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E5=BC=80=E5=90=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 87c6cb45..f21153c7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3786,6 +3786,12 @@ try { } function autoSS() { + const textSP = gE('#vrs') ?? gE('#dvrs'); + const spValue = textSP.childNodes[0].textContent * 1; + if (spValue <= 1){ + return; + } + console.log( textSP.childNodes[0].textContent, spValue); 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; From 4a6a9d539eb353136188fc79d4b273e716e2da62 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 01:22:08 +0800 Subject: [PATCH 045/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f21153c7..66b7a6c4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.35 +// @version 2.90.22.36 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From 751e399d2c547b556e2a1b5f225f26fc2bd47bf6 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 01:28:18 +0800 Subject: [PATCH 046/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=88=9D=E6=AC=A1?= =?UTF-8?q?=E8=B7=B3=E8=BD=ACgr=E6=B2=A1=E6=9C=89=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E6=AC=A1=E6=95=B0=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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 66b7a6c4..aa378e1c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.36 +// @version 2.90.22.37 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2675,6 +2675,8 @@ try { if(window.location.href.includes(`?s=Battle&ss=gr`)){ gE('#grindfest>div>div>img').onclick(); } else { + arena.gr++; + setValue('arena', arena); const html = $ajax.open(`?s=Battle&ss=gr`); } } else { From 6b5e3f52d3436c410e4faf31adda66f70037577f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 01:30:09 +0800 Subject: [PATCH 047/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index aa378e1c..d6320970 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3791,9 +3791,8 @@ try { const textSP = gE('#vrs') ?? gE('#dvrs'); const spValue = textSP.childNodes[0].textContent * 1; if (spValue <= 1){ - return; + return false; } - console.log( textSP.childNodes[0].textContent, spValue); 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; From 61bfa9b7fc245bdd2ae31390d2b4e17ca9d63c0e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 04:43:57 +0800 Subject: [PATCH 048/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=AB=9E=E6=8A=80?= =?UTF-8?q?=E5=9C=BA=E6=B2=A1=E6=9C=89token=E6=97=B6=E7=9A=84=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=8F=8A=E9=98=9F=E5=88=97=E8=8E=B7=E5=8F=96=EF=BC=9B?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E4=B8=96=E7=95=8C=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E7=9A=84=E8=A3=85=E5=A4=87=E4=BF=AE=E7=90=86=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=EF=BC=88=E6=96=B0=E7=89=88=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=BF=AE=E7=90=86=E5=8A=9F=E8=83=BD=E6=9C=AA=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d6320970..f8909b5e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.37 +// @version 2.90.22.38 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -355,7 +355,8 @@ try { return; } gE('img[src*="startchallenge.png"]', 'all', document).forEach((btn) => { - const temp = btn.getAttribute('onclick').match(/init_battle\((\d+),\d+,'(.*?)'\)/); + const onclick = btn.getAttribute('onclick'); + const temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/) ?? onclick.match(/init_battle\((\d+),\d+\)/); if(ar.includes(temp[1])) { return; } @@ -2396,16 +2397,32 @@ try { return await asyncCheckRepair(); } 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); + var eqps; + if(!isIsekai){ + var doc = $doc(await $ajax.fetch('?s=Forge&ss=re')); + const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); + console.log(json); + 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); + } else { + doc = $doc(await $ajax.fetch('?s=Bazaar&ss=am&screen=repair&filter=equipped')); + + eqps = (await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { + const id = eqp.getAttribute('onmouseover').match(/hover_equip\((\d+)\)/)[1]; + const condition = 1 * gE('td:last-child', eqp).childNodes[0].textContent.replace('%', ''); + if (condition > g('option').repairValue) { + return; + } + // TODO repair + return id; + } catch (e) {console.error(e)}}))).filter(e => e); + } if (eqps.length) { console.log('eqps need repair: ', eqps); document.title = `[R!]` + document.title; @@ -2547,8 +2564,12 @@ try { } return; } - gE('img[src*="startchallenge.png"]', 'all', doc).forEach((_) => { - const temp = _.getAttribute('onclick').match(/init_battle\((\d+),\d+,'(.*?)'\)/); + gE('img[src*="startchallenge.png"]', 'all', doc).forEach((btn) => { + const onclick = btn.getAttribute('onclick'); + const temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/); + if(!temp){ + return; + } arena.token[temp[1]] = temp[2]; }); } catch (e) {console.error(e)}})); From 682da33ce45659e7780b54f7e09445e09aa6ba2e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 2 Nov 2025 17:14:29 +0800 Subject: [PATCH 049/216] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E4=B8=96?= =?UTF-8?q?=E7=95=8C=E6=96=B0=E7=89=88=E6=9C=AC=E4=B8=8B=E7=9A=84=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A3=85=E5=A4=87=E4=BF=AE=E7=90=86=E5=92=8C=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E7=AB=9E=E6=8A=80=E5=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 95 ++++++++++++++----- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f8909b5e..94bd04e4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.38 +// @version 2.90.22.39 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2401,7 +2401,6 @@ try { if(!isIsekai){ var doc = $doc(await $ajax.fetch('?s=Forge&ss=re')); const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); - console.log(json); 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]; @@ -2412,7 +2411,6 @@ try { } catch (e) {console.error(e)}}))).filter(e => e); } else { doc = $doc(await $ajax.fetch('?s=Bazaar&ss=am&screen=repair&filter=equipped')); - eqps = (await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { const id = eqp.getAttribute('onmouseover').match(/hover_equip\((\d+)\)/)[1]; const condition = 1 * gE('td:last-child', eqp).childNodes[0].textContent.replace('%', ''); @@ -2420,7 +2418,15 @@ try { return; } // TODO repair - return id; + var iframe = cE('iframe'); + iframe.style.cssText += "display:none" + iframe.src = `?s=Bazaar&ss=am&screen=repair&filter=equipped&eqids[]=${id}`; + document.body.appendChild(iframe); + await loadIframe(iframe); + if(gE('#equipsubmit', iframe.contentWindow.document.body).getAttribute('disabled')){ + return id; + } + gE('#equipform', iframe.contentWindow.document.body).submit(); } catch (e) {console.error(e)}}))).filter(e => e); } if (eqps.length) { @@ -2431,6 +2437,15 @@ try { return !eqps.length; } catch (e) {console.error(e)}; return false; } + function loadIframe(iframe) { + return new Promise((resolve, reject) => { + // 监听iframe的load事件 + iframe.onload = () => { + resolve("Iframe loaded successfully"); + }; + }); + } + function checkStamina(low, cost) { let stamina = getValue('stamina'); const lastTime = getValue('staminaTime'); @@ -2558,19 +2573,26 @@ try { await Promise.all(arena.sites.map(async site => { try { const doc = $doc(await $ajax.fetch(site)); if (site === '?s=Battle&ss=gr') { - const onclickInner = gE('img[src*="startgrindfest.png"]', doc).getAttribute('onclick').match(/init_battle\(1, '(.*?)'\)/); + const onclickInner = gE('img[src*="startgrindfest.png"]', doc).getAttribute('onclick').match(/init_battle\(1\)/); if(onclickInner){ - arena.token.gr = onclickInner[1]; + arena.token.gr = null; } return; } gE('img[src*="startchallenge.png"]', 'all', doc).forEach((btn) => { const onclick = btn.getAttribute('onclick'); - const temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/); - if(!temp){ + var temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/); + if(temp){ + arena.token[temp[1]] = temp[2]; + return; + } + temp = onclick.match(/init_battle\((\d+),\d+\)/); + if(temp){ + arena.token[temp[1]] = null; return; } - arena.token[temp[1]] = temp[2]; + temp = onclick.match(/init_battle\((\d+)\)/); + arena.token[temp[1]] = null; }); } catch (e) {console.error(e)}})); } @@ -2609,6 +2631,15 @@ try { } async function idleArena() { try { // 闲置竞技场 + function writeArenaStart(){ + document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); + if (key !== 'gr'){ + arena.arrayDone.push(key); + } else { + arena.gr--; + } + setValue('arena', arena); + } let arena = getValue('arena', true); console.log('arena:', getValue('arena', true)); if (arena.array.length === 0) { @@ -2685,23 +2716,39 @@ try { logSwitchAsyncTask(arguments); return; } - document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); - if (key !== 'gr'){ - arena.arrayDone.push(key); - } else { - arena.gr--; + if(token){ + writeArenaStart(); + $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); + logSwitchAsyncTask(arguments); + return; } - setValue('arena', arena); - if(!token && href === 'gr'){ - if(window.location.href.includes(`?s=Battle&ss=gr`)){ - gE('#grindfest>div>div>img').onclick(); - } else { - arena.gr++; - setValue('arena', arena); - const html = $ajax.open(`?s=Battle&ss=gr`); + // new version in isekai + var iframe = cE('iframe'); + iframe.src = `?s=Battle&ss=${href}`; + iframe.style.cssText += "display:none"; + document.body.appendChild(iframe); + await loadIframe(iframe); + var btns = gE(`#arena_list>tbody>tr>td>img`, 'all', iframe.contentWindow.document.body); + for(let btn of btns){ + const onclick = btn.getAttribute('onclick'); + if(!onclick){ + continue; } - } else { - $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); + var temp = onclick.match(/init_battle\((\d+),\d+\)/) ?? onclick.match(/init_battle\((\d+)\)/); + if(!temp || temp[1]*1 !== key){ + continue; + } + iframe.contentWindow.confirm = function(message) { // 自动点击进入 + return true; + }; + iframe.contentWindow.alert = function(message) { + return; + }; + writeArenaStart(); + btn.onclick(); + await loadIframe(iframe); + goto(); + return; } logSwitchAsyncTask(arguments); } catch (e) {console.error(e)}} From e4ceb4d0d95ff28b575f95707b5332ef6128da87 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 4 Nov 2025 03:31:28 +0800 Subject: [PATCH 050/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 94bd04e4..612e3e23 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.39 +// @version 2.90.23 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From dc6bcc2c7694a4a6a8e31cf34e348e6d8a6b4bc6 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 4 Nov 2025 16:04:20 +0800 Subject: [PATCH 051/216] 2.90.24 Adjust new version Isekai in-battle buffTurn acquire --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 612e3e23..d86c5d02 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.23 +// @version 2.90.24 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2017,7 +2017,11 @@ try { if (!buff) { return 0; } - buff = buff.getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; + var match = buff.getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/); + if(!match){ // new version for isekai 2025S2 + match = buff.getAttribute('onmouseover').match(/\(.*,.*,(.*?)\)$/); + } + buff = match[1] * 1; return isNaN(buff) ? Infinity : buff; }, }; From 1babbb6c1d69384479727f171c5d93ff38341908 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 4 Nov 2025 19:06:36 +0800 Subject: [PATCH 052/216] fix all buff turn acquire to adapt new version isekai --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d86c5d02..5f7dc7f7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.24 +// @version 2.90.25 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1982,6 +1982,14 @@ try { } } + function getBuffTurnFromImg(buff, nanValue=NaN) { + if (!buff) { + return 0; + } + buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; + return isNaN(buff) ? nanValue : buff; + } + function checkCondition(parms) { if (typeof parms === 'undefined') { return true; @@ -2013,16 +2021,7 @@ try { return isOn(id) ? 1 : 0; }, buffTurn(img) { - let buff = gE(`#pane_effects>img[src*="${img}"]`); - if (!buff) { - return 0; - } - var match = buff.getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/); - if(!match){ // new version for isekai 2025S2 - match = buff.getAttribute('onmouseover').match(/\(.*,.*,(.*?)\)$/); - } - buff = match[1] * 1; - return isNaN(buff) ? Infinity : buff; + return getBuffTurnFromImg(gE(`#pane_effects>img[src*="${img}"]`), Infinity); }, }; @@ -3700,7 +3699,7 @@ try { }; for (i = 0; i < buff.length; i++) { const spellName = buff[i].getAttribute('onmouseover').match(/'(.*?)'/)[1]; - const buffLastTime = buff[i].getAttribute('onmouseover').match(/\(.*,.*, (.*?)\)$/)[1] * 1; + const buffLastTime = getBuffTurnFromImg(buff[i]); if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { continue; } else { @@ -4102,7 +4101,7 @@ try { // 已有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])) { + if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { gE(skillLib[buff].id).click(); gE(`#mkey_${id}`).click(); return true; From 45547454799f9e707bc5787209f5ee4b3dc96dc8 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 5 Nov 2025 21:36:39 +0800 Subject: [PATCH 053/216] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=BC=82=E4=B8=96=E7=95=8C=E6=88=98=E6=96=97=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=95=B0=E6=8D=AE=E6=94=B6=E9=9B=86=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E4=BC=A4=E5=AE=B3=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5f7dc7f7..ec4bded1 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.25 +// @version 2.90.26 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4428,8 +4428,8 @@ try { if (debug) { console.log(text); } - if (text.match(/you for \d+ \w+ damage/)) { - reg = text.match(/you for (\d+) (\w+) damage/); + if (text.match(/you for \d+ \w+ damage/) || text.match(/You take \d+ \w+ damage/)) { + reg = text.match(/you for (\d+) (\w+) damage/) ?? text.match(/You take (\d+) (\w+) damage/); magic = reg[2].replace('ing', ''); point = reg[1] * 1; stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; @@ -4472,7 +4472,8 @@ try { } 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', ''); + magic = parm.log[i - 1].textContent.match(/you for (\d+) (\w+) damage/) ?? parm.log[i - 1].textContent.match(/You take (\d+) (\w+) damage/); + magic = magic[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]}`; From cab64a72b9e78765cd9ea5e1f5bbfee4f9ab40c0 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 5 Nov 2025 21:53:51 +0800 Subject: [PATCH 054/216] Update damage matching regex for better accuracy --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ec4bded1..b4358992 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4428,8 +4428,8 @@ try { if (debug) { console.log(text); } - if (text.match(/you for \d+ \w+ damage/) || text.match(/You take \d+ \w+ damage/)) { - reg = text.match(/you for (\d+) (\w+) damage/) ?? text.match(/You take (\d+) (\w+) damage/); + if (text.match(/you for \d+ \w+ damage/) || text.match(/(You|and) take \d+ \w+ damage/)) { + reg = text.match(/you for (\d+) (\w+) damage/) ?? text.match(/(You|and) take (\d+) (\w+) damage/); magic = reg[2].replace('ing', ''); point = reg[1] * 1; stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; @@ -4445,6 +4445,9 @@ try { stats.hurt._mtotal += point; stats.hurt._mavg = Math.round(stats.hurt._mtotal / stats.hurt._mcount); } + if (text.match(/You ((partially )*(evade|parry|block)( and )*)+ the attack/)){ + stats.self.evade++; + } } 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]; @@ -4472,7 +4475,7 @@ try { } 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/) ?? parm.log[i - 1].textContent.match(/You take (\d+) (\w+) damage/); + magic = parm.log[i - 1].textContent.match(/you for (\d+) (\w+) damage/) ?? parm.log[i - 1].textContent.match(/(You|and) take (\d+) (\w+) damage/); magic = magic[2].replace('ing', ''); stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; point = reg[3] * 1; From 7f2feb0a9dde2e95a56e9e72cc1ff3a598af50a3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 6 Nov 2025 15:35:53 +0800 Subject: [PATCH 055/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E6=A0=8F=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b4358992..c8df662c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.26 +// @version 2.90.27 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1308,9 +1308,10 @@ try { } g('customizeTarget', target); const position = target.getBoundingClientRect(); + const bodyPosition = document.body.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('.customizeBox').style.top = `${position.bottom - bodyPosition.top}px`; + gE('.customizeBox').style.left = `${position.left - bodyPosition.left}px`; }; // 标签页-主要选项 gE('input[name="pauseHotkeyStr"]', optionBox).onkeyup = function (e) { From 240a0af28c24d0d42fe642e80895a24c541fb1aa Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 6 Nov 2025 16:47:46 +0800 Subject: [PATCH 056/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=9D=83=E9=87=8D=E7=9B=B8=E5=85=B3=E5=A4=8D=E9=80=89=E6=A1=86?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c8df662c..bde8dbc0 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1087,9 +1087,9 @@ try { ' ', '
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%)`
', + '
显示权重及顺序顯示權重及順序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. ', From b3c0b72a3ae72337f74c9326004cff054ac3c467 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 6 Nov 2025 19:52:35 +0800 Subject: [PATCH 057/216] =?UTF-8?q?2.90.28=20=E8=A1=A5=E5=85=85=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=BC=A4=E5=AE=B3=E6=97=A5=E5=BF=97=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index bde8dbc0..ce468df9 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.27 +// @version 2.90.28 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4429,8 +4429,7 @@ try { if (debug) { console.log(text); } - if (text.match(/you for \d+ \w+ damage/) || text.match(/(You|and) take \d+ \w+ damage/)) { - reg = text.match(/you for (\d+) (\w+) damage/) ?? text.match(/(You|and) take (\d+) (\w+) damage/); + if (reg = matchDamageInfoFromLogText(text)) { magic = reg[2].replace('ing', ''); point = reg[1] * 1; stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; @@ -4476,8 +4475,7 @@ try { } 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/) ?? parm.log[i - 1].textContent.match(/(You|and) take (\d+) (\w+) damage/); - magic = magic[2].replace('ing', ''); + magic = matchDamageInfoFromLogText(parm.log[i - 1], false)[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]}`; @@ -4503,6 +4501,25 @@ try { setValue('stats', stats); } + function matchDamageInfoFromLogText(text, isSkipUnmatched=true){ + const regList = [ + /you for (\d+) (\w+) damage/, + /and take (\d+) (\w+) damage/, + /You take (\d+) (\w+) damage/, + /hits you, causing (\d+) points of (\w+) damage/ + ]; + for (let reg of regList){ + let match = text.match(reg); + if (!match) { + continue; + } + return match; + } + if(!isSkipUnmatched){ + console.log(`Can't match damage info from: `, text); + } + } + function recordUsage2() { const stats = getValue('stats', true); stats.self._monster += g('monsterAll'); From 2c88af09c789e9edf470c8e7ce219790348cb9b0 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 6 Nov 2025 20:06:18 +0800 Subject: [PATCH 058/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=88=98=E6=96=97?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E8=80=90=E5=8A=9B=E8=AE=BE=E7=BD=AEUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ce468df9..99a9632b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -868,16 +868,16 @@ try { ' ', ' ', '
', - '
', - '
精力精力Stamina: 阈值閾值 threshold: Min(85, );
', - '
含本日自然恢复的阈值含本日自然恢復的閾值Stamina threshold with naturally recovers today.: ;
', - '
', - '
进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', - '
进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
', + '
', + ' [S!]精力精力Stamina: 阈值閾值 threshold: Min(85, )
', + ' 进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', + ' 进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
', + ' [S!!]含本日自然恢复的阈值含本日自然恢復的閾值Stamina threshold with naturally recovers today:
', + '
', - '
: ', + '
: ', ' 耐久度耐久度Durability%
', - '
检查物品库存檢查物品庫存Check is item needs supply: ', + '
[C!]检查物品库存檢查物品庫存Check is item needs supply: ', '
', ' 体力药水體力藥水Health Potion', ' 体力长效药體力長效藥Health Draught', From 1d1daabfd29ec938818cd5e7fea4a636ea06bd39 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 6 Nov 2025 23:14:12 +0800 Subject: [PATCH 059/216] =?UTF-8?q?2.90.29=20=E4=BF=AE=E6=AD=A3=E8=80=90?= =?UTF-8?q?=E5=8A=9B=E7=9B=B8=E5=85=B3=E6=A3=80=E6=B5=8B=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E5=8F=8A=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 99a9632b..3e24f75b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.28 +// @version 2.90.29 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -869,10 +869,11 @@ try { ' ', '
', '
', - ' [S!]精力精力Stamina: 阈值閾值 threshold: Min(85, )
', + ' [S!]精力精力Stamina: ', ' 进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', + ' 竞技场/浴血擂台阈值競技場/浴血擂台閾值Minimum stamina to auto start The Arena or Ring Of Blood: Min(85, )
', ' 进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
', - ' [S!!]含本日自然恢复的阈值含本日自然恢復的閾值Stamina threshold with naturally recovers today:
', + ' [S!!]进入竞技场/浴血擂台/压榨届时,含本日自然恢复的阈值进入競技場/浴血擂台/壓榨屆时,含本日自然恢復的閾值Stamina threshold with naturally recovers today for The Arena, Ring Of Bloog, GrindFest:
', '
', '
: ', @@ -2626,11 +2627,11 @@ try { if(staminaChecked === 1){ // succeed return true; } - if(staminaChecked === 0){ // failed until today ends + if(staminaChecked === 0){ // failed currently setTimeout(method, Math.floor(time(0) / _1h + 1) * _1h - time(0)); - document.title = `[S!!]` + document.title; - } else { // case -1: // failed with nature recover document.title = `[S!]` + document.title; + } else { // case -1: // failed with nature recover + document.title = `[S!!]` + document.title; } } From 345a0de14aca11dcc995a10f25db498efc79fb53 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 00:08:43 +0800 Subject: [PATCH 060/216] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=BA=BA=E7=89=A9?= =?UTF-8?q?=E5=8F=8A=E6=80=AA=E7=89=A9=E7=8A=B6=E6=80=81=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=EF=BC=8C=E6=88=98=E6=96=97=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=BC=A4=E5=AE=B3=E6=9D=A1=E7=9B=AE=E8=AF=BB=E5=8F=96=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 126 ++++++++++-------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3e24f75b..c3f70eb4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.29 +// @version 2.90.30 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -44,6 +44,14 @@ const _1m = 60 * _1s; const _1h = 60 * _1m; const _1d = 24 * _1h; +const monsterStateKeys = { + obj: `div.btm1`, + lv: `div.btm2`, + name: `div.btm3`, + bars: `div.btm4>div.btm5`, + buffs: `div.btm6`, +} + try { const isFrame = window.self !== window.top; if (isFrame) { @@ -523,6 +531,33 @@ try { return document.createElement(name); } + function getBuffTurnFromImg(buff, nanValue=NaN) { + if (!buff) { + return 0; + } + buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; + return isNaN(buff) ? nanValue : buff; + } + + function getMonsterID(s) { + if (s.order !== undefined) { + return (s.order + 1) % 10; + } // case is monsterStatus + return (s + 1) % 10; // case is order + } + + function getPlayerBuff(buff){ + return gE(`#pane_effects>img[src*="${buff}"]`); + } + + function getMonster(id){ + return gE(`#mkey_${id}`); + } + + function getMonsterBuff(id, buff){ + return gE(`${monsterStateKeys.buffs}>img[src*="${buff}"]`, getMonster(id)); + } + function isOn(id) { // 是否可以施放技能/使用物品 if (id * 1 > 10000) { // 使用物品 return gE(`.bti3>div[onmouseover*="(${id})"]`); @@ -744,8 +779,8 @@ try { '.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;}', + // `${monsterStateKeys.lv}>div:nth-child(1):before{font-size:23px;font-weight:bold;text-shadow:1px 1px 2px;content:counter(order);counter-increment:order;}`, + // `${monsterStateKeys.lv}>div:nth-child(1)>img{display:none;}`, ].join(''); globalStyle.textContent = cssContent; optionButton(lang); @@ -1984,14 +2019,6 @@ try { } } - function getBuffTurnFromImg(buff, nanValue=NaN) { - if (!buff) { - return 0; - } - buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; - return isNaN(buff) ? nanValue : buff; - } - function checkCondition(parms) { if (typeof parms === 'undefined') { return true; @@ -2023,7 +2050,7 @@ try { return isOn(id) ? 1 : 0; }, buffTurn(img) { - return getBuffTurnFromImg(gE(`#pane_effects>img[src*="${img}"]`), Infinity); + return getBuffTurnFromImg(getPlayerBuff(img), Infinity); }, }; @@ -2881,7 +2908,7 @@ try { } const type = battle.roundType; let subtype, title; - const monsterNames = Array.from(gE('div.btm3>div>div', 'all')).map(monster => monster.innerHTML); + const monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerHTML); const lang = g('lang') * 1; const info = battleInfoList[type]; switch (type) { @@ -2979,13 +3006,6 @@ try { } } - function getMonsterID(s) { - if (s.order !== undefined) { - return (s.order + 1) % 10; - } // case is monsterStatus - return (s + 1) % 10; // case is order - } - /** * 按照技能范围,获取包含原目标且范围内最终权重(finweight)之和最低的范围的中心目标 * @param {int} id id from g('battle').monsterStatus.sort(objArrSort('finWeight')); @@ -3122,7 +3142,7 @@ try { 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; + const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[style*="background"]`, 'all').length; g('bossAlive', g('bossAll') - bossDead); const battleLog = gE('#textlog>tbody>tr>td', 'all'); if (g('option').recordUsage) { @@ -3251,11 +3271,11 @@ try { if (window.location.hash !== '') { goto(); } - g('monsterAll', gE('div.btm1', 'all').length); + g('monsterAll', gE(monsterStateKeys.obj, 'all').length); const monsterDead = gE('img[src*="nbardead"]', 'all').length; g('monsterAlive', g('monsterAll') - monsterDead); - g('bossAll', gE('div.btm2[style^="background"]', 'all').length); - const bossDead = gE('div.btm1[style*="opacity"] div.btm2[style*="background"]', 'all').length; + g('bossAll', gE(`${monsterStateKeys.lv}[style^="background"]`, 'all').length); + const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[style*="background"]`, 'all').length; g('bossAlive', g('bossAll') - bossDead); const battleLog = gE('#textlog>tbody>tr>td', 'all'); if (!battle.roundType) { @@ -3318,8 +3338,8 @@ try { 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 monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); + const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>div>div`, 'all')).map(monster => monster.innerText); const monsterDB = getValue('monsterDB', true) ?? {}; const monsterMID = getValue('monsterMID', true) ?? {}; const oldDB = JSON.stringify(monsterDB); @@ -3369,7 +3389,7 @@ try { battle.roundNow = 1; battle.roundAll = 1; } - } else if (!battle.monsterStatus || battle.monsterStatus.length !== gE('div.btm2', 'all').length) { + } else if (!battle.monsterStatus || battle.monsterStatus.length !== gE(monsterStateKeys.lv, 'all').length) { battle.roundNow = 1; battle.roundAll = 1; } @@ -3406,7 +3426,7 @@ try { function countMonsterHP() { // 统计敌人血量 let i, j; - const monsterHp = gE('div.btm4>div.btm5:nth-child(1)', 'all'); + const monsterHp = gE(`${monsterStateKeys.bars}:nth-child(1)`, 'all'); let battle = getValue('battle', true); const monsterStatus = battle.monsterStatus; const hpArray = []; @@ -3476,7 +3496,7 @@ try { img: 'wpn_bleed', }, }; - const monsterBuff = gE('div.btm6', 'all'); + const monsterBuff = gE(monsterStateKeys.buffs, 'all'); const hpMin = Math.min.apply(null, hpArray); const yggdrasilExtraWeight = g('option').YggdrasilExtraWeight; const unreachableWeight = g('option').unreachableWeight; @@ -3489,7 +3509,7 @@ try { } let weight = baseHpRatio * Math.log10(monsterStatus[i].hpNow / hpMin); // > 0 生命越低权重越低优先级越高 monsterStatus[i].hpWeight = weight; - const name = gE('div.btm3>div>div', monsterBuff[i].parentNode).innerText; + const name = gE(`${monsterStateKeys.name}>div>div`, monsterBuff[i].parentNode).innerText; if (yggdrasilExtraWeight && ('Yggdrasil' === name || '世界树 Yggdrasil' === name)) { // 默认设置下,任何情况都优先击杀群体大量回血的boss"Yggdrasil" weight += yggdrasilExtraWeight; // yggdrasilExtraWeight.defalut -1000 } @@ -3599,7 +3619,7 @@ try { continue; } for (let j = 1; j <= scrollLib[i].mult; j++) { - if (gE(`#pane_effects>img[src*="${scrollLib[i][`img${j}`]}${scrollFirst}"]`)) { + if (getPlayerBuff(scrollLib[i][`img${j}`]+scrollFirst)) { continue; } gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`).click(); @@ -3616,7 +3636,7 @@ try { if (!g('option').channelSkill) { return false; } - if (!gE('#pane_effects>img[src*="channeling"]')) { + if (!getPlayerBuff('channeling')) { return false; } const skillLib = { @@ -3672,7 +3692,7 @@ try { 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)) { + if (g('option').channelSkill[j] && !getPlayerBuff(skillLib[j].img) && isOn(skillLib[j].id)) { gE(skillLib[j].id).click(); return true; } @@ -3705,7 +3725,7 @@ try { 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')) { + if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('sparklife') && isOn('422')) { gE('422').click(); return true; } if (spellName in name2Skill && isOn(skillLib[name2Skill[spellName]].id)) { @@ -3779,7 +3799,7 @@ try { 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)) { + if (g('option').buffSkill[buff] && checkCondition(g('option')[`buffSkill${buff}Condition`]) && !getPlayerBuff(skillLib[buff].img) && isOn(skillLib[buff].id)) { gE(skillLib[buff].id).click(); return true; } @@ -3807,7 +3827,7 @@ try { }, }; 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})"]`)) { + if (!getPlayerBuff(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; } @@ -3845,7 +3865,7 @@ try { id: 12601, img: 'darkinfusion', }]; - if (gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`) && !gE(`#pane_effects>img[src*="${infusionLib[[g('attackStatus')]].img}"]`)) { + if (gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`) && !getPlayerBuff(infusionLib[[g('attackStatus')]].img)) { gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`).click(); return true; } @@ -3933,7 +3953,7 @@ try { continue; } const range = id in rangeSkills ? rangeSkills[id] : 0; - gE(`#mkey_${getRangeCenter(target, range).id}`).click(); + getMonster(getRangeCenter(target, range).id).click(); return true; } } @@ -3951,7 +3971,7 @@ try { if (monsterStatus[j].hpNow / monsterStatus[j].hp >= 0.25) { continue; } - if (!gE(`#mkey_${getMonsterID(monsterStatus[j])} img[src*="wpn_bleed"]`)) { + if (!getMonsterBuff(getMonsterID(monsterStatus[j]), 'bleed')) { continue; } return monsterStatus[j]; @@ -4069,7 +4089,7 @@ try { } // 获取目标 - let isDebuffed = (target) => gE(`img[src*="${skillLib[buff].img}"]`, gE(`#mkey_${getMonsterID(target)}>.btm6`)); + let isDebuffed = (target) => getMonsterBuff(getMonsterID(target), skillLib[buff].img); let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; let monsterStatus = g('battle').monsterStatus; if (debuffByIndex){ @@ -4099,13 +4119,13 @@ try { return false; } - const imgs = gE('img', 'all', gE(`#mkey_${id}>.btm6`)); + const imgs = gE('img', 'all', gE(monsterStateKeys.buffs, getMonster(id))); // 已有buff小于6个 // 未开启debuff失败警告 // buff剩余持续时间大于等于警报时间 if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { gE(skillLib[buff].id).click(); - gE(`#mkey_${id}`).click(); + getMonster(id).click(); return true; } @@ -4153,7 +4173,6 @@ try { 4502: { 152: [0, 2, 3] }, 4503: { 153: [0, 3, 4, 4] }, } - let range = 0; // Spell > Offensive Magic const attackStatus = g('attackStatus'); @@ -4163,7 +4182,7 @@ try { range = 1; } } 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)) { + if (g('option').etherTap && getMonsterBuff(getMonsterID(monsterStatus[0]), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) && checkCondition(g('option').etherTapCondition)) { `pass` } else { @@ -4188,7 +4207,7 @@ try { } } } - gE(`#mkey_${getRangeCenter(monsterStatus[0], range, !attackStatus).id}`).click(); + getMonster(getRangeCenter(monsterStatus[0], range, !attackStatus).id).click(); return true; } @@ -4201,10 +4220,10 @@ try { 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 monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); + const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>div>div`, 'all')).map(monster => monster.innerText); const monsterDB = getValue('monsterDB', true); - gE('div.btm2', 'all').forEach((monster, order) => { + gE(monsterStateKeys.lv, 'all').forEach((monster, order) => { monsterStatus.push({ order: order, hp: getHPFromMonsterDB(monsterDB, monsterNames[order], monsterLvs[order]) ?? ((monster.style.background === '') ? 1000 : 100000), @@ -4240,7 +4259,7 @@ try { status.forEach(s => { const rank = weights.indexOf(s.finWeight); const id = getMonsterID(s); - if (!gE(`#mkey_${id}`) || !gE(`#mkey_${id}>.btm3`)) { + if (!getMonster(id) || !gE(monsterStateKeys.name, getMonster(id))) { return; } if (g('option').displayWeightBackground) { @@ -4258,12 +4277,12 @@ try { } catch { } - gE(`#mkey_${id}`).style.cssText += `background: ${colorText};`; + getMonster(id).style.cssText += `background: ${colorText};`; } } - gE(`#mkey_${id}>.btm3`).style.cssText += 'display: flex; flex-direction: row;' + gE(monsterStateKeys.name, getMonster(id)).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)}]
`; + gE(monsterStateKeys.name, getMonster(id)).innerHTML += `
[${rank}|-${-rank + weights.length - 1}|${s.finWeight.toPrecision(s.finWeight >= 1 ? 5 : 4)}]
`; } }); } @@ -4503,6 +4522,9 @@ try { } function matchDamageInfoFromLogText(text, isSkipUnmatched=true){ + if(!text){ + return undefined; + } const regList = [ /you for (\d+) (\w+) damage/, /and take (\d+) (\w+) damage/, From a09b29c6a3815112af7e156c05f61f35c8d5c53a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 00:20:15 +0800 Subject: [PATCH 061/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c3f70eb4..44d9caa1 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4495,7 +4495,7 @@ try { } 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 = matchDamageInfoFromLogText(parm.log[i - 1], false)[2].replace('ing', ''); + magic = matchDamageInfoFromLogText(parm.log[i - 1].textContent, false)[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]}`; @@ -4522,9 +4522,6 @@ try { } function matchDamageInfoFromLogText(text, isSkipUnmatched=true){ - if(!text){ - return undefined; - } const regList = [ /you for (\d+) (\w+) damage/, /and take (\d+) (\w+) damage/, From 2cb0ebc849748ba7271122cd21dffa09b4c7da14 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:10:26 +0800 Subject: [PATCH 062/216] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=80=AA=E7=89=A9=E7=8A=B6=E6=80=81=EF=BC=88?= =?UTF-8?q?buff=E6=8C=81=E7=BB=AD=E6=97=B6=E9=97=B4=E3=80=81HP%=E3=80=81MP?= =?UTF-8?q?%=E3=80=81SP%=EF=BC=89=EF=BC=8C=E5=8E=9F=E6=9C=89=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E7=9A=84=E6=85=88=E6=82=B2=E7=9A=84=E9=99=90?= =?UTF-8?q?=E5=AE=9A=E6=9D=A1=E4=BB=B6=E5=B0=86=E8=87=AA=E5=8A=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=B8=BA=E5=AF=B9=E5=BA=94=E7=9A=84=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 199 ++++++++++-------- 1 file changed, 112 insertions(+), 87 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 44d9caa1..ac8e9e7d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.30 +// @version 2.90.31 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -396,6 +396,32 @@ try { option[itemArray[0]][itemArray[1]] ??= option[aliasDict[key]]; } } + // 迁移旧版本最后的慈悲条件为可配置条件 + const mercifulBlowCondition = option.skillT3Condition ?? {"0":[]}; + const size = Object.keys(mercifulBlowCondition).length; + if (option.mercifulBlowStrict){ + option.mercifulBlow = false; + option.mercifulBlowStrict = false; + for(let id in mercifulBlowCondition){ + const condition = mercifulBlowCondition[id]; + condition.push("fightingStyle,5,2"); + condition.push("targetHp,2,0.25"); + condition.push("_targetBuffTurn_bleed,1,0"); + } + } else if(option.mercifulBlow) { + option.mercifulBlow = false; + const newCondition = {}; + for(let id in mercifulBlowCondition){ + const condition = mercifulBlowCondition[id]; + newCondition[id] = condition; + newCondition[(id*1+size).toString()] = [...condition]; + newCondition[(id*1+size).toString()].push("fightingStyle,6,2"); + condition.push("fightingStyle,5,2"); + condition.push("targetHp,2,0.25"); + condition.push("_targetBuffTurn_bleed,1,0"); + } + option.skillT3Condition = newCondition; + } if(isFrame){ g('option', option); } else{ @@ -1078,7 +1104,7 @@ try { '
', '
: {{skillOFCCondition}}
', '
: {{skillFRDCondition}}
', - '
:
', + '
:
{{skillT3Condition}}
', '
: {{skillT2Condition}}
', '
: {{skillT1Condition}}
', @@ -1798,6 +1824,11 @@ try { '', '', '', + '', + '', + '', + '', + '', '', ].join(''); customizeBox.innerHTML = [ @@ -2019,12 +2050,12 @@ try { } } - function checkCondition(parms) { + function checkCondition(parms, targets=undefined) { if (typeof parms === 'undefined') { - return true; + return g('battle').monsterStatus[0]; } - let i; let j; let - k; + let i; let j; let k; + let target; const returnValue = function (str) { if (str.match(/^_/)) { const arr = str.split('_'); @@ -2050,59 +2081,74 @@ try { return isOn(id) ? 1 : 0; }, buffTurn(img) { - return getBuffTurnFromImg(getPlayerBuff(img), Infinity); + return getBuffTurnFromImg(getPlayerBuff(img), 0); + }, + targetBuffTurn(img){ + return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), 'bleed'), 0); + }, + targetHp(){ + return target.hpNow/target.hp; + }, + targetMp(){ + return target.mpNow; + }, + targetSp(){ + return target.spNow; }, }; + targets ??= [g('battle').monsterStatus[0]]; for (i in parms) { - let parmResult = true; - for (j = 0; j < parms[i].length; j++) { - let result = true; - 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]); + for (target of targets){ + let parmResult = true; + for (j = 0; j < parms[i].length; j++) { + let result = true; + 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]); - } + 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 = k[0] > k[2]; - break; - case '2': - result = k[0] < k[2]; - break; - case '3': - result = k[0] >= k[2]; - break; - case '4': - result = k[0] <= k[2]; - break; - case '5': - result = k[0] === k[2]; - break; - case '6': - result = k[0] !== k[2]; + switch (k[1]) { + case '1': + result = k[0] > k[2]; + break; + case '2': + result = k[0] < k[2]; + break; + case '3': + result = k[0] >= k[2]; + break; + case '4': + result = k[0] <= k[2]; + break; + case '5': + result = k[0] === k[2]; + break; + case '6': + result = k[0] !== k[2]; + break; + } + if (!result) { + parmResult = false; break; + } } - if (!result) { - parmResult = false; - break; + if (parmResult){ + return target; } } - if (parmResult) { - return true; - } } - return false; + return undefined; } // 答题// @@ -3427,6 +3473,8 @@ try { function countMonsterHP() { // 统计敌人血量 let i, j; const monsterHp = gE(`${monsterStateKeys.bars}:nth-child(1)`, 'all'); + const monsterMp = gE(`${monsterStateKeys.bars}:nth-child(2)`, 'all'); + const monsterSp = gE(`${monsterStateKeys.bars}:nth-child(3)`, 'all'); let battle = getValue('battle', true); const monsterStatus = battle.monsterStatus; const hpArray = []; @@ -3436,7 +3484,9 @@ try { 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); + monsterStatus[i].hpNow = Math.floor(monsterStatus[i].hp * parseFloat(gE('img:first-child', monsterHp[i]).style.width) / 120 + 1); + monsterStatus[i].mpNow = parseFloat(gE('img:first-child', monsterMp[i]).style.width) / 120; + monsterStatus[i].spNow = parseFloat(gE('img:first-child', monsterSp[i]).style.width) / 120; hpArray.push(monsterStatus[i].hpNow); } } @@ -3933,9 +3983,6 @@ try { if(!skill){ return; } - if (!checkCondition(g('option')[`skill${skill}Condition`])) { - continue; - } let id = skillLib[skill]; if (!isOn(id)) { continue; @@ -3948,7 +3995,7 @@ try { } g('skillOTOS')[skill]++; gE(id).click(); - let target = getWeaponSkillTarget(id); + let target = checkCondition(g('option')[`skill${skill}Condition`], g('battle').monsterStatus); if(!target){ continue; } @@ -3958,31 +4005,6 @@ try { } } - function getWeaponSkillTarget(id){ - let target = undefined; - const monsterStatus = g('battle').monsterStatus; - if (id !== 2203) { - return monsterStatus[0]; - } - // Merciful Blow - if(g('option').mercifulBlow || g('option').mercifulBlowStrict){ - // get target with conditions (hp < 0.25 and bleeding) - for (let j = 0; j < monsterStatus.length; j++) { - if (monsterStatus[j].hpNow / monsterStatus[j].hp >= 0.25) { - continue; - } - if (!getMonsterBuff(getMonsterID(monsterStatus[j]), 'bleed')) { - continue; - } - return monsterStatus[j]; - } - } - if(!g('option').mercifulBlowStrict){ - return monsterStatus[0]; - } - return undefined; - } - function useDeSkill() { // 自动施法DEBUFF技能 if (!g('option').debuffSkillSwitch) { // 总开关是否开启 return false; @@ -3991,7 +4013,7 @@ try { let skillPack = ['We', 'Im']; for (let i = 0; i < skillPack.length; i++) { if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 - if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`])) { // 检查条件 + if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`], g('battle').monsterStatus)) { // 检查条件 continue; } } @@ -4006,7 +4028,7 @@ try { for (let i in skillPack) { let buff = skillPack[i]; if (i >= toAllCount) { // 非先全体 - if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`])) { // 检查条件 + if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`], g('battle').monsterStatus)) { // 检查条件 continue; } } @@ -4102,7 +4124,8 @@ try { let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; - if (target.isDead || isDebuffed(target)) { + target = checkCondition(g('option')[`debuffSkill${buff}Condition`], [target]); + if (!target || target.isDead || isDebuffed(target)) { continue; } const center = getRangeCenter(target, range, false, isDebuffed, debuffByIndex); @@ -4176,21 +4199,23 @@ try { let range = 0; // Spell > Offensive Magic const attackStatus = g('attackStatus'); - const monsterStatus = g('battle').monsterStatus; + let target = g('battle').monsterStatus[0]; if (attackStatus === 0) { if (g('fightingStyle') === '1') { // 二天一流 range = 1; } } else { - if (g('option').etherTap && getMonsterBuff(getMonsterID(monsterStatus[0]), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) && checkCondition(g('option').etherTapCondition)) { + if (g('option').etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) && checkCondition(g('option').etherTapCondition)) { `pass` - } - else { + } 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; + target = checkCondition(condition, g('battle').monsterStatus); + if (target && isOn(id)){ + return id; + } } })(); gE(skill)?.click(); @@ -4207,7 +4232,7 @@ try { } } } - getMonster(getRangeCenter(monsterStatus[0], range, !attackStatus).id).click(); + getMonster(getRangeCenter(target, range, !attackStatus).id).click(); return true; } From 3d17497acc7e8420ad774df21bdfc25888d4a7e3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:27:27 +0800 Subject: [PATCH 063/216] =?UTF-8?q?=E6=9B=B4=E6=96=B02.90.31=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index df72b5e5..a6580878 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -88,7 +88,12 @@ **示例**: Protection的img为protection,则`_buffTurn_protection,5,0`表示不存在Protection的buff,`_buffTurn_protection,3,10`表示Protection的buff至少剩余10回合 -9. 空白(blank): 自己输入 (the value you want to put in) +9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照`targetBuffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 + 1. 默认情况的target均为权重优先级最高的目标 + 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff + ![示例](https://github.com/user-attachments/assets/6171d4a5-53d4-4af4-908e-c8182b9ded41) + +10. 空白(blank): 自己输入 (the value you want to put in) #### 示例 @@ -382,3 +387,4 @@ 灵感来自hoverplay,刚开始接触js,初步完成代码 功能有:答题警报、其他警报、快捷键、自动前进、自动使用宝石、自动回复、自动使用增益技能、自动打怪 很可惜,玩游戏不走心,一直搞不懂HVSTAT是怎么知道每个怪的血量的,直到[版本2.0](#20) + From 3a629d9e78549a2c4904b7d5153892459ce4c32a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:36:29 +0800 Subject: [PATCH 064/216] Update README with installation notice and content --- HentaiVerse/hvAutoAttack/README_en.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README_en.md b/HentaiVerse/hvAutoAttack/README_en.md index c44fef8f..fa416b60 100644 --- a/HentaiVerse/hvAutoAttack/README_en.md +++ b/HentaiVerse/hvAutoAttack/README_en.md @@ -82,9 +82,15 @@ Four drop down lists and one button are visible in the box 8. `buffTurn`: time the buff last in person, format`_buffTurn_img` - **example**: the image of Protection is protection, `_buffTurn_protection,5,0` means you don't have the buff of Protection or `_buffTurn_protection,3,10` means the the buff of Protection on you last at least 10 turns + **example**: the image of Protection is protection, `_buffTurn_protection,5,0` means you don't have the buff of Protection or `_buffTurn_protection,3,10` means the buff of Protection on you last at least 10 turns -9. blank: the value you want to put in +9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: + 1. The highest priority monster by rank in default situations. + 2. Weapon skills (OFC, T1~T3, etc.), Offensive Spell skills (Tire2, Tire3): by each condition > for each ranked target > find the target fit all sub-condition in the condition and cast to it. Such as the pic below: condition for Merciful Blow: only cast to targets which with hp below 25% and a bleed buff. + + ![example](https://github.com/user-attachments/assets/da181eac-e634-41ad-97a7-ff59a7b28b6d) + +10. blank: the value you want to put in #### Example @@ -188,3 +194,4 @@ In this example, the script will attack enemy 1 next. * Old 1. see [README_Chinese#更新历史](https://github.com/dodying/UserJs/blob/master/HentaiVerse/hvAutoAttack/README.md#更新历史) + From 5d98708ee6163ed5cc5d12f75b22394f5856dcbe Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:37:33 +0800 Subject: [PATCH 065/216] Update README.md --- HentaiVerse/hvAutoAttack/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index a6580878..e59f7e77 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -91,7 +91,8 @@ 9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照`targetBuffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 1. 默认情况的target均为权重优先级最高的目标 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff - ![示例](https://github.com/user-attachments/assets/6171d4a5-53d4-4af4-908e-c8182b9ded41) + + ![示例](https://github.com/user-attachments/assets/b4d0c57d-fdb1-464b-88d6-107643809339) 10. 空白(blank): 自己输入 (the value you want to put in) @@ -388,3 +389,4 @@ 功能有:答题警报、其他警报、快捷键、自动前进、自动使用宝石、自动回复、自动使用增益技能、自动打怪 很可惜,玩游戏不走心,一直搞不懂HVSTAT是怎么知道每个怪的血量的,直到[版本2.0](#20) + From 72c279e0f9c9a67dd4db3a8aacd18321b9f64fd7 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:38:59 +0800 Subject: [PATCH 066/216] Update README_en.md From 327608a3f1b954b441eae37537b7d7c2c617bea6 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:44:15 +0800 Subject: [PATCH 067/216] Update README.md --- HentaiVerse/hvAutoAttack/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index e59f7e77..70a8eadb 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -88,7 +88,7 @@ **示例**: Protection的img为protection,则`_buffTurn_protection,5,0`表示不存在Protection的buff,`_buffTurn_protection,3,10`表示Protection的buff至少剩余10回合 -9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照`targetBuffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 +9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 1. 默认情况的target均为权重优先级最高的目标 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff @@ -390,3 +390,4 @@ 很可惜,玩游戏不走心,一直搞不懂HVSTAT是怎么知道每个怪的血量的,直到[版本2.0](#20) + From e04ac63a196b5a4a897fda587b9c5c27ad809f0c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 02:54:58 +0800 Subject: [PATCH 068/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ac8e9e7d..24ca28f6 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -769,6 +769,7 @@ try { '.hvAACenter{text-align:center;}', '.hvAATitle{font-weight:bolder;}', '.hvAAGoto{cursor:pointer;text-decoration:underline;}', + '.customizeInput{width:193px}', '.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;}', From e4f9ce8dfc08161d542350e45288c7209c9dfe8a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 03:18:12 +0800 Subject: [PATCH 069/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 24ca28f6..4529c951 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2085,7 +2085,7 @@ try { return getBuffTurnFromImg(getPlayerBuff(img), 0); }, targetBuffTurn(img){ - return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), 'bleed'), 0); + return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), img), 0); }, targetHp(){ return target.hpNow/target.hp; @@ -3981,7 +3981,7 @@ try { } for (let i in skillOrder) { let skill = skillOrder[i]; - if(!skill){ + if(!skill || !g('option').skill[skill]){ return; } let id = skillLib[skill]; @@ -3995,11 +3995,11 @@ try { continue; } g('skillOTOS')[skill]++; - gE(id).click(); let target = checkCondition(g('option')[`skill${skill}Condition`], g('battle').monsterStatus); if(!target){ continue; } + gE(id).click(); const range = id in rangeSkills ? rangeSkills[id] : 0; getMonster(getRangeCenter(target, range).id).click(); return true; From 9c287ad024d6e3dce6aef349219e0a7ff6f8d9e1 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 15:48:56 +0800 Subject: [PATCH 070/216] =?UTF-8?q?2.90.32=20=E5=A2=9E=E5=8A=A0=E6=AD=A5?= =?UTF-8?q?=E8=BF=9B=E6=8C=89=E9=92=AE=E5=8F=8A=E5=BF=AB=E6=8D=B7=E9=94=AE?= =?UTF-8?q?=EF=BC=8C=E7=82=B9=E5=87=BB=E5=90=8E=E6=89=A7=E8=A1=8C=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=E6=88=98=E6=96=97=E6=93=8D=E4=BD=9C=EF=BC=88=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E6=88=98=E6=96=97=E3=80=81=E6=88=96=E6=88=98=E6=96=97?= =?UTF-8?q?=E5=86=85=E6=93=8D=E4=BD=9C=EF=BC=89=E5=90=8E=E6=9A=82=E5=81=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 4529c951..b67b2e09 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.31 +// @version 2.90.32 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -469,6 +469,8 @@ try { function setPauseUI(parent) { setPauseButton(parent); setPauseHotkey(); + setSteppingButton(parent); + setSteppingHotkey(parent); } function setPauseButton(parent) { @@ -484,6 +486,7 @@ try { button.className = 'pauseChange'; button.onclick = pauseChange; } + function setPauseHotkey() { if (!g('option').pauseHotkey) { return; @@ -498,6 +501,30 @@ try { }, false); } + function setSteppingButton(parent) { + if (!g('option').steppingButton) { + return; + } + const button = parent.appendChild(cE('button')); + button.innerHTML = '步进步進Stepping'; + button.className = 'stepping'; + button.onclick = stepping; + } + + function setSteppingHotkey() { + if (!g('option').steppingHotkey) { + return; + } + document.addEventListener('keydown', (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + return; + } + if (e.keyCode === g('option').steppingHotkeyCode) { + stepping(); + } + }, 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 @@ -869,7 +896,10 @@ try { '
脚本行为腳本行為Script Activity', '
暂停相关暫停相關Pause with: ', ' ; ', - '
', + '
', + ' ; ', + ' ', + '
', '
警告相关警告相關To Warn: ', ' ; ', ' ', @@ -1381,6 +1411,10 @@ try { this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; gE('input[name="pauseHotkeyCode"]', optionBox).value = e.keyCode; }; + gE('input[name="steppingHotkeyStr"]', optionBox).onkeyup = function (e) { + this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; + gE('input[name="steppingHotkeyCode"]', 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'); @@ -3042,12 +3076,14 @@ try { const names = g('option').battleOrderName?.split(',') ?? []; for (let i = 0; i < names.length; i++) { if(taskList[names[i]]()){ + onSteppingDone(); return; } delete taskList[names[i]]; } for (let name in taskList) { if (taskList[name]()) { + onSteppingDone(); return; } } @@ -3134,6 +3170,21 @@ try { } } + function stepping() { + setValue('stepping', true); + if (getValue('disabled')) { + pauseChange(); + } + } + + function onSteppingDone(){ + if(!getValue('stepping')){ + return; + } + delValue('stepping'); + pauseChange(); + } + function SetExitBattleTimeout(alarm){ setAlarm(alarm); if(alarm === 'SkipDefeated') return; @@ -3241,6 +3292,7 @@ try { unsafeWindow.battle.clear_infopane(); Debug.log('______________newRound', true); newRound(true); + onSteppingDone(); onBattle(); } catch(e) { e=>console.error(e) } }} From e2d4d029c246c3cc6161be5d4ae373689655d0af Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 16:27:50 +0800 Subject: [PATCH 071/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 114 +++++++++++------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b67b2e09..1eb70bc8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.32 +// @version 2.90.33 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -469,8 +469,8 @@ try { function setPauseUI(parent) { setPauseButton(parent); setPauseHotkey(); - setSteppingButton(parent); - setSteppingHotkey(parent); + setStepInButton(parent); + setStepInHotkey(parent); } function setPauseButton(parent) { @@ -501,26 +501,26 @@ try { }, false); } - function setSteppingButton(parent) { - if (!g('option').steppingButton) { + function setStepInButton(parent) { + if (!g('option').stepInButton) { return; } const button = parent.appendChild(cE('button')); - button.innerHTML = '步进步進Stepping'; - button.className = 'stepping'; - button.onclick = stepping; + button.innerHTML = '步进步進StepIn'; + button.className = 'stepIn'; + button.onclick = stepIn; } - function setSteppingHotkey() { - if (!g('option').steppingHotkey) { + function setStepInHotkey() { + if (!g('option').stepInHotkey) { return; } document.addEventListener('keydown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { return; } - if (e.keyCode === g('option').steppingHotkeyCode) { - stepping(); + if (e.keyCode === g('option').stepInHotkeyCode) { + stepIn(); } }, false); } @@ -897,8 +897,8 @@ try { '
暂停相关暫停相關Pause with: ', ' ; ', '
', - ' ; ', - ' ', + ' ; ', + ' ', '
', '
警告相关警告相關To Warn: ', ' ; ', @@ -1411,9 +1411,9 @@ try { this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; gE('input[name="pauseHotkeyCode"]', optionBox).value = e.keyCode; }; - gE('input[name="steppingHotkeyStr"]', optionBox).onkeyup = function (e) { + gE('input[name="stepInHotkeyStr"]', optionBox).onkeyup = function (e) { this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; - gE('input[name="steppingHotkeyCode"]', optionBox).value = e.keyCode; + gE('input[name="stepInHotkeyCode"]', 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'); @@ -2135,6 +2135,9 @@ try { targets ??= [g('battle').monsterStatus[0]]; for (i in parms) { for (target of targets){ + if (target.isDead) { + continue; + } let parmResult = true; for (j = 0; j < parms[i].length; j++) { let result = true; @@ -3076,14 +3079,15 @@ try { const names = g('option').battleOrderName?.split(',') ?? []; for (let i = 0; i < names.length; i++) { if(taskList[names[i]]()){ - onSteppingDone(); + console.log(names[i]); + onStepInDone(); return; } delete taskList[names[i]]; } for (let name in taskList) { if (taskList[name]()) { - onSteppingDone(); + onStepInDone(); return; } } @@ -3170,18 +3174,20 @@ try { } } - function stepping() { - setValue('stepping', true); + function stepIn() { + setValue('stepIn', true); if (getValue('disabled')) { + g('timeNow', time(0)); pauseChange(); } } - function onSteppingDone(){ - if(!getValue('stepping')){ + function onStepInDone(){ + if(!getValue('stepIn')){ return; } - delValue('stepping'); + console.trace('onStepInDone'); + delValue('stepIn'); pauseChange(); } @@ -3199,22 +3205,30 @@ try { } function reloader() { - let obj; let a; let cost; const battleUnresponsive = { - 'Alert': { Method: setAlarm }, - 'Reload': { Method: goto }, - 'Alt': { Method: gotoAlt } + 'Alert': { method: setAlarm }, + 'Reload': { method: goto }, + 'Alt': { method: gotoAlt } } function clearBattleUnresponsive(){ - Object.keys(battleUnresponsive).forEach(t=>clearTimeout(battleUnresponsive[t].Timeout)); + Object.keys(battleUnresponsive).forEach(t=>clearTimeout(battleUnresponsive[t].timeout)); + } + async function onBattleUnresponsive(method) { + if(getValue('disabled')){ + await pauseAsync(_1s); + return await onBattleUnresponsive(); + } + method(); } + + 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); + battleUnresponsive[t].timeout = setTimeout(()=>onBattleUnresponsive(battleUnresponsive[t].method), Math.max(1, g('option').battleUnresponsiveTime[t]) * _1s); } } if (g('option').recordUsage) { @@ -3232,6 +3246,7 @@ try { } }; gE('body').appendChild(eventStart); + const eventEnd = cE('a'); eventEnd.id = 'eventEnd'; eventEnd.onclick = function () { @@ -3258,13 +3273,27 @@ try { if (g('option').recordUsage) { recordUsage2(); } - if (g('battle').roundNow !== g('battle').roundAll) { // Next Round - if(g('option').NewRoundWaitTime){ - setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); + onRoundEnd(); + async function onRoundEnd() { + if(getValue('disabled')){ + await pauseAsync(_1s); + return await onRoundEnd(); + } + if (g('battle').roundNow === g('battle').roundAll) { // Next Round + if (g('monsterAlive') > 0) { // Defeat + SetExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); + } + if (g('battle').roundNow === g('battle').roundAll) { // Victory + SetExitBattleTimeout('Victory'); + } } else { - onNewRound(); + if(g('option').NewRoundWaitTime){ + setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); + } else { + onNewRound(); + } } - return; + clearBattleUnresponsive(); async function onNewRound(){ try { if(getValue('disabled')){ @@ -3292,20 +3321,13 @@ try { unsafeWindow.battle.clear_infopane(); Debug.log('______________newRound', true); newRound(true); - onSteppingDone(); + onStepInDone(); onBattle(); - } catch(e) { e=>console.error(e) } - }} - - if (g('monsterAlive') > 0) { // Defeat - SetExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); + } catch(e) { e=>console.error(e) }} } - 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'); @@ -4056,6 +4078,7 @@ try { getMonster(getRangeCenter(target, range).id).click(); return true; } + return false; } function useDeSkill() { // 自动施法DEBUFF技能 @@ -4285,6 +4308,9 @@ try { } } } + if(!target || target.isDead){ + return false; + } getMonster(getRangeCenter(target, range, !attackStatus).id).click(); return true; } From 019270dc5ee2c339a216b22ac6ed44ace73f75fe Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 7 Nov 2025 16:29:43 +0800 Subject: [PATCH 072/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1eb70bc8..d9fb0ccb 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.33 +// @version 2.90.32 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3079,7 +3079,6 @@ try { const names = g('option').battleOrderName?.split(',') ?? []; for (let i = 0; i < names.length; i++) { if(taskList[names[i]]()){ - console.log(names[i]); onStepInDone(); return; } @@ -3186,7 +3185,6 @@ try { if(!getValue('stepIn')){ return; } - console.trace('onStepInDone'); delValue('stepIn'); pauseChange(); } From 81a81f2eb10d29a44bc715a3427da124c5546999 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 8 Nov 2025 23:23:05 +0800 Subject: [PATCH 073/216] =?UTF-8?q?2.90.33=20=E4=BF=AE=E6=AD=A3=E5=85=88?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E5=85=A8=E4=BD=93=E7=9A=84debuff=E7=9A=84?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=A4=E6=96=AD=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d9fb0ccb..f804fde4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.32 +// @version 2.90.33 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4094,7 +4094,7 @@ try { skillPack.splice(i, 1); i--; } - skillPack.sort((x, y) => g('option').debuffSkillOrderValue.indexOf(x) - g('option').debuffSkillOrderValue.indexOf(y)) + 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(',')); @@ -4165,7 +4165,6 @@ try { img: 'confuse', }, }; - if (!isOn(skillLib[buff].id)) { // 技能不可用 return false; } @@ -4198,7 +4197,7 @@ try { let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; - target = checkCondition(g('option')[`debuffSkill${buff}Condition`], [target]); + target = checkCondition(g('option')[`debuffSkill${buff}${isAll ? 'all' : ''}Condition`], [target]); if (!target || target.isDead || isDebuffed(target)) { continue; } @@ -4215,7 +4214,6 @@ try { if (id === undefined) { return false; } - const imgs = gE('img', 'all', gE(monsterStateKeys.buffs, getMonster(id))); // 已有buff小于6个 // 未开启debuff失败警告 From 92ca5f13190edfb68fb5e85d9cb775d0de69e6c1 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 8 Nov 2025 23:46:28 +0800 Subject: [PATCH 074/216] =?UTF-8?q?2.90.34=20=E4=BF=AE=E6=AD=A3=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=88=A4=E6=96=AD=E8=8E=B7=E5=8F=96=E7=9A=84=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=EF=BC=8C=E5=9C=A8=E7=A9=BA=E6=9D=A1=E4=BB=B6=E6=97=B6?= =?UTF-8?q?=E6=9C=AA=E6=8C=89=E7=85=A7=E7=BB=99=E5=AE=9A=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/dodying/UserJs/issues/160#issuecomment-3506641243 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f804fde4..b8cfa8d3 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.33 +// @version 2.90.34 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2086,11 +2086,12 @@ try { } function checkCondition(parms, targets=undefined) { + let i; let j; let k; let target; + + targets ??= [g('battle').monsterStatus[0]]; if (typeof parms === 'undefined') { - return g('battle').monsterStatus[0]; + return targets[0]; } - let i; let j; let k; - let target; const returnValue = function (str) { if (str.match(/^_/)) { const arr = str.split('_'); @@ -2131,8 +2132,6 @@ try { return target.spNow; }, }; - - targets ??= [g('battle').monsterStatus[0]]; for (i in parms) { for (target of targets){ if (target.isDead) { From a589e3fde045e6eeec88406cf8207f1fbd2951e2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 10 Nov 2025 01:19:39 +0800 Subject: [PATCH 075/216] =?UTF-8?q?2.90.35=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=8F=8A=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8450 +++++++++-------- 1 file changed, 4247 insertions(+), 4203 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b8cfa8d3..666ecf7b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.34 +// @version 2.90.35 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -28,4207 +28,4250 @@ // @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 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; - -const monsterStateKeys = { - obj: `div.btm1`, - lv: `div.btm2`, - name: `div.btm3`, - bars: `div.btm4>div.btm5`, - buffs: `div.btm6`, -} - -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); + +(function () { + try { + 'use strict'; + + const standalone = ['option', 'arena', 'drop', 'stats', 'staminaLostLog', 'battleCode', 'disabled', 'stamina', 'staminaTime', 'lastHref', 'battle', 'monsterDB', 'monsterMID', 'ability']; + const sharable = ['option']; + const excludeStandalone = { 'option': ['optionStandalone', 'version', 'lang'] }; + const href = window.location.href; + const isFrame = window.self !== window.top; + + const isIsekai = href.indexOf('isekai') !== -1; + const current = isIsekai ? 'isekai' : 'persistent'; + const other = isIsekai ? 'persistent' : 'isekai'; + + const scriptVersion = '2.90'; + let hvVersion; + + const _1s = 1000; + const _1m = 60 * _1s; + const _1h = 60 * _1m; + const _1d = 24 * _1h; + const monsterStateKeys = { obj: `div.btm1`, lv: `div.btm2`, name: `div.btm3`, bars: `div.btm4>div.btm5`, buffs: `div.btm6` } + const [$async, $debug, $ajax] = [initAsync(), initDebug(), initAjax()]; + for (let check of [checkIsHV, checkIsWindowTop, checkOption]) { + if (!check()) return; + } + for (let step of [onRiddle, onIdle, onBattle]) { + if (step()) return; + } + // 其他情况进行等待刷新(例如加载错误等) + setTimeout(goto, 5 * _1m); + + // ----------Process Steps---------- + function initDebug() { + 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); + } + } } - 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 $debug; } - return; - } - try { - if(window.location.href.startsWith('https://')) { - MAIN_URL = MAIN_URL.replace(/^http:/, 'https:'); - } else { - MAIN_URL = MAIN_URL.replace(/^https:/, 'http:'); + + function initAjax() { + const $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, + error: 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') + }, + 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('&'); + } + } 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 () { + const _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); }); + return $ajax; } - } 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); + + function initAsync() { + const $async = { + list: [], + logSwitch: function (args) { + try { + const argsStr = Array.from(args).join(','); + const name = `${args.callee.name}${argsStr === '' ? argsStr : `(${argsStr})`}`; + const state = $async.list.indexOf(name) === -1; + if (!state) { + $async.list.splice($async.list.indexOf(name), 1); + } else { + $async.list.push(name); + } + console.log(`${state ? 'Start' : 'End'} ${name}\n`, JSON.parse(JSON.stringify($async.list))); + } catch (e) { } + } } + return $async; } - } - 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){} - } + function checkIsHV() { + if (window.location.host !== 'e-hentai.org') { + setValue('url', window.location.origin); + const hvver = gE('script[src*="hvc.js"]', document).src.match(/z\/(\d+)(.*)\/hvc.js/); + hvVersion = hvver[1] * 1; + hvVersion.sub = hvver[2]; - //ajax - function $doc(h) { - const d = document.implementation.createHTMLDocument(''); d.documentElement.innerHTML = h; return d; - } - var $ajax = { + // 补充记录(因写入冲突、网络卡顿等)未被记录的encounter链接 + if (window.location.href.indexOf(`?s=Battle&ss=ba`) !== -1) { + 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); + } - 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: [], + try { + if (window.location.href.startsWith('https://')) { + unsafeWindow.MAIN_URL = unsafeWindow.MAIN_URL.replace(/^http:/, `https:`); + } else { + unsafeWindow.MAIN_URL = unsafeWindow.MAIN_URL.replace(/^https:/, `http:`); + } + } catch (e) { } - 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('&'); - } - } 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; + return true; } - if ($ajax.tid) { - if (!$ajax.conn) { - clearTimeout($ajax.tid); - $ajax.timer(); - $ajax.send(); + + setValue('lastEH', time(0)); + const isEngage = window.location.href === 'https://e-hentai.org/news.php?encounter'; + let 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]; + if (url === undefined) { // 新一天 + encounter = []; } + encounter.unshift({ href: url, time: now }); + setEncounter(encounter); } 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; + 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; + } } - 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; + } + + if (!url) { + if (isEngage && !getValue('battle')) { + // 自动跳转,同时先刷新遭遇时间,延长下一次遭遇 + $ajax.openNoFetch(getValue('lastHref')); + } + return false; + } + + // 减少因在恒定世界处于战斗中时打开eh触发了遭遇而导致的错失 + // 缓存当前链接,等战斗结束时再自动打开,下次打开链接时: + // 1. 若新的遭遇未出现,进入已缓存的战斗链接 + // 2. 若新的遭遇已出现,则前一次已超时失效错过,重新获取新的一次 + if (!isEngage) { // 战斗外,非自动跳转 + eventpane.style.cssText += 'color:red;' // 链接标红提醒 + } else if (getValue('battle')) { //战斗中 + eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 + } else { // 战斗外,自动跳转 + $ajax.openNoFetch(`${href}/${url}`); + } + return false; } - if (!gE('#navbar,#riddlecounter,#textlog')) { - setTimeout(goto, 5 * _1m); - return; + function checkIsWindowTop() { + if (!isFrame) { + return true; + } + 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 false; } - 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); + function checkOption() { + g('version', GM_info ? GM_info.script.version.substr(0, 4) : scriptVersion); + 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 false; + } + loadOption(); + g('lang', g('option').lang || '0'); 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 (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 false; + } - 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; + 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 false; + } + return true; } - unsafeWindow = typeof unsafeWindow === 'undefined' ? window : unsafeWindow; - - if (gE('#riddlecounter')) { // 需要答题 + function onRiddle() { + if (!gE('#riddlecounter')) { + return false; + } if (!g('option').riddlePopup || window.opener) { riddleAlert(); // 答题警报 - return; + return true; } window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); - return; + return true; } - if (window.location.href.indexOf(`?s=Battle&ss=ba`) !== -1) { - // 补充记录(因写入冲突、网络卡顿等)未被记录的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) }); + function onIdle() { + if (!gE('#navbar')) { + return false; + } + // 战斗结束跳转回原链接 + if (window.top.location.href.endsWith(`?s=Battle`)) { + $ajax.openNoFetch(getValue('lastHref')); + return true; } - setEncounter(encounter); + if (window.location.href.indexOf(`?s=Battle&ss=ba`) === -1) { // 不缓存encounter + setValue('lastHref', window.top.location.href); // 缓存进入战斗前的页面地址 + setArenaDisplay(); + } + delValue(1); + if (g('option').showQuickSite && g('option').quickSite) { + quickSite(); + } + const hvAAPauseUI = document.body.appendChild(cE('div')); + hvAAPauseUI.classList.add('hvAAPauseUI'); + setPauseUI(hvAAPauseUI); + asyncOnIdle(); + return true; } - if (!gE('#navbar')) { // 战斗中 + + function onBattle() { + if (!gE('#textlog')) { + return false; + } const box2 = gE('#battle_main').appendChild(cE('div')); box2.id = 'hvAABox2'; setPauseUI(box2); reloader(); g('attackStatus', g('option').attackStatus); for (let fightingStyle = 1; fightingStyle < 6; fightingStyle++) { - if(gE(`2${fightingStyle}01`)){ + if (gE(`2${fightingStyle}01`)) { g('fightingStyle', fightingStyle.toString()); } } - g('timeNow', time(0)); g('runSpeed', 1); - Debug.log('______________newRound', false); + $debug.log('______________newRound', false); newRound(false); if (g('option').recordEach && !getValue('battleCode')) { setValue('battleCode', `${time(1)}: ${g('battle')?.roundType?.toUpperCase()}-${g('battle')?.roundAll}`); } - onBattle(); + onBattleRound(); updateEncounter(false, true); - return; - } - if(window.top.location.href.endsWith(`?s=Battle`)){ - $ajax.openNoFetch(getValue('lastHref')); - return; + return true; } - // 战斗外 - if (window.location.href.indexOf(`?s=Battle&ss=ba`) === -1) { // 不缓存encounter - setValue('lastHref', window.top.location.href); // 缓存进入战斗前的页面地址 - setArenaDisplay(); + // ----------methods---------- + // 通用// + function pauseAsync(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } - 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 gE(ele, mode, parent) { // 获取元素 + if (typeof ele === 'object') { + return ele; + } if (mode === undefined && parent === undefined) { + return (isNaN(ele * 1)) ? document.querySelector(ele) : document.getElementById(ele); + } if (mode === 'all') { + return (parent === undefined) ? document.querySelectorAll(ele) : parent.querySelectorAll(ele); + } if (typeof mode === 'object' && parent === undefined) { + return mode.querySelector(ele); + } + } - function setArenaDisplay(){ - if(window.location.href.indexOf(`?s=Battle&ss=ar`) === -1 && window.location.href.indexOf(`?s=Battle&ss=rb`) === -1){ - return; + function cE(name) { // 创建元素 + return document.createElement(name); } - var ar = g('option').idleArenaValue?.split(','); - if(!ar || ar.length === 0){ - return; + + function loadIframe(iframe) { + return new Promise((resolve, reject) => { + // 监听iframe的load事件 + iframe.onload = () => { + resolve("Iframe loaded successfully"); + }; + }); } - if(!g('option').obscureNotIdleArena){ - return; + + function $doc(h) { + const doc = document.implementation.createHTMLDocument(''); + doc.documentElement.innerHTML = h; + return doc; } - gE('img[src*="startchallenge.png"]', 'all', document).forEach((btn) => { - const onclick = btn.getAttribute('onclick'); - const temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/) ?? onclick.match(/init_battle\((\d+),\d+\)/); - if(ar.includes(temp[1])) { + + function setArenaDisplay() { + if (!g('option').obscureNotIdleArena) { 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 (window.location.href.indexOf(`?s=Battle&ss=ar`) === -1 && window.location.href.indexOf(`?s=Battle&ss=rb`) === -1) { + return; } + const ar = g('option').idleArenaValue?.split(','); + if (!ar || ar.length === 0) { + return; + } + getStartBattleButtons().forEach(btn => { + if (ar.includes(btn.id)) { + return; + } + gE('div', 'all', btn.parentNode.parentNode).forEach(div => { div.style.cssText += 'color:grey!important;' }); + }); } - // 迁移旧版本最后的慈悲条件为可配置条件 - const mercifulBlowCondition = option.skillT3Condition ?? {"0":[]}; - const size = Object.keys(mercifulBlowCondition).length; - if (option.mercifulBlowStrict){ - option.mercifulBlow = false; - option.mercifulBlowStrict = false; - for(let id in mercifulBlowCondition){ - const condition = mercifulBlowCondition[id]; - condition.push("fightingStyle,5,2"); - condition.push("targetHp,2,0.25"); - condition.push("_targetBuffTurn_bleed,1,0"); - } - } else if(option.mercifulBlow) { - option.mercifulBlow = false; - const newCondition = {}; - for(let id in mercifulBlowCondition){ - const condition = mercifulBlowCondition[id]; - newCondition[id] = condition; - newCondition[(id*1+size).toString()] = [...condition]; - newCondition[(id*1+size).toString()].push("fightingStyle,6,2"); - condition.push("fightingStyle,5,2"); - condition.push("targetHp,2,0.25"); - condition.push("_targetBuffTurn_bleed,1,0"); - } - option.skillT3Condition = newCondition; - } - if(isFrame){ - g('option', option); - } else{ - g('option', setValue('option', option)); - } - } - - function pauseAsync(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - async function asyncOnIdle() { try { - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncOnIdle(); - } - 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); + function getStartBattleButtons(document = undefined) { + const buttons = []; + document ??= window.document; + gE(`img[src*="startchallenge.png"], img[src*="startgrindfest.png"]`, 'all', document).forEach((btn) => { + const onclick = btn.getAttribute('onclick'); + const key = btn.getAttribute('src').match(`${unsafeWindow.IMG_URL}(.*)/start(.*).png`)[1] === 'grindfest' ? 'gr' : undefined; + let temp = hvVersion < 91 ? onclick.match(/init_battle\((\d+),\s*(\d+,)*'(.*?)'\)/) : onclick.match(/init_battle\((\d+)(,\d+)*\)/); + btn.id = key ? key : temp[1] * 1; + btn.token = temp[3]; + buttons.push(btn); + }); + return buttons; + } + + 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]]; + } + } + // 迁移旧版本最后的慈悲条件为可配置条件 + const mercifulBlowCondition = option.skillT3Condition ?? { "0": [] }; + const size = Object.keys(mercifulBlowCondition).length; + if (option.mercifulBlowStrict) { + option.mercifulBlow = false; + option.mercifulBlowStrict = false; + for (let id in mercifulBlowCondition) { + const condition = mercifulBlowCondition[id]; + condition.push("fightingStyle,5,2"); + condition.push("targetHp,2,0.25"); + condition.push("_targetBuffTurn_bleed,1,0"); + } + } else if (option.mercifulBlow) { + option.mercifulBlow = false; + const newCondition = {}; + for (let id in mercifulBlowCondition) { + const condition = mercifulBlowCondition[id]; + newCondition[id] = condition; + newCondition[(id * 1 + size).toString()] = [...condition]; + newCondition[(id * 1 + size).toString()].push("fightingStyle,6,2"); + condition.push("fightingStyle,5,2"); + condition.push("targetHp,2,0.25"); + condition.push("_targetBuffTurn_bleed,1,0"); + } + option.skillT3Condition = newCondition; + } + if (isFrame) { + g('option', option); + } else { + g('option', setValue('option', option)); + } } - 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(); - setStepInButton(parent); - setStepInHotkey(parent); - } - 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'; + function setPauseUI(parent) { + setPauseButton(parent); + setPauseHotkey(); + setStepInButton(parent); + setStepInHotkey(parent); } - 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') { + function setPauseButton(parent) { + if (!g('option').pauseButton) { return; } - if (e.keyCode === g('option').pauseHotkeyCode) { - pauseChange(); + const button = parent.appendChild(cE('button')); + button.innerHTML = '暂停暫停Pause'; + if (getValue('disabled')) { // 如果禁用 + document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); + button.innerHTML = '继续繼續Continue'; } - }, false); - } - - function setStepInButton(parent) { - if (!g('option').stepInButton) { - return; + button.className = 'pauseChange'; + button.onclick = pauseChange; } - const button = parent.appendChild(cE('button')); - button.innerHTML = '步进步進StepIn'; - button.className = 'stepIn'; - button.onclick = stepIn; - } - function setStepInHotkey() { - if (!g('option').stepInHotkey) { - return; - } - document.addEventListener('keydown', (e) => { - if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + function setPauseHotkey() { + if (!g('option').pauseHotkey) { return; } - if (e.keyCode === g('option').stepInHotkeyCode) { - stepIn(); - } - }, false); - } + document.addEventListener('keydown', (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + 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; + function setStepInButton(parent) { + if (!g('option').stepInButton) { + return; } - t.unshift(front); - break; + const button = parent.appendChild(cE('button')); + button.innerHTML = '步进步進StepIn'; + button.className = 'stepIn'; + button.onclick = stepIn; } - return t; - } - function getKeys(objArr, prop) { - let out = []; - objArr.forEach((_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--; + function setStepInHotkey() { + if (!g('option').stepInHotkey) { + return; } + document.addEventListener('keydown', (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + return; + } + if (e.keyCode === g('option').stepInHotkeyCode) { + stepIn(); + } + }, false); } - return out; - } - function time(e, stamp) { - const date = stamp ? new Date(stamp) : new Date(); - if (e === 0) { - return date.getTime(); - } if (e === 1) { - return `${date.getUTCMonth() + 1}/${date.getUTCDate()}`; - } if (e === 2) { - return `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${date.getUTCDate()}`; - } if (e === 3) { - return date.toLocaleString(navigator.language, { - hour12: 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 gE(ele, mode, parent) { // 获取元素 - if (typeof ele === 'object') { - return ele; - } if (mode === undefined && parent === undefined) { - return (isNaN(ele * 1)) ? document.querySelector(ele) : document.getElementById(ele); - } if (mode === 'all') { - return (parent === undefined) ? document.querySelectorAll(ele) : parent.querySelectorAll(ele); - } if (typeof mode === 'object' && parent === undefined) { - return mode.querySelector(ele); + function getKeys(objArr, prop) { + let out = []; + objArr.forEach((_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--; + } + } + return out; } - } - function cE(name) { // 创建元素 - return document.createElement(name); - } - - function getBuffTurnFromImg(buff, nanValue=NaN) { - if (!buff) { - return 0; + function time(e, stamp) { + const date = stamp ? new Date(stamp) : new Date(); + if (e === 0) { + return date.getTime(); + } if (e === 1) { + return `${date.getUTCMonth() + 1}/${date.getUTCDate()}`; + } if (e === 2) { + return `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${date.getUTCDate()}`; + } if (e === 3) { + return date.toLocaleString(navigator.language, { + hour12: false, + }); + } } - buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; - return isNaN(buff) ? nanValue : buff; - } - - function getMonsterID(s) { - if (s.order !== undefined) { - return (s.order + 1) % 10; - } // case is monsterStatus - return (s + 1) % 10; // case is order - } - - function getPlayerBuff(buff){ - return gE(`#pane_effects>img[src*="${buff}"]`); - } - - function getMonster(id){ - return gE(`#mkey_${id}`); - } - - function getMonsterBuff(id, buff){ - return gE(`${monsterStateKeys.buffs}>img[src*="${buff}"]`, getMonster(id)); - } - - function isOn(id) { // 是否可以施放技能/使用物品 - if (id * 1 > 10000) { // 使用物品 - return gE(`.bti3>div[onmouseover*="(${id})"]`); - } // 施放技能 - return gE(id) && (gE(id).style.opacity * 1 !== 0.5); - } - function setLocal(item, value) { - if (typeof GM_setValue === 'undefined') { - window.localStorage[`hvAA-${item}`] = (typeof value === 'string') ? value : JSON.stringify(value); - } else { - GM_setValue(item, value); + function setLocal(item, value) { + if (typeof GM_setValue === 'undefined') { + window.localStorage[`hvAA-${item}`] = (typeof value === 'string') ? value : JSON.stringify(value); + } else { + GM_setValue(item, value); + } } - } - function setValue(item, value) { // 储存数据 - if (!standalone.includes(item)) { - setLocal(item, value); + function setValue(item, value) { // 储存数据 + if (!standalone.includes(item)) { + setLocal(item, value); + return value; + } + setLocal(`${current}_${item}`, value); + if (sharable.includes(item) && !getValue('option').optionStandalone) { + setLocal(`${other}_${item}`, value); + } return value; } - setLocal(`${current}_${item}`, value); - if (sharable.includes(item) && !getValue('option').optionStandalone) { - setLocal(`${other}_${item}`, value); - } - return value; - } - 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; + 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; + } + return GM_getValue(item, null); } - return GM_getValue(item, null); - } - function getValue(key, toJSON) { // 读取数据 - if (!standalone.includes(key)) { - return getLocal(key, toJSON); - } - let otherWorldItem = getLocal(`${other}_${key}`); - // 将旧的数据迁移到新的数据 - 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 (Object.keys(excludeStandalone).includes(key)) { - otherWorldItem ??= getLocal(`${current}_${key}`) ?? {}; - for (let i of excludeStandalone[key]) { - otherWorldItem[i] = getLocal(`${current}_${key}`)[i]; + function getValue(key, toJSON) { // 读取数据 + if (!standalone.includes(key)) { + return getLocal(key, toJSON); + } + let otherWorldItem = getLocal(`${other}_${key}`); + // 将旧的数据迁移到新的数据 + 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 (Object.keys(excludeStandalone).includes(key)) { + otherWorldItem ??= getLocal(`${current}_${key}`) ?? {}; + for (let i of excludeStandalone[key]) { + otherWorldItem[i] = getLocal(`${current}_${key}`)[i]; + } } + setLocal(`${other}_${key}`, otherWorldItem); + return getLocal(`${current}_${key}`); } - setLocal(`${other}_${key}`, otherWorldItem); - return getLocal(`${current}_${key}`); - } - function delLocal(key) { - if (typeof GM_deleteValue === 'undefined') { - window.localStorage.removeItem(`hvAA-${key}`); - return; + function delLocal(key) { + if (typeof GM_deleteValue === 'undefined') { + window.localStorage.removeItem(`hvAA-${key}`); + return; + } + GM_deleteValue(key); } - 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(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 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) { // 全局变量 - const hvAA = window.hvAA || {}; - if (key === undefined && value === undefined) { - return hvAA; - } if (value === undefined) { - return hvAA[key]; + function goto() { // 前进 + window.location.href = window.location; + setTimeout(goto, 5000); } - hvAA[key] = value; - window.hvAA = hvAA; - return window.hvAA[key]; - } - function objArrSort(key) { // 对象数组排序函数,从小到大排序 - return function (obj1, obj2) { - return (obj2[key] < obj1[key]) ? 1 : (obj2[key] > obj1[key]) ? -1 : 0; - }; - } + 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 objSort(obj) { // 对象排序 - const objNew = {}; - const arr = Object.keys(obj).sort(); - arr.forEach((key) => { - objNew[key] = obj[key]; - }); - return objNew; - } + function g(key, value) { // 全局变量 + const hvAA = window.hvAA || {}; + if (key === undefined && value === undefined) { + return hvAA; + } if (value === undefined) { + return hvAA[key]; + } + hvAA[key] = value; + window.hvAA = hvAA; + return window.hvAA[key]; + } - function _alert(func, l0, l1, l2, answer) { - const lang = [l0, l1, l2][g('lang')]; - if (func === -1) { - return lang; - } if (func === 0) { - window.alert(lang); - } else if (func === 1) { - return window.confirm(lang); - } else if (func === 2) { - return window.prompt(lang, answer); + function objArrSort(key) { // 对象数组排序函数,从小到大排序 + return function (obj1, obj2) { + return (obj2[key] < obj1[key]) ? 1 : (obj2[key] > obj1[key]) ? -1 : 0; + }; } - } - 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;}`; + function objSort(obj) { // 对象排序 + const objNew = {}; + const arr = Object.keys(obj).sort(); + arr.forEach((key) => { + objNew[key] = obj[key]; + }); + return objNew; + } + + function _alert(func, l0, l1, l2, answer) { + const lang = [l0, l1, l2][g('lang')]; + if (func === -1) { + return lang; + } if (func === 0) { + window.alert(lang); + } else if (func === 1) { + return window.confirm(lang); + } else if (func === 2) { + return window.prompt(lang, answer); + } + } + + 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;}`; + } + 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;}', + '.customizeInput{width:193px}', + '.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;}', + // `${monsterStateKeys.lv}>div:nth-child(1):before{font-size:23px;font-weight:bold;text-shadow:1px 1px 2px;content:counter(order);counter-increment:order;}`, + // `${monsterStateKeys.lv}>div:nth-child(1)>img{display:none;}`, + ].join(''); + globalStyle.textContent = cssContent; + 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; + } + }; } - 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;}', - '.customizeInput{width:193px}', - '.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;}', - // `${monsterStateKeys.lv}>div:nth-child(1):before{font-size:23px;font-weight:bold;text-shadow:1px 1px 2px;content:counter(order);counter-increment:order;}`, - // `${monsterStateKeys.lv}>div:nth-child(1)>img{display:none;}`, - ].join(''); - globalStyle.textContent = cssContent; - 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; - } - }; - } - - 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: ', - '
', - ' ', - '
', - ' ', - ' ', - ' ', - '
', - '
', - ' [S!]精力精力Stamina: ', - ' 进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
', - ' 竞技场/浴血擂台阈值競技場/浴血擂台閾值Minimum stamina to auto start The Arena or Ring Of Blood: Min(85, )
', - ' 进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
', - ' [S!!]进入竞技场/浴血擂台/压榨届时,含本日自然恢复的阈值进入競技場/浴血擂台/壓榨屆时,含本日自然恢復的閾值Stamina threshold with naturally recovers today for The Arena, Ring Of Bloog, GrindFest:
', - '
', - '
: ', - ' 耐久度耐久度Durability%
', - '
[C!]检查物品库存檢查物品庫存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}}
', - '
:
{{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)
    ', - '
    ', - - '
    ', - '
    ', - ].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('.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; + 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: ', + '
    ', + ' ', + '
    ', + ' ', + ' ', + ' ', + '
    ', + '
    ', + ' [S!]精力精力Stamina: ', + ' 进入遭遇战的最低精力進入遭遇戰的最低精力Minimum stamina to engage encounter:
    ', + ' 竞技场/浴血擂台阈值競技場/浴血擂台閾值Minimum stamina to auto start The Arena or Ring Of Blood: Min(85, )
    ', + ' 进入压榨届的最低精力進入壓榨屆的最低精力Minimum stamina to auto start GrindFest:
    ', + ' [S!!]进入竞技场/浴血擂台/压榨届时,含本日自然恢复的阈值进入競技場/浴血擂台/壓榨屆时,含本日自然恢復的閾值Stamina threshold with naturally recovers today for The Arena, Ring Of Bloog, GrindFest:
    ', + '
    ', + '
    : ', + ' 耐久度耐久度Durability%
    ', + '
    [C!]检查物品库存檢查物品庫存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}}
    ', + '
    :
    {{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)
      ', + '
      ', + + '
      ', + ' ', + '
      ', + ].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('.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]}`; } - _html = `${_html}${key}`; + } else { + if (getValue('drop')) { + drop.__name = getValue('battleCode'); + dropOld.push(drop); + } + dropOld.reverse(); + _html = `${_html}`; dropOld.forEach((_dropOld) => { - if (key in _dropOld) { - _html = `${_html}${_dropOld[key]}`; - } else { - _html = `${_html}`; - } + _html = `${_html}${_dropOld.__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) => { + getKeys(dropOld).forEach((key) => { + if (key === '__name') { + return; + } _html = `${_html}${key}`; - statsOld.forEach((_statsOld) => { - if (key in _statsOld[i]) { - _html = `${_html}${_statsOld[i][key]}`; + dropOld.forEach((_dropOld) => { + if (key in _dropOld) { + _html = `${_html}${_dropOld[key]}`; } else { _html = `${_html}`; } }); + _html = `${_html}`; }); - }); - } - _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); + _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 === '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(); }; - }); + gE('.hvAAGoto', 'all', optionBox).forEach((i) => { + 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; + 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; } - } - } - 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; + 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; + } } - return; - } - g('customizeTarget', target); - const position = target.getBoundingClientRect(); - const bodyPosition = document.body.getBoundingClientRect(); - gE('.customizeBox').style.zIndex = 5; - gE('.customizeBox').style.top = `${position.bottom - bodyPosition.top}px`; - gE('.customizeBox').style.left = `${position.left - bodyPosition.left}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; - }; - gE('input[name="stepInHotkeyStr"]', optionBox).onkeyup = function (e) { - this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; - gE('input[name="stepInHotkeyCode"]', 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'); - }; - 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); - }; - 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', {}); - } - }; - gE('.idleArenaReset', optionBox).onclick = function () { - 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('.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('.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; - }; + 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(); + const bodyPosition = document.body.getBoundingClientRect(); + gE('.customizeBox').style.zIndex = 5; + gE('.customizeBox').style.top = `${position.bottom - bodyPosition.top}px`; + gE('.customizeBox').style.left = `${position.left - bodyPosition.left}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; + }; + gE('input[name="stepInHotkeyStr"]', optionBox).onkeyup = function (e) { + this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; + gE('input[name="stepInHotkeyCode"]', 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'); + }; + 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); + }; + 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', {}); + } + }; + gE('.idleArenaReset', optionBox).onclick = function () { + 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('.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('.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; - }; + 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; + if (e.target.checked) { + name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); + } else { + name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="battleOrderName"]').value = name; + }; - // 标签页-物品 - 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; - }; - // 标签页-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; - }; - // 标签页-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; - }; - // 标签页-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; - }; - // 标签页-其他技能 - 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; - }; - // 标签页-警报 - 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'); - }; - // 标签页-掉落监测 - gE('.reDropMonitor', optionBox).onclick = function () { - 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'); - } - }; - // 标签页-关于本脚本 - gE('.hvAAFix', optionBox).onclick = function () { - 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 = ''; - }; - gE('.hvAAConfig', optionBox).onclick = function () { - 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(); + // 标签页-物品 + 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; + }; + // 标签页-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; + }; + // 标签页-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; + }; + // 标签页-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; + }; + // 标签页-其他技能 + 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; + }; + // 标签页-警报 + 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'); + }; + // 标签页-掉落监测 + gE('.reDropMonitor', optionBox).onclick = function () { + 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'); + } + }; + // 标签页-关于本脚本 + gE('.hvAAFix', optionBox).onclick = function () { + 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 = ''; + }; + gE('.hvAAConfig', optionBox).onclick = function () { + 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(); + } } } - } - 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; - }; - 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(); - }; - 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); - }; - gE('.hvAAExport', optionBox).onclick = function () { - 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); + 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; + }; + 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(); - } - }; - gE('.hvAAReset', optionBox).onclick = function () { - 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)) { + 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); + }; + gE('.hvAAExport', optionBox).onclick = function () { + 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(); + } + }; + gE('.hvAAReset', optionBox).onclick = function () { + 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; } - } else if (inputs[i].type === 'text' || inputs[i].type === 'hidden') { - itemName = inputs[i].name; - itemValue = inputs[i].value || inputs[i].placeholder; - if (itemValue === '') { - continue; + 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; + } } - } else if (inputs[i].type === 'checkbox') { - itemName = inputs[i].id; - itemValue = inputs[i].checked; - if (itemValue === false) { + } + 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; } - } else if (inputs[i].type === 'select-one') { - itemName = inputs[i].name; - itemValue = inputs[i].value; + _option.quickSite.push({ + fav: inputs[3 * i].value, + name: inputs[3 * i + 1].value, + url: inputs[3 * i + 2].value, + }); } - itemArray = itemName.split('_'); - if (itemArray.length === 1) { - _option[itemName] = itemValue; - } else { - if (!(itemArray[0] in _option)) { - _option[itemArray[0]] = {}; + setValue('option', _option); + optionBox.style.display = 'none'; + // 更改设置后实时刷新竞技场数据 + const arenaNew = _option.idleArenaValue; + if (arenaNew === arenaPrev) { + 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'; + }; + 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; } - 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); + itemName = inputs[i].name || inputs[i].id; + if (typeof _option[itemName] !== 'undefined') { + itemValue = _option[itemName]; } else { - _option[itemArray[0]][itemArray[1]] = itemValue; + 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; } } - } - inputs = gE('.hvAAQuickSite input[type="text"]', 'all', optionBox); - for (i = 0; 3 * i < inputs.length; i++) { - if (i === 0 && inputs.length !== 0) { - _option.quickSite = []; + 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[3 * i + 1].value === '') { - continue; + if (_option.quickSite) { + _html = '图标圖標ICON名称名稱Name链接鏈接Link'; + _option.quickSite.forEach((i) => { + _html = `${_html}`; + }); + gE('.hvAAQuickSite>table>tbody', optionBox).innerHTML = _html; } - _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){ - 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'; - }; - 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; + if (getValue('backup')) { + const backups = getValue('backup', true); + _html = ''; + for (i in backups) { + _html = `${_html}
    • ${i}
    • `; + } + gE('.hvAABackupList', optionBox).innerHTML = _html; } - itemName = inputs[i].name || inputs[i].id; - if (typeof _option[itemName] !== 'undefined') { - itemValue = _option[itemName]; + } + } + + function customizeBox() { // 自定义条件界面 + const customizeBox = gE('body').appendChild(cE('div')); + customizeBox.className = 'customizeBox'; + const statusOption = [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ].join(''); + customizeBox.innerHTML = [ + '??', + `${String.fromCharCode(0x21F1.toString(10))}`, + '', + ``, + '', + ``, + '', + ].join(' '); + const funcSelect = function (e) { + let box; + if (gE('#hvAAInspectBox')) { + box = gE('#hvAAInspectBox'); } 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]]; - } + box = gE('body').appendChild(cE('div')); + box.id = 'hvAAInspectBox'; } - 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; - } - } - 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]; - } + 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); + } + 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); + } + }; + 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}`; + }; + + 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]}`; } } - if (_option.quickSite) { - _html = '图标圖標ICON名称名稱Name链接鏈接Link'; - _option.quickSite.forEach((i) => { - _html = `${_html}`; - }); - gE('.hvAAQuickSite>table>tbody', optionBox).innerHTML = _html; + } + + function setAlarm(e) { // 发出警报 + e = e || 'Common'; + if (g('option').notification) { + setNotification(e); } - if (getValue('backup')) { - const backups = getValue('backup', true); - _html = ''; - for (i in backups) { - _html = `${_html}
    • ${i}
    • `; - } - gE('.hvAABackupList', optionBox).innerHTML = _html; + if (g('option').alert && g('option').audioEnable && g('option').audioEnable[e]) { + setAudioAlarm(e); } } - } - function customizeBox() { // 自定义条件界面 - const customizeBox = gE('body').appendChild(cE('div')); - customizeBox.className = 'customizeBox'; - const statusOption = [ - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - ].join(''); - customizeBox.innerHTML = [ - '??', - `${String.fromCharCode(0x21F1.toString(10))}`, - '', - ``, - '', - ``, - '', - ].join(' '); - const funcSelect = function (e) { - let box; - if (gE('#hvAAInspectBox')) { - box = gE('#hvAAInspectBox'); + function setAudioAlarm(e) { // 发出音频警报 + let audio; + if (gE(`#hvAAAlert-${e}`)) { + audio = gE(`#hvAAAlert-${e}`); } 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); - } - 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); - } - }; - 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}`; - }; - - 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]}`; + 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 setAlarm(e) { // 发出警报 - e = e || 'Common'; - if (g('option').notification) { - setNotification(e); - } - if (g('option').alert && g('option').audioEnable && g('option').audioEnable[e]) { - setAudioAlarm(e); - } - } + function pauseAudio(e) { + 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, + }, + 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, + }, + }, + ][g('lang')][e]; + if (typeof GM_notification !== 'undefined') { + GM_notification({ + text: notification.text, + image: `${window.location.origin}${unsafeWindow.IMG_URL}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: `${unsafeWindow.IMG_URL}hentaiverse.png`, + }); + setTimeout(() => { + if (n) { + n.close(); + } + }, 1000 * notification.time); - function setAudioAlarm(e) { // 发出音频警报 - let audio; - if (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'); + const nClose = function (e) { + if (n) { + n.close(); + } + document.removeEventListener(e.type, nClose, true); + }; + document.addEventListener('mousemove', nClose, true); + } + }); + } } - audio.play(); - function pauseAudio(e) { - audio.pause(); - document.removeEventListener(e.type, pauseAudio, true); - } - document.addEventListener('mousemove', pauseAudio, true); - } + function checkCondition(parms, targets = undefined) { + let i; let j; let k; let target; - 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, + targets ??= [g('battle').monsterStatus[0]]; + if (typeof parms === 'undefined') { + return targets[0]; + } + 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('battle') ?? getValue('battle', true))[key] ?? g(key) ?? getValue(key) ?? g('option')?.[key]; + continue; + } + result = result[key] + } + return isNaN(result * 1) ? result : (result * 1); + } + return str * 1; + }; + const func = { + isCd(id) { // is cool down done + return isOn(id) ? 1 : 0; }, - Error: { - text: 'Some errors have occurred', - time: 10, + buffTurn(img) { + return getBuffTurnFromImg(getPlayerBuff(img), 0); }, - Defeat: { - text: 'You have been defeated.\nYou can check the battle log.', - time: 5, + targetBuffTurn(img) { + return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), img), 0); }, - Riddle: { - text: 'Riddle\nURGENT\nURGENT\nURGENT', - time: 30, + targetHp() { + return target.hpNow / target.hp; }, - Victory: { - text: 'You\'re victorious.\nThis page will refresh in 3 seconds.', - time: 3, + targetMp() { + return target.mpNow; }, - Test: { - text: 'testText', - time: 3, + targetSp() { + return target.spNow; }, - }, - ][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, - }); - } - 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(); - } - document.removeEventListener(e.type, nClose, true); - }; - document.addEventListener('mousemove', nClose, true); - // document.addEventListener('click', nClose, true); - } - }); - } - } - - function checkCondition(parms, targets=undefined) { - let i; let j; let k; let target; - - targets ??= [g('battle').monsterStatus[0]]; - if (typeof parms === 'undefined') { - return targets[0]; - } - 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('battle') ?? getValue('battle', true))[key] ?? g(key) ?? getValue(key) ?? g('option')?.[key]; - continue; - } - result = result[key] - } - return isNaN(result * 1) ? result : (result * 1); - } - return str * 1; - }; - var func = { - isCd(id) { // is cool down done - return isOn(id) ? 1 : 0; - }, - buffTurn(img) { - return getBuffTurnFromImg(getPlayerBuff(img), 0); - }, - targetBuffTurn(img){ - return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), img), 0); - }, - targetHp(){ - return target.hpNow/target.hp; - }, - targetMp(){ - return target.mpNow; - }, - targetSp(){ - return target.spNow; - }, - }; - for (i in parms) { - for (target of targets){ - if (target.isDead) { - continue; - } - let parmResult = true; - for (j = 0; j < parms[i].length; j++) { - let result = true; - if (!Array.isArray(parms[i])) { + }; + for (i in parms) { + for (target of targets) { + if (target.isDead) { continue; } - k = parms[i][j].split(','); - const kk = k.toString(); - k[0] = returnValue(k[0]); - k[2] = returnValue(k[2]); + let parmResult = true; + for (j = 0; j < parms[i].length; j++) { + let result = true; + 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]); - } + 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 = k[0] > k[2]; - break; - case '2': - result = k[0] < k[2]; - break; - case '3': - result = k[0] >= k[2]; - break; - case '4': - result = k[0] <= k[2]; - break; - case '5': - result = k[0] === k[2]; - break; - case '6': - result = k[0] !== k[2]; + switch (k[1]) { + case '1': + result = k[0] > k[2]; + break; + case '2': + result = k[0] < k[2]; + break; + case '3': + result = k[0] >= k[2]; + break; + case '4': + result = k[0] <= k[2]; + break; + case '5': + result = k[0] === k[2]; + break; + case '6': + result = k[0] !== k[2]; + break; + } + if (!result) { + parmResult = false; break; + } } - if (!result) { - parmResult = false; - break; + if (parmResult) { + return target; } } - if (parmResult){ - return target; - } } + return undefined; } - return undefined; - } - // 答题// - function riddleAlert() { // 答题警报 - if (window.opener) { - 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; - } - }; - 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 checkTime = function () { - let time; - if (typeof g('time') === 'undefined') { - const timeDiv = gE('#riddlecounter>div>div', 'all'); - if (timeDiv.length === 0) { - return; + function pauseChange() { // 暂停状态更改 + if (getValue('disabled')) { + if (gE('.pauseChange')) { + gE('.pauseChange').innerHTML = '暂停暫停Pause'; } - time = ''; - for (let j = 0; j < timeDiv.length; j++) { - time = (timeDiv[j].style.backgroundPosition.match(/(\d+)px$/)[1] / 12).toString() + time; + document.title = gE('#navbar') ? 'The Hentaiverse' : getValue('disabled'); + delValue(0); + if (!gE('#navbar')) { // in battle + onBattleRound(); } - g('time', time * 1); } else { - time = g('time'); - time--; - g('time', time); + if (gE('.pauseChange')) { + gE('.pauseChange').innerHTML = '继续繼續Continue'; + } + setValue('disabled', document.title); + document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); } - document.title = time; - if (time <= g('option').riddleAnswerTime) { - riddleSubmit(gE('#riddleanswer').value || answers[parseInt(Math.random() * 3)]); + } + + function stepIn() { + setValue('stepIn', true); + if (getValue('disabled')) { + g('timeNow', time(0)); + pauseChange(); } - }; - for (let i = 0; i < 30; i++) { - setTimeout(checkTime, i * _1s); } - 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 onStepInDone() { + if (!getValue('stepIn')) { + return; } + delValue('stepIn'); + pauseChange(); } - } - // 战斗外// - 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'; - let 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]; - if(url === undefined){ // 新一天 - encounter = []; + // 答题// + function riddleAlert() { // 答题警报 + if (window.opener) { + gE('#riddleanswer+img').onclick = function () { + riddleSubmit(gE('#riddleanswer').value); + }; } - 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); + 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; } - for (let e of encounter) { - if (e.encountered) { - continue; + }; + 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 checkTime = function () { + let time; + if (typeof g('time') === 'undefined') { + const timeDiv = gE('#riddlecounter>div>div', 'all'); + if (timeDiv.length === 0) { + return; } - url = e.href; - break; + 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); } + 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); } - } - if (!url) { - if (isEngage && !getValue('battle')) { - // 自动跳转,同时先刷新遭遇时间,延长下一次遭遇 - $ajax.openNoFetch(getValue('lastHref')); + 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)); + } } - return; } - // 减少因在恒定世界处于战斗中时打开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 quickSite() { // 快捷站点 + const quickSiteBar = gE('body').appendChild(cE('div')); + quickSiteBar.className = 'quickSiteBar'; + quickSiteBar.innerHTML = '<<贴吧Forums'; + if (g('option').quickSite) { + 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 === '<<') ? '>>' : '<<'; + }; } - } - - 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; - } - try { - // if is latest version data - for (let e of encounter) {} - } catch { - // if old versions - const last = encounter.lastTime; - const times = encounter.time; - encounter = []; - for (let i = 0; i <= times; i++) { - encounter.unshift({ href: i===0 ? undefined : i, time: last, encountered: i===0 ? undefined : time(0) }); - } - setEncounter(encounter); - } - 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; + function autoSwitchIsekai() { + if (!g('option').isekai) { + // 若不启用自动跳转 + return; + } + window.location.href = `${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`; } - return getToday(Object.values(dict)).sort((x, y) => x.time < y.time ? 1 : x.time > y.time ? -1 : 0); - } - function quickSite() { // 快捷站点 - const quickSiteBar = gE('body').appendChild(cE('div')); - quickSiteBar.className = 'quickSiteBar'; - quickSiteBar.innerHTML = '<<贴吧Forums'; - if (g('option').quickSite) { - g('option').quickSite.forEach((site) => { - quickSiteBar.innerHTML = `${quickSiteBar.innerHTML}${(site.fav) ? `` : ''}${site.name}`; - }); + async function asyncOnIdle() { + try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncOnIdle(); + } + 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) } } - 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 === '<<') ? '>>' : '<<'; - }; - } - function autoSwitchIsekai() { - if (!g('option').isekai) { - // 若不启用自动跳转 - return; + function setEncounter(encounter) { + return g('encounter', setValue('encounter', encounter)); } - window.location.href = `${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`; - } - async function asyncSetAbilityData() { try { - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncSetAbilityData(); - } - 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']; - switch(type){ - case 'deprecating1': - case 'deprecating2': - case 'elemental': - case 'forbidden': - case 'divine': - break; - default: - return; + 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; } - 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), + try { + // if is latest version data + for (let e of encounter) { } + } catch { + // if old versions + const last = encounter.lastTime; + const times = encounter.time; + encounter = []; + for (let i = 0; i <= times; i++) { + encounter.unshift({ href: i === 0 ? undefined : i, time: last, encountered: i === 0 ? undefined : time(0) }); } - }); - } catch (e) {console.error(e)}})); - setValue('ability', ability); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - async function asyncSetEnergyDrinkHathperk() { try { - if (isIsekai || !g('option').restoreStamina) { - return; - } - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncSetEnergyDrinkHathperk(); - } - 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 { - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncSetStamina(); - } - 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 { - if (!g('option').checkSupply && (isIsekai || !g('option').restoreStamina)) { - return; - } - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncGetItems(); - } - 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]; + setEncounter(encounter); + } + 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); } - g('items', items); - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - async function asyncCheckSupply() { try { - if (!g('option').checkSupply) { - return true; - } - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncCheckSupply(); - } - 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}`); - document.title = `[C!]` + document.title; + async function asyncSetAbilityData() { + try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetAbilityData(); + } + $async.logSwitch(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']; + switch (type) { + case 'deprecating1': + case 'deprecating2': + case 'elemental': + case 'forbidden': + case 'divine': + break; + default: + return; + } + 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); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - logSwitchAsyncTask(arguments); - return !needs.length; - } catch (e) {console.error(e)} return false; } - async function asyncCheckRepair() { try { - if (!g('option').repair) { - return true; - } - if(getValue('disabled')){ - await pauseAsync(_1s); - return await asyncCheckRepair(); - } - logSwitchAsyncTask(arguments); - var eqps; - if(!isIsekai){ - var doc = $doc(await $ajax.fetch('?s=Forge&ss=re')); - const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); - 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) { + async function asyncSetEnergyDrinkHathperk() { + try { + if (isIsekai || !g('option').restoreStamina) { 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); - } else { - doc = $doc(await $ajax.fetch('?s=Bazaar&ss=am&screen=repair&filter=equipped')); - eqps = (await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { - const id = eqp.getAttribute('onmouseover').match(/hover_equip\((\d+)\)/)[1]; - const condition = 1 * gE('td:last-child', eqp).childNodes[0].textContent.replace('%', ''); - if (condition > g('option').repairValue) { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetEnergyDrinkHathperk(); + } + $async.logSwitch(arguments); + const html = await $ajax.fetch('https://e-hentai.org/hathperks.php'); + if (!html) { return; } - // TODO repair - var iframe = cE('iframe'); - iframe.style.cssText += "display:none" - iframe.src = `?s=Bazaar&ss=am&screen=repair&filter=equipped&eqids[]=${id}`; - document.body.appendChild(iframe); - await loadIframe(iframe); - if(gE('#equipsubmit', iframe.contentWindow.document.body).getAttribute('disabled')){ - return id; + const doc = $doc(html); + const perks = gE('.stuffbox>table>tbody>tr', 'all', doc); + if (!perks) { + return; } - gE('#equipform', iframe.contentWindow.document.body).submit(); - } catch (e) {console.error(e)}}))).filter(e => e); - } - if (eqps.length) { - console.log('eqps need repair: ', eqps); - document.title = `[R!]` + document.title; + setValue('staminaHathperk', perks[25].innerHTML.includes('Obtained')); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - logSwitchAsyncTask(arguments); - return !eqps.length; - } catch (e) {console.error(e)}; return false; } - - function loadIframe(iframe) { - return new Promise((resolve, reject) => { - // 监听iframe的load事件 - iframe.onload = () => { - resolve("Iframe loaded successfully"); - }; - }); - } - 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 asyncSetStamina() { + try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetStamina(); + } + $async.logSwitch(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); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - } - async function updateEncounter(engage, isInBattle) { try { - if(!g('option').encounter && !g('option').encounterDisplay){ - console.log("skip encounter check"); - return; - } - if(getValue('disabled')){ - await pauseAsync(_1s); - return await updateEncounter(engage, isInBattle); - } - 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); + async function asyncGetItems() { + try { + if (!g('option').checkSupply && (isIsekai || !g('option').restoreStamina)) { + return; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncGetItems(); + } + $async.logSwitch(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); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - $ajax.openNoFetch('https://e-hentai.org/news.php?encounter'); - } - async function startUpdateArena(idleStart, startIdleArena=true) { try { - const now = time(0); - if (!idleStart) { - await updateArena(); - } - let timeout = g('option').idleArenaTime * _1s; - if (idleStart) { - timeout -= time(0) - idleStart; - } - if(startIdleArena){ - setTimeout(idleArena, timeout); - } - 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 { - if(getValue('disabled')){ - await pauseAsync(_1s); - return await updateArena(forceUpdateToken); - } - 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') { - const onclickInner = gE('img[src*="startgrindfest.png"]', doc).getAttribute('onclick').match(/init_battle\(1\)/); - if(onclickInner){ - arena.token.gr = null; - } - return; + async function asyncCheckSupply() { + try { + if (!g('option').checkSupply) { + return true; } - gE('img[src*="startchallenge.png"]', 'all', doc).forEach((btn) => { - const onclick = btn.getAttribute('onclick'); - var temp = onclick.match(/init_battle\((\d+),\d+,'(.*?)'\)/); - if(temp){ - arena.token[temp[1]] = temp[2]; - return; + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckSupply(); + } + $async.logSwitch(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; } - temp = onclick.match(/init_battle\((\d+),\d+\)/); - if(temp){ - arena.token[temp[1]] = null; - return; + const [name, count] = item; + const threshold = thresholdList[id] ?? 0; + if ((count ?? 0) >= threshold) { + continue; } - temp = onclick.match(/init_battle\((\d+)\)/); - arena.token[temp[1]] = null; - }); - } 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(); + needs.push(`\n${name}(${count}<${threshold})`); + } + if (needs.length) { + console.log(`Needs supply:${needs}`); + document.title = `[C!]` + document.title; + } + $async.logSwitch(arguments); + return !needs.length; + } catch (e) { console.error(e) } return false; } - 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; + async function asyncCheckRepair() { + try { + if (!g('option').repair) { + return true; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckRepair(); + } + $async.logSwitch(arguments); + let eqps; + if (hvVersion < 91) { + 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]); + 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); + } else { + const doc = $doc(await $ajax.fetch('?s=Bazaar&ss=am&screen=repair&filter=equipped')); + eqps = (await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { + try { + const id = eqp.getAttribute('onmouseover').match(/hover_equip\((\d+)\)/)[1]; + const condition = 1 * gE('td:last-child', eqp).childNodes[0].textContent.replace('%', ''); + if (condition > g('option').repairValue) { + return; + } + const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped&eqids[]=${id}`; + const iframe = cE('iframe'); + iframe.src = href; + iframe.style.cssText += "display:none" + document.body.appendChild(iframe); + await loadIframe(iframe); + const doc = iframe.contentWindow.document; + const disabled = gE('#equipsubmit', doc).getAttribute('disabled'); + if (disabled !== undefined && disabled !== null) { + return id; + } + gE('#equipform', doc).submit(); + } catch (e) { console.error(e) } + }))).filter(e => e); + } + if (eqps.length) { + console.log('eqps need repair: ', eqps); + document.title = `[R!]` + document.title; + } + $async.logSwitch(arguments); + return !eqps.length; + } catch (e) { console.error(e) }; return false; } - const staminaChecked = checkStamina(condition.staminaLow, condition.staminaCost); - console.log("staminaChecked", condition.staminaLow, condition.staminaCost, staminaChecked); - if(staminaChecked === 1){ // succeed + + 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 return true; + } + if (staminaChecked === 0) { // failed currently + setTimeout(method, Math.floor(time(0) / _1h + 1) * _1h - time(0)); + document.title = `[S!]` + document.title; + } else { // case -1: // failed with nature recover + document.title = `[S!!]` + document.title; + } } - if(staminaChecked === 0){ // failed currently - setTimeout(method, Math.floor(time(0) / _1h + 1) * _1h - time(0)); - document.title = `[S!]` + document.title; - } else { // case -1: // failed with nature recover - document.title = `[S!!]` + document.title; - } - } - async function idleArena() { try { // 闲置竞技场 - function writeArenaStart(){ - document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); - if (key !== 'gr'){ - arena.arrayDone.push(key); - } else { - arena.gr--; + 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; } - setValue('arena', arena); - } - 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; + let checked = 0; + if (!stmNRChecked) { + checked = -1; } - if (id >= 105) { - arena.token = (await updateArena(true)).token; - if (id in arena.token) { - break; - } + if (isIsekai || !g('option').restoreStamina) { + return checked; } - 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]; - let key = id; - if (key === 'gr') { - if (arena.gr <= 0) { - setValue('arena', arena); - idleArena(); - arena.arrayDone.push('gr'); - return; + 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; } - href = 'gr'; - key = 1; - cost = staminaCost.gr; - } else if (key >= 105) { - href = 'rb'; - } else if (key >= 19) { - href = 'ar&page=2'; - } else { - href = 'ar'; - } - cost ??= staminaCost[key]; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: href === 'gr' ? g('option').staminaGrindFest : undefined})) { - logSwitchAsyncTask(arguments); - return; } - if(token){ - writeArenaStart(); - $ajax.open(`?s=Battle&ss=${href}`, `initid=${String(key)}&inittoken=${token}`); - logSwitchAsyncTask(arguments); - return; + + async function updateEncounter(engage, isInBattle) { + try { + if (!g('option').encounter && !g('option').encounterDisplay) { + console.log("skip encounter check"); + return; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await updateEncounter(engage, isInBattle); + } + 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) } } - // new version in isekai - var iframe = cE('iframe'); - iframe.src = `?s=Battle&ss=${href}`; - iframe.style.cssText += "display:none"; - document.body.appendChild(iframe); - await loadIframe(iframe); - var btns = gE(`#arena_list>tbody>tr>td>img`, 'all', iframe.contentWindow.document.body); - for(let btn of btns){ - const onclick = btn.getAttribute('onclick'); - if(!onclick){ - continue; - } - var temp = onclick.match(/init_battle\((\d+),\d+\)/) ?? onclick.match(/init_battle\((\d+)\)/); - if(!temp || temp[1]*1 !== key){ - continue; - } - iframe.contentWindow.confirm = function(message) { // 自动点击进入 - return true; - }; - iframe.contentWindow.alert = function(message) { + + function onEncounter() { + if (getValue('disabled') || getValue('battle') || !checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { return; - }; - writeArenaStart(); - btn.onclick(); - await loadIframe(iframe); - goto(); - return; + } + setEncounter(getEncounter()); // 离开页面前保存 + if (!window.top.location.href.endsWith(`?s=Battle`)) { + setValue('lastHref', window.top.location.href); + } + $ajax.openNoFetch('https://e-hentai.org/news.php?encounter'); } - logSwitchAsyncTask(arguments); - } catch (e) {console.error(e)}} - - // 战斗中// - 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 + + async function startUpdateArena(idleStart, startIdleArena = true) { + try { + const now = time(0); + if (!idleStart) { + await updateArena(); } - }) - battle.monsterStatus.sort(objArrSort('order')); - }; - 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); + let timeout = g('option').idleArenaTime * _1s; + if (idleStart) { + timeout -= time(0) - idleStart; + } + if (startIdleArena) { + setTimeout(idleArena, timeout); + } + const last = getValue('arena', true)?.date ?? now; + setTimeout(startUpdateArena, Math.max(0, Math.floor(last / _1d + 1) * _1d - now)); + } catch (e) { console.error(e) } } - // 战斗战况 - if (!gE('.hvAALog')) { - const div = gE('#hvAABox2').appendChild(cE('div')); - div.className = 'hvAALog'; + async function updateArena(forceUpdateToken = false) { + try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await updateArena(forceUpdateToken); + } + 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)); + getStartBattleButtons(doc).forEach(btn => { arena.token[btn.id] = btn.token ?? null; }); + } 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) } } - 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(`${monsterStateKeys.name}>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]) { + + async function idleArena() { + try { // 闲置竞技场 + let id; + let arena = getValue('arena', true); + + const writeArenaStart = function () { + document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); + if (id !== 'gr') { + arena.arrayDone.push(id); + } else { + arena.gr--; + } + setValue('arena', arena); + } + console.log('arena:', getValue('arena', true)); + if (arena.array.length === 0) { + setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); + return; + } + $async.logSwitch(arguments); + const array = [...arena.array]; + 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; } - subtype = `${sub[lang] ? `
      ${sub[lang]}` : ``}${info.end ? `
      ${info.end}` : ``}`; - break; } + id = undefined; + } + if (!id) { + setValue('arena', arena); + $async.logSwitch(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 id in staminaCost) { + staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) + } + staminaCost.gr += 1 + + let href; + let token = arena.token[id]; + const cost = staminaCost[id]; + if (id === 'gr') { + if (arena.gr <= 0) { + setValue('arena', arena); + idleArena(); + arena.arrayDone.push('gr'); + return; + } + href = 'gr'; + } else if (id >= 105) { + href = 'rb'; + } else if (id >= 19) { + href = 'ar&page=2'; + } else { + href = 'ar'; + } + href = `?s=Battle&ss=${href}`; + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: id === 'gr' ? g('option').staminaGrindFest : undefined })) { + $async.logSwitch(arguments); + return; + } + if (hvVersion < 91) { + writeArenaStart(); + $ajax.open(href, `initid=${id === 'gr' ? 1 : id}&inittoken=${token}`); + $async.logSwitch(arguments); + return; + } + const iframe = cE('iframe'); + iframe.src = href; + iframe.style.cssText += "display:none"; + document.body.appendChild(iframe); + await loadIframe(iframe); + iframe.contentWindow.confirm = (message) => true; // 自动点击进入 + iframe.contentWindow.alert = (message) => undefined; + for (let btn of getStartBattleButtons(iframe.contentWindow.document)) { + if (btn.id * 1 !== id && btn.id !== id) { + continue; + } + writeArenaStart(); + btn.onclick(); + await loadIframe(iframe); + goto(); break; - case 'iw': - case 'gr': - title = `${info.title}`; - break; - default: - break; + } + $async.logSwitch(arguments); + } catch (e) { console.error(e) } + } + + // 战斗中// + function onBattleRound() { // 主程序 + 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')); + }; + $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'; + } + 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(`${monsterStateKeys.name}>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 ?? ''}`; } - return isTitle ? title : `${(info?.name ?? ['未知', '未知', 'Unknown'])[lang]}:[${title}]${subtype ?? ''}`; - } - - 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(); - } - 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(); - } - countMonsterHP(); - displayMonsterWeight(); - displayPlayStatePercentage(); - - if (getValue('disabled')) { // 如果禁用 - document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - gE('#hvAABox2>button').innerHTML = '继续繼續Continue'; - return; - } - battle = getValue('battle', true); - g('battle').turn = currentTurn; - battle.turn = currentTurn; - setValue('battle', battle); - killBug(); // 解决 HentaiVerse 可能出现的 bug + const currentTurn = (battle.turn ?? 0) + 1; - 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]]()){ - onStepInDone(); - return; + 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(); } - delete taskList[names[i]]; - } - for (let name in taskList) { - if (taskList[name]()) { - onStepInDone(); + 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(); + } + countMonsterHP(); + displayMonsterWeight(); + displayPlayStatePercentage(); + + if (getValue('disabled')) { // 如果禁用 + document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); + gE('#hvAABox2>button').innerHTML = '继续繼續Continue'; return; } - } - } + battle = getValue('battle', true); + g('battle').turn = currentTurn; + battle.turn = currentTurn; + setValue('battle', battle); - /** - * 按照技能范围,获取包含原目标且范围内最终权重(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 getRangeCenter(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { - if (!range) { - return { id: getMonsterID(target), rank: Number.MAX_SAFE_INTEGER }; - } - const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (g('option').centralExtraRatio / 100) ?? 0 : 0)); - 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 = Number.MAX_SAFE_INTEGER; - for (let i = order - range; i <= order + range; i++) { - if (i < 0 || i >= msTemp.length || msTemp[i].isDead) { - continue; // 无法选中 + killBug(); // 解决 HentaiVerse 可能出现的 bug + + if (g('option').autoFlee && checkCondition(g('option').fleeCondition)) { + gE('1001').click(); + setExitBattleTimeout('Flee'); + return; } - 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; + const 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]]()) { + onStepInDone(); + return; } - // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 - rank += cew; - // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 - rank += forceUseIndex ? -1 : mon.finWeight; + delete taskList[names[i]]; } - if (rank < minRank) { - newOrder = i; - minRank = rank; + for (let name in taskList) { + if (taskList[name]()) { + onStepInDone(); + return; + } } } - return { id: getMonsterID(newOrder), rank: minRank}; - } - function autoPause() { - if (g('option').autoPause && checkCondition(g('option').pauseCondition)) { - pauseChange(); - return true; + function getBuffTurnFromImg(buff, nanValue = NaN) { + if (!buff) { + return 0; + } + buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; + return isNaN(buff) ? nanValue : buff; } - return false; - } - function autoDefend() { - if (g('option').defend && checkCondition(g('option').defendCondition)) { - gE('#ckey_defend').click(); - return true; + function getMonsterID(s) { + if (s.order !== undefined) { + return (s.order + 1) % 10; + } // case is monsterStatus + return (s + 1) % 10; // case is order } - return false; - } - function pauseChange() { // 暂停状态更改 - if (getValue('disabled')) { - if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '暂停暫停Pause'; - } - document.title = getValue('disabled'); - delValue(0); - if (!gE('#navbar')) { // in battle - onBattle(); - } - } else { - if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '继续繼續Continue'; - } - setValue('disabled', document.title); - document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); + function getPlayerBuff(buff) { + return gE(`#pane_effects>img[src*="${buff}"]`); } - } - function stepIn() { - setValue('stepIn', true); - if (getValue('disabled')) { - g('timeNow', time(0)); - pauseChange(); + function getMonster(id) { + return gE(`#mkey_${id}`); } - } - function onStepInDone(){ - if(!getValue('stepIn')){ - return; + function getMonsterBuff(id, buff) { + return gE(`${monsterStateKeys.buffs}>img[src*="${buff}"]`, getMonster(id)); } - delValue('stepIn'); - pauseChange(); - } - 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; + function isOn(id) { // 是否可以施放技能/使用物品 + if (id * 1 > 10000) { // 使用物品 + return gE(`.bti3>div[onmouseover*="(${id})"]`); + } // 施放技能 + return gE(id) && (gE(id).style.opacity * 1 !== 0.5); } - $ajax.open(getValue('lastHref')); - } - function reloader() { - const battleUnresponsive = { - 'Alert': { method: setAlarm }, - 'Reload': { method: goto }, - 'Alt': { method: gotoAlt } - } - function clearBattleUnresponsive(){ - Object.keys(battleUnresponsive).forEach(t=>clearTimeout(battleUnresponsive[t].timeout)); - } - async function onBattleUnresponsive(method) { - if(getValue('disabled')){ - await pauseAsync(_1s); - return await onBattleUnresponsive(); + /** + * 按照技能范围,获取包含原目标且范围内最终权重(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 getRangeCenter(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { + if (!range) { + return { id: getMonsterID(target), rank: Number.MAX_SAFE_INTEGER }; + } + const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (g('option').centralExtraRatio / 100) ?? 0 : 0)); + 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 = Number.MAX_SAFE_INTEGER; + 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; + } + // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 + rank += cew; + // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 + rank += forceUseIndex ? -1 : mon.finWeight; + } + if (rank < minRank) { + newOrder = i; + minRank = rank; + } } - method(); + return { id: getMonsterID(newOrder), rank: minRank }; } - 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(()=>onBattleUnresponsive(battleUnresponsive[t].method), Math.max(1, g('option').battleUnresponsiveTime[t]) * _1s); - } + function autoPause() { + if (g('option').autoPause && checkCondition(g('option').pauseCondition)) { + pauseChange(); + return true; } - 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(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[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); + return false; + } + + function autoDefend() { + if (g('option').defend && checkCondition(g('option').defendCondition)) { + gE('#ckey_defend').click(); + return true; } - if (g('monsterAlive') && !gE('#btcp')) { - clearBattleUnresponsive(); - onBattle(); + return false; + } + + 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 (g('option').dropMonitor) { - dropMonitor(battleLog); + $ajax.open(getValue('lastHref')); + } + + function reloader() { + const battleUnresponsive = { + 'Alert': { method: setAlarm }, + 'Reload': { method: goto }, + 'Alt': { method: gotoAlt } } - if (g('option').recordUsage) { - recordUsage2(); + function clearBattleUnresponsive() { + Object.keys(battleUnresponsive).forEach(t => clearTimeout(battleUnresponsive[t].timeout)); } - onRoundEnd(); - async function onRoundEnd() { - if(getValue('disabled')){ + async function onBattleUnresponsive(method) { + if (getValue('disabled')) { await pauseAsync(_1s); - return await onRoundEnd(); + return await onBattleUnresponsive(); } - if (g('battle').roundNow === g('battle').roundAll) { // Next Round - if (g('monsterAlive') > 0) { // Defeat - SetExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); - } - if (g('battle').roundNow === g('battle').roundAll) { // Victory - SetExitBattleTimeout('Victory'); + method(); + } + + 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(() => onBattleUnresponsive(battleUnresponsive[t].method), Math.max(1, g('option').battleUnresponsiveTime[t]) * _1s); } - } else { - if(g('option').NewRoundWaitTime){ - setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); - } else { - onNewRound(); + } + 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; } } - clearBattleUnresponsive(); - - async function onNewRound(){ try { - if(getValue('disabled')){ + }; + 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(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[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(); + onBattleRound(); + return; + } + if (g('option').dropMonitor) { + dropMonitor(battleLog); + } + if (g('option').recordUsage) { + recordUsage2(); + } + onRoundEnd(); + async function onRoundEnd() { + if (getValue('disabled')) { await pauseAsync(_1s); - return await onNewRound(); + return await onRoundEnd(); } - if(gE('#btcp')?.innerHTML.includes("finishbattle.png")){ - goto(); - return; + if (g('battle').roundNow === g('battle').roundAll) { // Next Round + if (g('monsterAlive') > 0) { // Defeat + setExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); + } + if (g('battle').roundNow === g('battle').roundAll) { // Victory + setExitBattleTimeout('Victory'); + } + } else { + if (g('option').NewRoundWaitTime) { + setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); + } else { + onNewRound(); + } } - 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; + + async function onNewRound() { + try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await onNewRound(); + } + if (gE('#btcp')?.innerHTML.includes("finishbattle.png")) { + goto(); + return; + } + 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; + } + ['#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); + onStepInDone(); + onBattleRound(); + } catch (e) { e => console.error(e) } } - ['#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); - onStepInDone(); - onBattle(); - } catch(e) { e=>console.error(e) }} - } - }; - 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) { + 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; + unsafeWindow = typeof unsafeWindow === 'undefined' ? window : unsafeWindow; + b.open('POST', `${unsafeWindow.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)); } else { setTimeout(() => { b.send(JSON.stringify(a)); - }, delay * (Math.random() * 50 + 50) / 100); + }, 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; + }.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; + } + return a; } - return a; + } else { + window.location.href = window.location.search; } - } else { - window.location.href = window.location.search; } - } - 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(); + return false; + }.toString()}`; + gE('head').appendChild(fakeApiResponse); } - g('monsterAll', gE(monsterStateKeys.obj, 'all').length); - const monsterDead = gE('img[src*="nbardead"]', 'all').length; - g('monsterAlive', g('monsterAll') - monsterDead); - g('bossAll', gE(`${monsterStateKeys.lv}[style^="background"]`, 'all').length); - const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[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); - } - return true; - } - }, + + 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(); } - 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; + g('monsterAll', gE(monsterStateKeys.obj, 'all').length); + const monsterDead = gE('img[src*="nbardead"]', 'all').length; + g('monsterAlive', g('monsterAll') - monsterDead); + g('bossAll', gE(`${monsterStateKeys.lv}[style^="background"]`, 'all').length); + const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[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); + } + return true; + } + }, } - if (type.extra && !type.extra(id)) { - continue; + 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; + } + battle.roundType = name; + break; } - battle.roundType = name; - break; } - } - 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; + 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 roundPrev = battle.roundNow; - - if (battleLog[battleLog.length - 1].textContent.match('Initializing')) { - const monsterStatus = []; - let order = 0; - const monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); - const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>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] = {}; // 重置该名称的数据 + const roundPrev = battle.roundNow; + + if (battleLog[battleLog.length - 1].textContent.match('Initializing')) { + const monsterStatus = []; + let order = 0; + const monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); + const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>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 (monsterMID[mid]) { - monsterDB[name] = JSON.parse(JSON.stringify(monsterMID[mid])); // 将之前备份的mid的数据进行恢复 - delete monsterMID[mid]; + 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; } - 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); + monsterStatus[order] = { + order: order, + hp, + }; + order++; } - if (oldMID !== JSON.stringify(monsterMID)) { - setValue('monsterMID', monsterMID); + if (g('option').cacheMonsterHP) { + if (oldDB !== JSON.stringify(monsterDB)) { + setValue('monsterDB', monsterDB); + } + if (oldMID !== JSON.stringify(monsterMID)) { + setValue('monsterMID', monsterMID); + } } - } - battle.monsterStatus = monsterStatus; + 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 { + 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(monsterStateKeys.lv, 'all').length) { battle.roundNow = 1; battle.roundAll = 1; } - } else if (!battle.monsterStatus || battle.monsterStatus.length !== gE(monsterStateKeys.lv, 'all').length) { - battle.roundNow = 1; - battle.roundAll = 1; - } - - if(roundPrev !== battle.roundNow) { - battle.turn = 0; - } - battle.roundLeft = battle.roundAll - battle.roundNow; - setValue('battle', battle); - - g('skillOTOS', { - OFC: 0, - FRD: 0, - T3: 0, - T2: 0, - T1: 0, - }); - } - 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 (roundPrev !== battle.roundNow) { + battle.turn = 0; } + battle.roundLeft = battle.roundAll - battle.roundNow; + setValue('battle', battle); + + g('skillOTOS', { + OFC: 0, + FRD: 0, + T3: 0, + T2: 0, + T1: 0, + }); } - } - function countMonsterHP() { // 统计敌人血量 - let i, j; - const monsterHp = gE(`${monsterStateKeys.bars}:nth-child(1)`, 'all'); - const monsterMp = gE(`${monsterStateKeys.bars}:nth-child(2)`, 'all'); - const monsterSp = gE(`${monsterStateKeys.bars}:nth-child(3)`, 'all'); - let battle = getValue('battle', true); - const monsterStatus = battle.monsterStatus; - 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:first-child', monsterHp[i]).style.width) / 120 + 1); - monsterStatus[i].mpNow = parseFloat(gE('img:first-child', monsterMp[i]).style.width) / 120; - monsterStatus[i].spNow = parseFloat(gE('img:first-child', monsterSp[i]).style.width) / 120; - hpArray.push(monsterStatus[i].hpNow); + 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'; + } } } - 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', - }, - }; - const monsterBuff = gE(monsterStateKeys.buffs, '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; - const name = gE(`${monsterStateKeys.name}>div>div`, monsterBuff[i].parentNode).innerText; - if (yggdrasilExtraWeight && ('Yggdrasil' === name || '世界树 Yggdrasil' === name)) { // 默认设置下,任何情况都优先击杀群体大量回血的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]; - } - } - monsterStatus[i].finWeight = weight; - } - monsterStatus.sort(objArrSort('finWeight')); - battle.monsterStatus = monsterStatus; - g('battle', battle); - } - function autoRecover() { // 自动回血回魔 - if (!g('option').item) { - return false; - } - if (!g('option').itemOrderValue) { - return false; - } - const name = g('option').itemOrderName.split(','); - const order = g('option').itemOrderValue.split(','); - for (let i = 0; i < name.length; i++) { - let id = order[i]; - if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { - (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); - return true; + function countMonsterHP() { // 统计敌人血量 + let i, j; + const monsterHp = gE(`${monsterStateKeys.bars}:nth-child(1)`, 'all'); + const monsterMp = gE(`${monsterStateKeys.bars}:nth-child(2)`, 'all'); + const monsterSp = gE(`${monsterStateKeys.bars}:nth-child(3)`, 'all'); + let battle = getValue('battle', true); + const monsterStatus = battle.monsterStatus; + 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:first-child', monsterHp[i]).style.width) / 120 + 1); + monsterStatus[i].mpNow = parseFloat(gE('img:first-child', monsterMp[i]).style.width) / 120; + monsterStatus[i].spNow = parseFloat(gE('img:first-child', monsterSp[i]).style.width) / 120; + hpArray.push(monsterStatus[i].hpNow); + } } - } - return false; - } + battle.monsterStatus = monsterStatus; - function useScroll() { // 自动使用卷轴 - if (!g('option').scrollSwitch) { - return false; - } - if (!g('option').scroll) { - return false; - } - if (!g('option').scrollRoundType) { - return false; - } - if (!g('option').scrollRoundType[g('battle').roundType]) { - return false; - } - if (!checkCondition(g('option').scrollCondition)) { - 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', - }, - }; - const scrollFirst = (g('option').scrollFirst) ? '_scroll' : ''; - for (const i in scrollLib) { - if (!g('option').scroll[i]) { - continue; - } - if(!gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`)){ - continue; - } - if(!checkCondition(g('option')[`scroll${i}Condition`])){ - continue; - } - for (let j = 1; j <= scrollLib[i].mult; j++) { - if (getPlayerBuff(scrollLib[i][`img${j}`]+scrollFirst)) { + 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', + }, + }; + const monsterBuff = gE(monsterStateKeys.buffs, '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; } - gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`).click(); - return true; + let weight = baseHpRatio * Math.log10(monsterStatus[i].hpNow / hpMin); // > 0 生命越低权重越低优先级越高 + monsterStatus[i].hpWeight = weight; + const name = gE(`${monsterStateKeys.name}>div>div`, monsterBuff[i].parentNode).innerText; + if (yggdrasilExtraWeight && ('Yggdrasil' === name || '世界树 Yggdrasil' === name)) { // 默认设置下,任何情况都优先击杀群体大量回血的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]; + } + } + monsterStatus[i].finWeight = weight; } + monsterStatus.sort(objArrSort('finWeight')); + battle.monsterStatus = monsterStatus; + g('battle', battle); } - return false; - } - function useChannelSkill() { // 自动施法Channel技能 - if (!g('option').channelSkillSwitch) { + function autoRecover() { // 自动回血回魔 + if (!g('option').item) { + return false; + } + if (!g('option').itemOrderValue) { + return false; + } + const name = g('option').itemOrderName.split(','); + const order = g('option').itemOrderValue.split(','); + for (let i = 0; i < name.length; i++) { + let id = order[i]; + if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { + (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); + return true; + } + } return false; } - if (!g('option').channelSkill) { + + function useScroll() { // 自动使用卷轴 + if (!g('option').scrollSwitch) { + return false; + } + if (!g('option').scroll) { + return false; + } + if (!g('option').scrollRoundType) { + return false; + } + if (!g('option').scrollRoundType[g('battle').roundType]) { + return false; + } + if (!checkCondition(g('option').scrollCondition)) { + 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', + }, + }; + const scrollFirst = (g('option').scrollFirst) ? '_scroll' : ''; + for (const i in scrollLib) { + if (!g('option').scroll[i]) { + continue; + } + if (!gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`)) { + continue; + } + if (!checkCondition(g('option')[`scroll${i}Condition`])) { + continue; + } + for (let j = 1; j <= scrollLib[i].mult; j++) { + if (getPlayerBuff(scrollLib[i][`img${j}`] + scrollFirst)) { + continue; + } + gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`).click(); + return true; + } + } return false; } - if (!getPlayerBuff('channeling')) { + + function useChannelSkill() { // 自动施法Channel技能 + if (!g('option').channelSkillSwitch) { + return false; + } + if (!g('option').channelSkill) { + return false; + } + if (!getPlayerBuff('channeling')) { + 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', + }, + }; + let i; let + 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] && !getPlayerBuff(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 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 = getBuffTurnFromImg(buff[i]); + if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { + continue; + } else { + if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('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; } - 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', - }, - }; - let i; let - j; - const skillPack = g('option').buffSkillOrderValue.split(','); - if (g('option').channelSkill) { + + 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', + }, + }; + if (!g('option').buffSkillSwitch) { + return false; + } + if (!g('option').buffSkill) { + return false; + } + if (!checkCondition(g('option').buffSkillCondition)) { + return false; + } + let i; + const skillPack = g('option').buffSkillOrderValue.split(','); for (i = 0; i < skillPack.length; i++) { - j = skillPack[i]; - if (g('option').channelSkill[j] && !getPlayerBuff(skillLib[j].img) && isOn(skillLib[j].id)) { - gE(skillLib[j].id).click(); + let buff = skillPack[i]; + if (g('option').buffSkill[buff] && checkCondition(g('option')[`buffSkill${buff}Condition`]) && !getPlayerBuff(skillLib[buff].img) && isOn(skillLib[buff].id)) { + gE(skillLib[buff].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(); + 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', + }, + }; + for (i in draughtPack) { + if (!getPlayerBuff(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; } - 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 = getBuffTurnFromImg(buff[i]); - if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { - continue; - } else { - if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('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; - } - } + + function useInfusions() { // 自动使用魔药 + if (g('attackStatus') === 0) { + return false; + } + if (!g('option').infusionSwitch) { + return false; + } + if (!checkCondition(g('option').infusionCondition)) { + return false; } - } - return false; - } - 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', - }, - }; - if (!g('option').buffSkillSwitch) { - return false; - } - if (!g('option').buffSkill) { - return false; - } - if (!checkCondition(g('option').buffSkillCondition)) { - 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`]) && !getPlayerBuff(skillLib[buff].img) && isOn(skillLib[buff].id)) { - gE(skillLib[buff].id).click(); + const infusionLib = [null, { + id: 12101, + img: 'fireinfusion', + }, { + 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})"]`) && !getPlayerBuff(infusionLib[[g('attackStatus')]].img)) { + gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`).click(); return true; } + return false; } - 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', - }, - }; - for (i in draughtPack) { - if (!getPlayerBuff(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(); + + function autoFocus() { + if (g('option').focus && checkCondition(g('option').focusCondition)) { + gE('#ckey_focus').click(); return true; } - } - return false; - } - - function useInfusions() { // 自动使用魔药 - if (g('attackStatus') === 0) { return false; } - if (!g('option').infusionSwitch) { - return false; - } - if (!checkCondition(g('option').infusionCondition)) { - return false; - } - - const infusionLib = [null, { - id: 12101, - img: 'fireinfusion', - }, { - 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})"]`) && !getPlayerBuff(infusionLib[[g('attackStatus')]].img)) { - gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`).click(); - return true; - } - return false; - } - function autoFocus() { - if (g('option').focus && checkCondition(g('option').focusCondition)) { - gE('#ckey_focus').click(); - return true; - } - return false; - } - - function autoSS() { - const textSP = gE('#vrs') ?? gE('#dvrs'); - const spValue = textSP.childNodes[0].textContent * 1; - if (spValue <= 1){ + function autoSS() { + const textSP = gE('#vrs') ?? gE('#dvrs'); + const spValue = textSP.childNodes[0].textContent * 1; + if (spValue <= 1) { + return false; + } + 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; + } return false; } - 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; - } - return false; - } - /** - * INNAT / WEAPON SKILLS - * - * 优先释放先天和武器技能 - */ - function autoSkill() { - if (!g('option').skillSwitch) { - return false; - } - if (!gE('#ckey_spirit[src*="spirit_a"]')) { + /** + * INNAT / WEAPON SKILLS + * + * 优先释放先天和武器技能 + */ + function autoSkill() { + if (!g('option').skillSwitch) { + return false; + } + if (!gE('#ckey_spirit[src*="spirit_a"]')) { + return false; + } + + const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); + const fightStyle = g('fightingStyle'); + const skillLib = { + OFC: '1111', + FRD: '1101', + T3: fightStyle ? `2${fightStyle}03` : undefined, + T2: fightStyle ? `2${fightStyle}02` : undefined, + T1: fightStyle ? `2${fightStyle}01` : undefined, + }; + const skillOC = { // default as 2 + '1101': 4, + '1111': 8, + '2101': 4, + '2201': 1, + '2203': 4, + '2403': 3 + } + const rangeSkills = { + 2101: 2, + 2403: 2, + 1111: 4, + } + for (let i in skillOrder) { + let skill = skillOrder[i]; + if (!skill || !g('option').skill[skill]) { + return; + } + let id = skillLib[skill]; + if (!isOn(id)) { + continue; + } + if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { + continue; + } + if (g('option').skillOTOS && g('option').skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { + continue; + } + g('skillOTOS')[skill]++; + let target = checkCondition(g('option')[`skill${skill}Condition`], g('battle').monsterStatus); + if (!target) { + continue; + } + gE(id).click(); + const range = id in rangeSkills ? rangeSkills[id] : 0; + getMonster(getRangeCenter(target, range).id).click(); + return true; + } return false; } - const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); - const fightStyle = g('fightingStyle'); - const skillLib = { - OFC: '1111', - FRD: '1101', - T3: fightStyle ? `2${fightStyle}03` : undefined, - T2: fightStyle ? `2${fightStyle}02` : undefined, - T1: fightStyle ? `2${fightStyle}01` : undefined, - }; - const skillOC = { // default as 2 - '1101': 4, - '1111': 8, - '2101': 4, - '2201': 1, - '2203': 4, - '2403': 3 - } - const rangeSkills = { - 2101: 2, - 2403: 2, - 1111: 4, - } - for (let i in skillOrder) { - let skill = skillOrder[i]; - if(!skill || !g('option').skill[skill]){ - return; - } - let id = skillLib[skill]; - if (!isOn(id)) { - continue; + function useDeSkill() { // 自动施法DEBUFF技能 + if (!g('option').debuffSkillSwitch) { // 总开关是否开启 + return false; } - if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { - continue; + // 先处理特殊的 “先给全体上buff” + let skillPack = ['We', 'Im']; + for (let i = 0; i < skillPack.length; i++) { + if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 + if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`], g('battle').monsterStatus)) { // 检查条件 + continue; + } + } + skillPack.splice(i, 1); + i--; } - if (g('option').skillOTOS && g('option').skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { - continue; + 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(',')); } - g('skillOTOS')[skill]++; - let target = checkCondition(g('option')[`skill${skill}Condition`], g('battle').monsterStatus); - if(!target){ - continue; + for (let i in skillPack) { + let buff = skillPack[i]; + if (i >= toAllCount) { // 非先全体 + if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`], g('battle').monsterStatus)) { // 检查条件 + continue; + } + } + let succeed = useDebuffSkill(buff, i < toAllCount); + // 前 toAllCount 个都是先给全体上的 + if (succeed) { + return true; + } } - gE(id).click(); - const range = id in rangeSkills ? rangeSkills[id] : 0; - getMonster(getRangeCenter(target, range).id).click(); - return true; - } - return false; - } - - function useDeSkill() { // 自动施法DEBUFF技能 - if (!g('option').debuffSkillSwitch) { // 总开关是否开启 return false; } - // 先处理特殊的 “先给全体上buff” - let skillPack = ['We', 'Im']; - for (let i = 0; i < skillPack.length; i++) { - if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 - if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`], g('battle').monsterStatus)) { // 检查条件 + + 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', + }, + }; + if (!isOn(skillLib[buff].id)) { // 技能不可用 + return false; + } + // 获取范围 + let range = 0; + let ab; + const ability = getValue('ability', true); + for (ab in skillLib[buff].range) { + const ranges = skillLib[buff].range[ab]; + if (!ranges) { continue; } + if (ability) { + range = ranges[ability[ab].level]; + } + break; } - 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(',')); - } - for (let i in skillPack) { - let buff = skillPack[i]; - if (i >= toAllCount) { // 非先全体 - if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`], g('battle').monsterStatus)) { // 检查条件 + + // 获取目标 + let isDebuffed = (target) => getMonsterBuff(getMonsterID(target), skillLib[buff].img); + let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; + let monsterStatus = g('battle').monsterStatus; + if (debuffByIndex) { + monsterStatus = JSON.parse(JSON.stringify(monsterStatus)); + monsterStatus.sort(objArrSort('order')); + } + let max = isAll ? monsterStatus.length : 1; + + let id; + let minRank = Number.MAX_SAFE_INTEGER; + for (let i = 0; i < max; i++) { + let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; + target = checkCondition(g('option')[`debuffSkill${buff}${isAll ? 'all' : ''}Condition`], [target]); + if (!target || target.isDead || isDebuffed(target)) { continue; } + const center = getRangeCenter(target, range, false, isDebuffed, debuffByIndex); + if (!id || center.rank < minRank) { + minRank = center.rank; + id = center.id; + if (!isAll) { + // 只有覆盖全体才需要遍历全部 + break; + } + } } - let succeed = useDebuffSkill(buff, i < toAllCount); - // 前 toAllCount 个都是先给全体上的 - if (succeed) { + if (id === undefined) { + return false; + } + const imgs = gE('img', 'all', gE(monsterStateKeys.buffs, getMonster(id))); + // 已有buff小于6个 + // 未开启debuff失败警告 + // buff剩余持续时间大于等于警报时间 + if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { + gE(skillLib[buff].id).click(); + getMonster(id).click(); return true; } - } - return 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', - }, - }; - if (!isOn(skillLib[buff].id)) { // 技能不可用 - return false; - } - // 获取范围 - let range = 0; - let ab; - const ability = getValue('ability', true); - for (ab in skillLib[buff].range) { - const ranges = skillLib[buff].range[ab]; - if (!ranges) { - continue; - } - if(ability){ - range = ranges[ability[ab].level]; - } - break; - } - // 获取目标 - let isDebuffed = (target) => getMonsterBuff(getMonsterID(target), skillLib[buff].img); - let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; - let monsterStatus = g('battle').monsterStatus; - if (debuffByIndex){ - monsterStatus = JSON.parse(JSON.stringify(monsterStatus)); - monsterStatus.sort(objArrSort('order')); - } - let max = isAll ? monsterStatus.length : 1; - - let id; - let minRank = Number.MAX_SAFE_INTEGER; - for (let i = 0; i < max; i++) { - let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; - target = checkCondition(g('option')[`debuffSkill${buff}${isAll ? 'all' : ''}Condition`], [target]); - if (!target || target.isDead || isDebuffed(target)) { - continue; - } - const center = getRangeCenter(target, range, false, isDebuffed, debuffByIndex); - if(!id || center.rank < minRank){ - minRank = center.rank; - id = center.id; - if(!isAll){ - // 只有覆盖全体才需要遍历全部 - break; - } - } - } - if (id === undefined) { - return false; - } - const imgs = gE('img', 'all', gE(monsterStateKeys.buffs, getMonster(id))); - // 已有buff小于6个 - // 未开启debuff失败警告 - // buff剩余持续时间大于等于警报时间 - if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { - gE(skillLib[buff].id).click(); - getMonster(id).click(); + _alert(0, '无法正常施放DEBUFF技能,请尝试手动打怪', '無法正常施放DEBUFF技能,請嘗試手動打怪', 'Can not cast de-skills normally, continue the script?\nPlease try attack manually.'); + pauseChange(); return true; } - _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. 目标怪在魔力合流状态中 @@ -4237,425 +4280,426 @@ 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'); - let target = g('battle').monsterStatus[0]; - if (attackStatus === 0) { - if (g('fightingStyle') === '1') { // 二天一流 - range = 1; - } - } else { - if (g('option').etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) && checkCondition(g('option').etherTapCondition)) { - `pass` + 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'); + let target = g('battle').monsterStatus[0]; + if (attackStatus === 0) { + if (g('fightingStyle') === '1') { // 二天一流 + range = 1; + } } else { - const skill = 1 * (() => { - let lv = 3; - for (let condition of [g('option').highSkillCondition, g('option').middleSkillCondition, undefined]) { - let id = `1${attackStatus}${lv--}`; - target = checkCondition(condition, g('battle').monsterStatus); - if (target && isOn(id)){ - return id; + if (g('option').etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`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--}`; + target = checkCondition(condition, g('battle').monsterStatus); + if (target && isOn(id)) { + return id; + } } + })(); + gE(skill)?.click(); + for (let ab in updateAbility) { + const ranges = updateAbility[ab][skill]; + if (!ranges) { + continue; + } + const ability = getValue('ability', true); + if (ability) { + range = ranges[ability[ab].level]; + } + break; } - })(); - gE(skill)?.click(); - for (let ab in updateAbility) { - const ranges = updateAbility[ab][skill]; - if (!ranges) { - continue; - } - const ability = getValue('ability', true); - if(ability){ - range = ranges[ability[ab].level]; - } - break; } } + if (!target || target.isDead) { + return false; + } + getMonster(getRangeCenter(target, range, !attackStatus).id).click(); + return true; } - if(!target || target.isDead){ - return false; - } - getMonster(getRangeCenter(target, range, !attackStatus).id).click(); - return true; - } - function getHPFromMonsterDB(mdb, name, lv) { - let hp = (mdb && mdb[name]) ? mdb[name][lv] : undefined; - // TODO: 根据lv模糊推测 - return hp; - } + 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'); - const monsterStatus = []; - const monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); - const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>div>div`, 'all')).map(monster => monster.innerText); - const monsterDB = getValue('monsterDB', true); - gE(monsterStateKeys.lv, 'all').forEach((monster, order) => { - monsterStatus.push({ - order: order, - hp: getHPFromMonsterDB(monsterDB, monsterNames[order], monsterLvs[order]) ?? ((monster.style.background === '') ? 1000 : 100000), + function fixMonsterStatus() { // 修复monsterStatus + // document.title = _alert(-1, 'monsterStatus错误,正在尝试修复', 'monsterStatus錯誤,正在嘗試修復', 'monsterStatus Error, trying to fix'); + const monsterStatus = []; + const monsterNames = Array.from(gE(`${monsterStateKeys.name}>div>div`, 'all')).map(monster => monster.innerText); + const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>div>div`, 'all')).map(monster => monster.innerText); + const monsterDB = getValue('monsterDB', true); + gE(monsterStateKeys.lv, '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); - } + const battle = getValue('battle', true); + battle.monsterStatus = monsterStatus; + setValue('battle', battle); + } - function displayMonsterWeight() { + function displayMonsterWeight() { - const status = g('battle').monsterStatus.filter(m => !m.isDead); - let rank = 0; + const status = g('battle').monsterStatus.filter(m => !m.isDead); + let rank = 0; - const weights = []; - status.forEach(s => { - if (weights.indexOf(s.finWeight) !== -1) { - return; + 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; + }); } - 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 (!getMonster(id) || !gE(monsterStateKeys.name, getMonster(id))) { - return; - } - if (g('option').displayWeightBackground) { - if (g('option').weightBackground) { - let colorText = colorTextList[rank]; - let remainAttemp = 10; // 避免无穷递归 - while(remainAttemp > 0 && colorText && colorText.indexOf(``, colorTextList[i]); + const id = getMonsterID(s); + if (!getMonster(id) || !gE(monsterStateKeys.name, getMonster(id))) { + 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--; } - remainAttemp--; - } - try { - colorText = eval(colorText.replace('', rank).replace('', weights.length)); - } - catch { + try { + colorText = eval(colorText.replace('', rank).replace('', weights.length)); + } + catch { + } + getMonster(id).style.cssText += `background: ${colorText};`; } - getMonster(id).style.cssText += `background: ${colorText};`; } - } - gE(monsterStateKeys.name, getMonster(id)).style.cssText += 'display: flex; flex-direction: row;' - if (g('option').displayWeight) { - gE(monsterStateKeys.name, getMonster(id)).innerHTML += `
      [${rank}|-${-rank + weights.length - 1}|${s.finWeight.toPrecision(s.finWeight >= 1 ? 5 : 4)}]
      `; - } - }); - } + gE(monsterStateKeys.name, getMonster(id)).style.cssText += 'display: flex; flex-direction: row;' + if (g('option').displayWeight) { + gE(monsterStateKeys.name, getMonster(id)).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') ?? gE('#dvrhb'); - 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()}%]`; - text.style.cssText += textOC ? ` + 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') ?? gE('#dvrhb'); + 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()}%]`; + text.style.cssText += textOC ? ` display: grid; grid-template-columns: 1fr 1fr; width: 120px; `: ""; - const percentageDiv = gE('div', text); - const style = ` + const percentageDiv = gE('div', text); + const style = ` position: relative; top: ${textOC ? 0 : text === textHP ? -16.67 : -16}px; right: ${textOC ? -10 : text === textMP ? -60 : text === textSP ? 40 : -100}px; filter: brightness(0.2); text-align: left; ` - if (percentageDiv) { - percentageDiv.innerHTML = inner; - percentageDiv.style.cssText = style; - return; - } - text.innerHTML += `
      ${inner}
      ` - }); - } + if (percentageDiv) { + percentageDiv.innerHTML = inner; + percentageDiv.style.cssText = style; + return; + } + text.innerHTML += `
      ${inner}
      ` + }); + } - function dropMonitor(battleLog) { // 掉落监测 - const drop = getValue('drop', true) || { - '#startTime': time(3), - '#EXP': 0, - '#Credit': 0, - }; - let item; let name; let amount; let - 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; - } - } - } else if (item.style.color === 'rgb(186, 5, 180)') { - regexp = name.match(/^(\d+)x (Crystal of \w+)$/); + function dropMonitor(battleLog) { // 掉落监测 + const drop = getValue('drop', true) || { + '#startTime': time(3), + '#EXP': 0, + '#Credit': 0, + }; + let item; let name; let amount; let + 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) { - name = regexp[2]; - amount = regexp[1] * 1; + 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 { - name = name.match(/^(Crystal of \w+)$/)[1]; - amount = 1; + drop[name] = (name in drop) ? drop[name] + 1 : 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'); - } else { - setValue('drop', drop); - } - } - - 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: { // 熟练度 - }, - }; - let text; let magic; let point; let - reg; - const battle = g('battle'); - if (g('monsterAlive') === 0) { - stats.self._turn += battle.turn; - stats.self._round += 1; - if (battle.roundNow === battle.roundAll) { - stats.self._battle += 1; + 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'); + } else { + setValue('drop', drop); + } + } + + 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: { // 熟练度 + }, + }; + let text; let magic; let point; let + reg; + const battle = g('battle'); + if (g('monsterAlive') === 0) { + stats.self._turn += battle.turn; + stats.self._round += 1; + if (battle.roundNow === battle.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; - } else if (parm.mode === 'items') { - 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; - } - const debug = false; - let log = false; - for (let i = 0; i < parm.log.length; i++) { - if (parm.log[i].className === 'tls') { - break; + 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; + } else if (parm.mode === 'items') { + 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; } - text = parm.log[i].textContent; - if (debug) { - console.log(text); - } - if (reg = matchDamageInfoFromLogText(text)) { - 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); + const debug = false; + let log = false; + for (let i = 0; i < parm.log.length; i++) { + if (parm.log[i].className === 'tls') { + break; } - if (text.match(/You ((partially )*(evade|parry|block)( and )*)+ the attack/)){ + text = parm.log[i].textContent; + if (debug) { + console.log(text); + } + if (reg = matchDamageInfoFromLogText(text)) { + 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 (text.match(/You ((partially )*(evade|parry|block)( and )*)+ the attack/)) { + stats.self.evade++; + } + } 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 = matchDamageInfoFromLogText(parm.log[i - 1].textContent, false)[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 = matchDamageInfoFromLogText(parm.log[i - 1].textContent, false)[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(); + } + setValue('stats', stats); } - if (debug && log) { - console.table(stats); - pauseChange(); - } - setValue('stats', stats); - } - function matchDamageInfoFromLogText(text, isSkipUnmatched=true){ - const regList = [ - /you for (\d+) (\w+) damage/, - /and take (\d+) (\w+) damage/, - /You take (\d+) (\w+) damage/, - /hits you, causing (\d+) points of (\w+) damage/ - ]; - for (let reg of regList){ - let match = text.match(reg); - if (!match) { - continue; - } - return match; - } - if(!isSkipUnmatched){ - console.log(`Can't match damage info from: `, text); + function matchDamageInfoFromLogText(text, isSkipUnmatched = true) { + const regList = [ + /you for (\d+) (\w+) damage/, + /and take (\d+) (\w+) damage/, + /You take (\d+) (\w+) damage/, + /hits you, causing (\d+) points of (\w+) damage/ + ]; + for (let reg of regList) { + let match = text.match(reg); + if (!match) { + continue; + } + return match; + } + if (!isSkipUnmatched) { + console.log(`Can't match damage info from: `, text); + } } - } - 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'); - } else { - setValue('stats', stats); + 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'); + } else { + setValue('stats', stats); + } } + } catch (e) { + console.log(e); + document.title = e; } -} catch (e) { - console.log(e); - document.title = e; -} +})(); From 422b5e1d1467825ea8fc0f2eea71ad9125110ba2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 10 Nov 2025 05:43:02 +0800 Subject: [PATCH 076/216] 2.90.36 use fetch instead of iframe --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 149 +++++++----------- 1 file changed, 54 insertions(+), 95 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 666ecf7b..9465c714 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.35 +// @version 2.90.36 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -449,15 +449,6 @@ return document.createElement(name); } - function loadIframe(iframe) { - return new Promise((resolve, reject) => { - // 监听iframe的load事件 - iframe.onload = () => { - resolve("Iframe loaded successfully"); - }; - }); - } - function $doc(h) { const doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = h; @@ -521,7 +512,7 @@ option[itemArray[0]][itemArray[1]] ??= option[aliasDict[key]]; } } - // 迁移旧版本最后的慈悲条件为可配置条件 + // 迁移旧版本最后的慈悲条件为可配置条件 const mercifulBlowCondition = option.skillT3Condition ?? { "0": [] }; const size = Object.keys(mercifulBlowCondition).length; if (option.mercifulBlowStrict) { @@ -1283,8 +1274,7 @@ } const target = (e.target.tagName === 'SPAN') ? e.target : e.target.parentNode; const name = target.getAttribute('name'); - let i; let - _html; + let i, _html; if (name === 'Drop') { // 掉落监测 let drop = getValue('drop', true) || {}; const dropOld = getValue('dropOld', true) || []; @@ -1732,8 +1722,7 @@ version: g('version'), }; let inputs = gE('input,select', 'all', optionBox); - let itemName; let itemArray; let itemValue; let - i; + let itemName, itemArray, itemValue, i; for (i = 0; i < inputs.length; i++) { if (inputs[i].className === 'hvAADebug') { continue; @@ -1809,12 +1798,10 @@ optionBox.style.display = 'none'; }; if (g('option')) { - let i; let j; let - k; + let i, j, k; const _option = g('option'); const inputs = gE('input,select', 'all', optionBox); - let itemName; let itemArray; let itemValue; let - _html; + let itemName, itemArray, itemValue, _html; for (i = 0; i < inputs.length; i++) { if (inputs[i].className === 'hvAADebug') { continue; @@ -2122,7 +2109,7 @@ } function checkCondition(parms, targets = undefined) { - let i; let j; let k; let target; + let i, j, k, target; targets ??= [g('battle').monsterStatus[0]]; if (typeof parms === 'undefined') { @@ -2409,7 +2396,7 @@ dict[e.href ?? `newDawn`] = e; } try { - // if is latest version data + // if is latest version data for (let e of encounter) { } } catch { // if old versions @@ -2580,42 +2567,33 @@ $async.logSwitch(arguments); let eqps; if (hvVersion < 91) { - const doc = $doc(await $ajax.fetch('?s=Forge&ss=re')); + const href = `?s=Forge&ss=re`; + const doc = $doc(await $ajax.fetch(href)); const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); - 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); + 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; + } + const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); + return gE('.messagebox_error', )?.innerText ? undefined : id; + } catch (e) { console.error(e) } })); } else { - const doc = $doc(await $ajax.fetch('?s=Bazaar&ss=am&screen=repair&filter=equipped')); - eqps = (await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { - try { - const id = eqp.getAttribute('onmouseover').match(/hover_equip\((\d+)\)/)[1]; - const condition = 1 * gE('td:last-child', eqp).childNodes[0].textContent.replace('%', ''); - if (condition > g('option').repairValue) { - return; - } - const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped&eqids[]=${id}`; - const iframe = cE('iframe'); - iframe.src = href; - iframe.style.cssText += "display:none" - document.body.appendChild(iframe); - await loadIframe(iframe); - const doc = iframe.contentWindow.document; - const disabled = gE('#equipsubmit', doc).getAttribute('disabled'); - if (disabled !== undefined && disabled !== null) { - return id; - } - gE('#equipform', doc).submit(); - } catch (e) { console.error(e) } - }))).filter(e => e); + const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped`; + const doc = $doc(await $ajax.fetch(href)); + const token = gE('#equipform>input[name="postoken"]', doc).value; + eqps = await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { + const id = gE('input', eqp).value; + const condition = 1 * gE('td:last-child', eqp).textContent.replace('%', ''); + if (condition > g('option').repairValue) { + return; + } + const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); + return gE(`#e${id}`, after) ? id : undefined; + } catch (e) { console.error(e) } })); } + eqps = eqps.filter(e=>e); if (eqps.length) { console.log('eqps need repair: ', eqps); document.title = `[R!]` + document.title; @@ -2883,28 +2861,12 @@ return; } if (hvVersion < 91) { - writeArenaStart(); - $ajax.open(href, `initid=${id === 'gr' ? 1 : id}&inittoken=${token}`); - $async.logSwitch(arguments); - return; - } - const iframe = cE('iframe'); - iframe.src = href; - iframe.style.cssText += "display:none"; - document.body.appendChild(iframe); - await loadIframe(iframe); - iframe.contentWindow.confirm = (message) => true; // 自动点击进入 - iframe.contentWindow.alert = (message) => undefined; - for (let btn of getStartBattleButtons(iframe.contentWindow.document)) { - if (btn.id * 1 !== id && btn.id !== id) { - continue; - } - writeArenaStart(); - btn.onclick(); - await loadIframe(iframe); - goto(); - break; + token = `&inittoken=${token}`; + } else { + token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(href))).value}`; } + writeArenaStart(); + $ajax.open(href, `initid=${id === 'gr' ? 1 : id}${token}`); $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -3194,8 +3156,8 @@ let cew = j === i ? centralExtraWeight : 0; // cew <= 0, 增加未命中权重,降低命中权重 let mon = msTemp[j]; if (j < 0 || j >= msTemp.length // 超出范围 - || mon.isDead // 死亡目标 - || (excludeCondition && excludeCondition(mon))) { // 特殊排除判定 + || mon.isDead // 死亡目标 + || (excludeCondition && excludeCondition(mon))) { // 特殊排除判定 rank += unreachableWeight - cew; continue; } @@ -3258,7 +3220,7 @@ method(); } - let obj; let a; let cost; + let obj, a, cost; const eventStart = cE('a'); eventStart.id = 'eventStart'; eventStart.onclick = function () { @@ -3851,8 +3813,7 @@ img: 'absorb', }, }; - let i; let - j; + let i, j; const skillPack = g('option').buffSkillOrderValue.split(','); if (g('option').channelSkill) { for (i = 0; i < skillPack.length; i++) { @@ -4011,10 +3972,10 @@ return false; } - const infusionLib = [null, { - id: 12101, - img: 'fireinfusion', - }, { + const infusionLib = [ null, { + id: 12101, + img: 'fireinfusion', + }, { id: 12201, img: 'coldinfusion', }, { @@ -4272,13 +4233,13 @@ } function attack() { // 自动打怪 - // 如果 - // 1. 开启了自动以太水龙头 - // 2. 目标怪在魔力合流状态中 - // 3. 未获得以太水龙头*2 或 *1 - // 4. 满足条件 - // 使用物理普通攻击,跳过Offensive Magic - // 否则按照属性攻击模式释放Spell > Offensive Magic + // 如果 + // 1. 开启了自动以太水龙头 + // 2. 目标怪在魔力合流状态中 + // 3. 未获得以太水龙头*2 或 *1 + // 4. 满足条件 + // 使用物理普通攻击,跳过Offensive Magic + // 否则按照属性攻击模式释放Spell > Offensive Magic const updateAbility = { 4301: { //火 @@ -4472,8 +4433,7 @@ '#EXP': 0, '#Credit': 0, }; - let item; let name; let amount; let - regexp; + let item, name, amount, 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)/); @@ -4561,8 +4521,7 @@ proficiency: { // 熟练度 }, }; - let text; let magic; let point; let - reg; + let text, magic, point, reg; const battle = g('battle'); if (g('monsterAlive') === 0) { stats.self._turn += battle.turn; From dd7c879739cb4149facbae1558cd7ef23d217375 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 10 Nov 2025 23:34:35 +0800 Subject: [PATCH 077/216] =?UTF-8?q?2.90.37=20=E6=95=B0=E6=8D=AE=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=A2=9E=E5=8A=A0filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 402 +++++++++++------- 1 file changed, 251 insertions(+), 151 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9465c714..e38de762 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.36 +// @version 2.90.37 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1233,9 +1233,46 @@ '
      记录装备的最低品质記錄裝備的最低品質Minimum drop quality:
      ', '
      ', - '
      ', - ' 数据记录數據記錄Usage Tracking', - '
      ', + '
      ', + '
      ', + '
      自身自身Self', + '
      ' , + '
      Turns
      ', + '
      Rounds
      ', + '
      Battle
      ', + '
      Monster
      ', + '
      Boss
      ', + '
      闪避閃避Evade
      ', + '
      未命中未命中Miss
      ', + '
      集中集中Focus
      ', + '
      MP总消耗總消耗Cost
      ', + '
      OC总消耗總消耗Cost
      ', + '
      ', + '
      ', + '
      操作操作Actions', + '
      ' , + '
      回复 (总量)回复 (總量)Restore (Amount)
      ', + '
      物品 (次数)物品 (次數)Items (Count)
      ', + '
      技能 (次数)技能 (次數)Magic (Count)
      ', + '
      伤害 (总量)傷害 (總量)Damage (Amount)
      ', + '
      熟练度 (总量)熟練度 (總量)Proficiency (Amount)
      ', + '
      ', + '
      ', + '
      受伤 (总量)受傷 (總量)Hurt (Amount)', + '
      ' , + '
      平均平均Avg
      ', + '
      次数次數Count
      ', + '
      总量總量Total
      ', + '
      法术平均法術平均Magic Avg
      ', + '
      法术次数法術次數Magic Count
      ', + '
      法术总量法術總量Magic Total
      ', + '
      物理平均物理平均Physical Avg
      ', + '
      物理次数物理次數Physical Count
      ', + '
      物理总量物理總量Physical Total
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      ', '
      当前状况當前狀況Current status: ', @@ -1320,13 +1357,13 @@ let stats = getValue('stats', true) || {}; const statsOld = getValue('statsOld', true) || []; const translation = { - self: '自身 (次数)自身 (次數)Self (Frequency)', + self: '自身自身Self', restore: '回复 (总量)回复 (總量)Restore (Amount)', items: '物品 (次数)物品 (次數)Items (Frequency)', magic: '技能 (次数)技能 (次數)Magic (Frequency)', damage: '伤害 (总量)傷害 (總量)Damage (Amount)', - hurt: '受伤 (总量)受傷 (總量)Loss (Amount)', proficiency: '熟练度 (总量)熟練度 (總量)Proficiency (Amount)', + hurt: '受伤 (总量)受傷 (總量)Loss (Amount)', }; _html = ''; if (statsOld.length === 0 || (statsOld.length === 1 && !getValue('stats', true))) { @@ -2613,7 +2650,7 @@ return; } const staminaChecked = checkStamina(condition.staminaLow, condition.staminaCost); - console.log("staminaChecked", condition.staminaLow, condition.staminaCost, staminaChecked); + console.log(`stamina check done:\n${condition.staminaLow ? `low: ${condition.staminaLow}\n` : ''}${condition.staminaCost ? `cost: ${condition.staminaCost}\n` : ''}status: ${staminaChecked === 1 ? 'succeed' : staminaChecked === 0 ? 'failed' : 'failed with nature recover'}`); if (staminaChecked === 1) { // succeed return true; } @@ -3973,24 +4010,24 @@ } const infusionLib = [ null, { - id: 12101, - img: 'fireinfusion', - }, { - id: 12201, - img: 'coldinfusion', - }, { - id: 12301, - img: 'elecinfusion', - }, { - id: 12401, - img: 'windinfusion', - }, { - id: 12501, - img: 'holyinfusion', - }, { - id: 12601, - img: 'darkinfusion', - }]; + id: 12101, + img: 'fireinfusion', + }, { + 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})"]`) && !getPlayerBuff(infusionLib[[g('attackStatus')]].img)) { gE(`.bti3>div[onmouseover*="(${infusionLib[g('attackStatus')].id})"]`).click(); return true; @@ -4352,10 +4389,11 @@ const sec = Math.max(1, weights.length - 1); const max = 360 * 2 / 3; const colorTextList = []; - if (g('option').weightBackground) { + const weightBG = g('option').weightBackground + if (weightBG) { status.forEach(s => { const rank = weights.indexOf(s.finWeight); - let colorText = (g('option').weightBackground[rank + 1] ?? [])[0]; + let colorText = (weightBG[rank + 1] ?? [])[0]; colorTextList[rank] = colorText; }); } @@ -4365,23 +4403,21 @@ if (!getMonster(id) || !gE(monsterStateKeys.name, getMonster(id))) { 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)); + if (g('option').displayWeightBackground && weightBG) { + let colorText = colorTextList[rank]; + let remainAttemp = 10; // 避免无穷递归 + while (remainAttemp > 0 && colorText && colorText.indexOf(``, colorTextList[i]); } - catch { - } - getMonster(id).style.cssText += `background: ${colorText};`; + remainAttemp--; + } + try { + colorText = eval(colorText.replace('', rank).replace('', weights.length)); } + catch { + } + getMonster(id).style.cssText += `background: ${colorText};`; } gE(monsterStateKeys.name, getMonster(id)).style.cssText += 'display: flex; flex-direction: row;' if (g('option').displayWeight) { @@ -4484,62 +4520,95 @@ } } + function matchDamageInfoFromLogText(text, isSkipUnmatched = true) { + const regList = [ + /you for (\d+) (\w+) damage/, + /and take (\d+) (\w+) damage/, + /You take (\d+) (\w+) damage/, + /hits you, causing (\d+) points of (\w+) damage/ + ]; + for (let reg of regList) { + let match = text.match(reg); + if (!match) { + continue; + } + return match; + } + if (!isSkipUnmatched) { + console.log(`Can't match damage info from: `, text); + } + } + 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: { // 熟练度 - }, - }; + const filter = g('option').record; + if (!filter) { + return; + } + const stats = getValue('stats', true) || {}; + stats.self ??= { _startTime: time(3) }; + stats.self._turn = filter.turn ? stats.self._turn ?? 0 : undefined; + stats.self._round = filter.round ? stats.self._round ?? 0 : undefined; + stats.self._battle = filter.battle ? stats.self._battle ?? 0 : undefined; + stats.self._monster = filter.monster ? stats.self._monster ?? 0 : undefined; + stats.self._boss = filter.boss ? stats.self._boss ?? 0 : undefined; + stats.self.evade = filter.evade ? stats.self.evade ?? 0 : undefined; + stats.self.miss = filter.miss ? stats.self.miss ?? 0 : undefined; + stats.self.focus = filter.focus ? stats.self.focus ?? 0 : undefined; + stats.self.mp = filter.mp ? stats.self.mp ?? 0 : undefined; + stats.self.oc = filter.oc ? stats.self.oc ?? 0 : undefined; + stats.restore = filter.restore ? stats.restore ?? {} : undefined; // 回复量 + stats.items = filter.items ? stats.items ?? {} : undefined; // 物品使用次数 + stats.magic = filter.magic ? stats.magic ?? {} : undefined; // 技能使用次数 + stats.damage = filter.damage ? stats.damage ?? {} : undefined; // 技能攻击造成的伤害 + stats.proficiency = filter.proficiency ? stats.proficiency ?? {} : undefined; // 熟练度 + stats.hurt = filter.hurt ? stats.hurt ?? {} : undefined; // 受到攻击造成的伤害 + if (filter.hurt) { + stats.hurt._avg = filter.hurtavg ? stats.hurt._avg ?? 0 : undefined; + stats.hurt._count = filter.hurtcount ? stats.hurt._count ?? 0 : undefined; + stats.hurt._total = filter.hurttotal ? stats.hurt._total ?? 0 : undefined; + stats.hurt._mavg = filter.hurtmavg ? stats.hurt._mavg ?? 0 : undefined; + stats.hurt._mcount = filter.hurtmcount ? stats.hurt._mcount ?? 0 : undefined; + stats.hurt._mtotal = filter.hurtmtotal ? stats.hurt._mtotal ?? 0 : undefined; + stats.hurt._pavg = filter.hurtpavg ? stats.hurt._pavg ?? 0 : undefined; + stats.hurt._pcount = filter.hurtpcount ? stats.hurt._pcount ?? 0 : undefined; + stats.hurt._ptotal = filter.hurtptotal ? stats.hurt._ptotal ?? 0 : undefined; + } let text, magic, point, reg; const battle = g('battle'); if (g('monsterAlive') === 0) { - stats.self._turn += battle.turn; - stats.self._round += 1; - if (battle.roundNow === battle.roundAll) { - stats.self._battle += 1; + if (filter.turn) { + stats.self._turn += battle.turn; + } + if (filter.round) { + stats.self._round += 1; + } + if (filter.battle) { + if (battle.roundNow === battle.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; + if (filter.magic) { + stats.magic[magic] = (magic in stats.magic) ? stats.magic[magic] + 1 : 1; + } + if (filter.mp) { + stats.self.mp += parm.mp; + } + if (filter.oc) { + stats.self.oc += parm.oc; + } } else if (parm.mode === 'items') { - stats.items[parm.item] = (parm.item in stats.items) ? stats.items[parm.item] + 1 : 1; + if (filter.items) { + 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; + if (filter[parm.mode]) { + 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++) { @@ -4553,60 +4622,98 @@ if (reg = matchDamageInfoFromLogText(text)) { 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 (filter.hurt) { + stats.hurt[magic] = (magic in stats.hurt) ? stats.hurt[magic] + point : point; + if (filter.hurtcount || filter.hurtavg) { + stats.hurt._count++; + } + if (filter.hurttotal || filter.hurtavg) { + stats.hurt._total += point; + } + if (filter.hurtavg) { + stats.hurt._avg = Math.round(stats.hurt._total / stats.hurt._count); + } + if (magic.match(/pierc|crush|slash/)) { + if (filter.hurtpcount || filter.hurtpavg) { + stats.hurt._pcount++; + } + if (filter.hurtptotal || filter.hurtpavg) { + stats.hurt._ptotal += point; + } + if (filter.hurtpavg) { + stats.hurt._pavg = Math.round(stats.hurt._ptotal / stats.hurt._pcount); + } + } else { + if (filter.hurtmcount || filter.hurtmavg) { + stats.hurt._mcount++; + } + if (filter.hurtmtotal || filter.hurtmavg) { + stats.hurt._mtotal += point; + } + if (filter.hurtmavg) { + stats.hurt._mavg = Math.round(stats.hurt._mtotal / stats.hurt._mcount); + } + } } - if (text.match(/You ((partially )*(evade|parry|block)( and )*)+ the attack/)) { + if (filter.evade && text.match(/You ((partially )*(evade|parry|block)( and )*)+ the attack/)) { stats.self.evade++; } } 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; + if (filter.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; + if (filter.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++; + if (filter.evade) { + 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++; + if (filter.miss) { + stats.self.miss++; + } } else if (text.match(/You gain the effect Focusing/)) { - stats.self.focus++; + if (filter.focus) { + 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; + if (filter.restore) { + 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; + if (filter.restore) { + 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 = matchDamageInfoFromLogText(parm.log[i - 1].textContent, false)[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; + if (filter.hurt) { + reg = text.match(/(.*) absorbs (\d+) points of damage from the attack into (\d+) points of (\w+) damage/); + point = reg[2] * 1; + magic = matchDamageInfoFromLogText(parm.log[i - 1].textContent, false)[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; + if (filter.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) { @@ -4619,32 +4726,23 @@ console.table(stats); pauseChange(); } - setValue('stats', stats); - } - - function matchDamageInfoFromLogText(text, isSkipUnmatched = true) { - const regList = [ - /you for (\d+) (\w+) damage/, - /and take (\d+) (\w+) damage/, - /You take (\d+) (\w+) damage/, - /hits you, causing (\d+) points of (\w+) damage/ - ]; - for (let reg of regList) { - let match = text.match(reg); - if (!match) { - continue; - } - return match; - } - if (!isSkipUnmatched) { - console.log(`Can't match damage info from: `, text); + if (JSON.stringify(stats) !== JSON.stringify(getValue('stats', true))) { + setValue('stats', stats); } } function recordUsage2() { + const filter = g('option').record; + if (!filter) { + return; + } const stats = getValue('stats', true); - stats.self._monster += g('monsterAll'); - stats.self._boss += g('bossAll'); + if (filter.monster) { + stats.self._monster += g('monsterAll'); + } + if (filter.boss) { + stats.self._boss += g('bossAll'); + } const battle = g('battle'); if (g('option').recordEach && battle.roundNow === battle.roundAll) { const old = getValue('statsOld', true) || []; @@ -4653,7 +4751,9 @@ old.push(stats); setValue('statsOld', old); delValue('stats'); - } else { + return; + } + if (JSON.stringify(stats) !== JSON.stringify(getValue('stats', true))) { setValue('stats', stats); } } From b18baa241db0d5d9e129bbe54f3ed34f8edf50a9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 12 Nov 2025 15:34:06 +0800 Subject: [PATCH 078/216] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=88=98=E6=96=97?= =?UTF-8?q?=E6=9D=83=E9=87=8D=E6=98=BE=E7=A4=BA=E8=AE=BE=E7=BD=AEUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e38de762..0a1fecce 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1214,16 +1214,18 @@ '
      显示权重及顺序顯示權重及順序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. ', + '
      ', + '
        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])
      )
      ', '
      ', From 471c5a349498c45c9def42d49671c55a5400ed04 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 12 Nov 2025 18:03:30 +0800 Subject: [PATCH 079/216] =?UTF-8?q?2.90.38=20=E5=A2=9E=E5=8A=A0=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=85=B6=E4=BB=96=E6=8A=80=E8=83=BD=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0a1fecce..a452ad25 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.37 +// @version 2.90.38 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2517,6 +2517,7 @@ if (!perks) { return; } + console.log(perks); setValue('staminaHathperk', perks[25].innerHTML.includes('Obtained')); $async.logSwitch(arguments); } catch (e) { console.error(e) } @@ -4093,9 +4094,13 @@ 2403: 2, 1111: 4, } + const optionSkills = !g('option').skill; + if (!optionSkills) { + return; + } for (let i in skillOrder) { let skill = skillOrder[i]; - if (!skill || !g('option').skill[skill]) { + if (!skill || !optionSkills[skill]) { return; } let id = skillLib[skill]; From 576ff361989fcc8328284a12baf267b0ae50f9c9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 12 Nov 2025 19:53:29 +0800 Subject: [PATCH 080/216] =?UTF-8?q?2.90.39=20=E8=83=BD=E9=87=8F=E9=A5=AE?= =?UTF-8?q?=E6=96=99hathperk=E8=AE=B0=E5=BD=95=E6=94=B9=E4=B8=BA=E6=8C=89?= =?UTF-8?q?=E7=85=A7userid=EF=BC=8C=E4=B8=94=E8=B7=B3=E8=BF=87=E5=B7=B2?= =?UTF-8?q?=E8=A7=A3=E9=94=81user=E7=9A=84=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a452ad25..d0cbc6ad 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.38 +// @version 2.90.39 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2285,6 +2285,16 @@ pauseChange(); } + function getCurrentUser() { + const cookie = document.cookie.split("; "); + for (const cookieObj of cookie) { + const match = cookieObj.match(/ipb_member_id=(\d+)/); + if (match) { + return match[1]; + } + } + } + // 答题// function riddleAlert() { // 答题警报 if (window.opener) { @@ -2508,17 +2518,21 @@ return await asyncSetEnergyDrinkHathperk(); } $async.logSwitch(arguments); + let currentID = getCurrentUser(); + let perk = getValue('staminaHathperk') ?? {}; + if (perk[currentID]) { + return; + } 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; + if (perks && perks[25].innerHTML.includes('Obtained')) { + perk[currentID] = true; + setValue('staminaHathperk', perk); } - console.log(perks); - setValue('staminaHathperk', perks[25].innerHTML.includes('Obtained')); $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -2688,7 +2702,7 @@ if (!items) { return checked; } - const recover = items[11402] ? 5 : items[11401] ? getValue('staminaHathperk') ? 20 : 10 : 0; + const recover = items[11402] ? 5 : items[11401] ? (getValue('staminaHathperk')??{})[getCurrentUser()] ? 20 : 10 : 0; if (recover && stamina <= (100 - recover)) { $ajax.open(window.location.href, 'recover=stamina'); return checked; From d78ffc87b5cebbd85bcdb053f3ba68c3bbd05cea Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 13 Nov 2025 01:07:37 +0800 Subject: [PATCH 081/216] timing for encounter changed to after battleready checked --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d0cbc6ad..eda7f8be 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2411,7 +2411,6 @@ asyncSetEnergyDrinkHathperk(), asyncSetAbilityData(), updateArena(), - updateEncounter(g('option').encounter), (async () => { try { const checked = await asyncCheckRepair(); @@ -2419,7 +2418,7 @@ } catch (e) { console.error(e) } })(), ]); - if (notBattleReady) { + if (notBattleReady || await updateEncounter(g('option').encounter)) { return; } if (g('option').idleArena && g('option').idleArenaValue) { @@ -2713,7 +2712,7 @@ try { if (!g('option').encounter && !g('option').encounterDisplay) { console.log("skip encounter check"); - return; + return false; } if (getValue('disabled')) { await pauseAsync(_1s); @@ -2760,6 +2759,7 @@ 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); + return false; } catch (e) { console.error(e) } } From 32ca9bcb9e0bfe2f40088c71a7ccb4c6446df696 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 13 Nov 2025 02:16:01 +0800 Subject: [PATCH 082/216] =?UTF-8?q?2.90.40=20=E8=B0=83=E6=95=B4=E5=BC=80?= =?UTF-8?q?=E5=90=AF=E6=88=98=E6=96=97=E5=89=8D=E5=BC=82=E6=AD=A5=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E6=B5=81=E7=A8=8B=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=81=AD?= =?UTF-8?q?=E9=81=87=E6=88=98=E5=89=8D=E6=A3=80=E6=9F=A5=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E5=92=8C=E8=A3=85=E5=A4=87=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 79 +++++++++++++------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index eda7f8be..79c200f1 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.39 +// @version 2.90.40 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1000,8 +1000,8 @@ '
      ', '
      : ', - ' 耐久度耐久度Durability%
      ', - '
      [C!]检查物品库存檢查物品庫存Check is item needs supply: ', + ' 耐久度耐久度Durability%; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', + '
      [C!]检查物品库存檢查物品庫存Check is item needs supply;遭遇战前检查遭遇戰前檢查Check before encounter', '
      ', ' 体力药水體力藥水Health Potion', ' 体力长效药體力長效藥Health Draught', @@ -2397,34 +2397,67 @@ await pauseAsync(_1s); return await asyncOnIdle(); } - let notBattleReady = false; + const option = g('option'); + const ready = { + isChecked: () => ready.supply && ready.repair, + }; 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(), + // ability + (async () => { try { + ready.ability = await asyncSetAbilityData() || true; + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // stamina & hathperk + (async () => { try { + ready.stamina = await Promise.all([ + asyncSetStamina(), + asyncSetEnergyDrinkHathperk(), + ]) || true; + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // item & supply + (async () => { try { + ready.item = await asyncGetItems() || true; + await tryEncounter(); + ready.supply = await asyncCheckSupply(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // repair + (async () => { try { + ready.repair = await asyncCheckRepair(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // arena data updateArena(), - (async () => { - try { - const checked = await asyncCheckRepair(); - notBattleReady ||= !checked; - } catch (e) { console.error(e) } - })(), ]); - if (notBattleReady || await updateEncounter(g('option').encounter)) { + if (!ready.isChecked()) { return; } - if (g('option').idleArena && g('option').idleArenaValue) { + if (option.idleArena && option.idleArenaValue) { startUpdateArena(idleStart); } - setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); + setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); + + async function tryEncounter() { + if (ready.encounterUpdated) { + return; + } + if (option.encounter) { + switch (true) { + case !ready.ability: + case !ready.stamina: + case option.restoreStamina && !ready.item: + case option.encounterSupply && !ready.supply: + case option.encounterRepair && !ready.repair: + return; + } + } + ready.encounterUpdated = true; + $async.logSwitch(arguments); + await updateEncounter(option.encounter); + $async.logSwitch(arguments); + } } catch (e) { console.error(e) } } From 071954243579f6a93bc6b426569792043eb75d6f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 13 Nov 2025 02:30:46 +0800 Subject: [PATCH 083/216] Add logging for async operations --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 79c200f1..1b8d77ce 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2397,6 +2397,7 @@ await pauseAsync(_1s); return await asyncOnIdle(); } + $async.logSwitch(arguments); const option = g('option'); const ready = { isChecked: () => ready.supply && ready.repair, @@ -2436,8 +2437,11 @@ } if (option.idleArena && option.idleArenaValue) { startUpdateArena(idleStart); + } else { + console.log("skip arena check"); } setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); + $async.logSwitch(arguments); async function tryEncounter() { if (ready.encounterUpdated) { From 00966f069934f0a826bb11404b177f7118b3c38b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 13 Nov 2025 12:20:35 +0800 Subject: [PATCH 084/216] 2.90.41 auto skill: fix optionSkills assignment --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1b8d77ce..71ad8a3f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.40 +// @version 2.90.41 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4145,7 +4145,7 @@ 2403: 2, 1111: 4, } - const optionSkills = !g('option').skill; + const optionSkills = g('option').skill; if (!optionSkills) { return; } From 90a6d84e01e1f268b391d620869aeaba5c76b02c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 13 Nov 2025 14:43:32 +0800 Subject: [PATCH 085/216] 2.90.42 skip encounter check in arena battle ready check while auto encounter is not enabled --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 71ad8a3f..dd6f4d75 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.41 +// @version 2.90.42 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2947,7 +2947,7 @@ href = 'ar'; } href = `?s=Battle&ss=${href}`; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: true, staminaLow: id === 'gr' ? g('option').staminaGrindFest : undefined })) { + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: g('option').encounter, staminaLow: id === 'gr' ? g('option').staminaGrindFest : undefined })) { $async.logSwitch(arguments); return; } From b1a48d1872069d972ecb6fb33a05098d7dd7f3dd Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 15 Nov 2025 22:29:57 +0800 Subject: [PATCH 086/216] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=9B=A0=E7=BD=91=E7=BB=9C=E5=8E=9F=E5=9B=A0=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E4=BA=86=E7=AB=9E=E6=8A=80=E5=9C=BAdone=E4=BD=86=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E6=9C=AA=E8=BF=9B=E5=85=A5=E6=97=B6=EF=BC=8C=E5=BD=93?= =?UTF-8?q?=E6=97=A5=E6=97=A0=E6=B3=95=E5=86=8D=E8=87=AA=E5=8A=A8=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E8=AF=A5=E7=AB=9E=E6=8A=80=E5=9C=BA=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index dd6f4d75..dbfe5083 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2861,6 +2861,7 @@ arena.array = g('option').idleArenaValue?.split(',') ?? []; arena.array.reverse(); } + arena.arrayDone = arena.arrayDone.filter(id => id === 'gr' || !Object.keys(arena.token).includes(id.toString())); return setValue('arena', arena); } catch (e) { console.error(e) } } From afd50c95212d1027f4d1ba5675f9747ddefc2b6a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 01:42:03 +0800 Subject: [PATCH 087/216] =?UTF-8?q?2.90.43=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=BC=80=E5=90=AF=E6=88=98=E6=96=97=E6=97=B6=E4=BC=98?= =?UTF-8?q?=E5=85=88=E4=BD=BF=E7=94=A8alt=E7=AB=99=E7=9A=84=E9=80=89?= =?UTF-8?q?=E9=A1=B9=EF=BC=9B=E8=87=AA=E5=8A=A8=E9=81=AD=E9=81=87=E6=88=98?= =?UTF-8?q?=E3=80=81=E7=AB=9E=E6=8A=80=E5=9C=BA=E7=AD=89=E5=89=8D=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E5=BD=93=E5=89=8D=E7=BD=91=E7=BB=9C=E6=83=85=E5=86=B5?= =?UTF-8?q?=EF=BC=88fetch=E5=BD=93=E5=89=8D=E9=A1=B5=E9=9D=A2=EF=BC=89?= =?UTF-8?q?=E4=BB=A5=E9=81=BF=E5=85=8D=E5=9B=A0=E7=BD=91=E7=BB=9C=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0=E5=AF=BC=E8=87=B4=E7=9A=84=E9=A1=B5=E9=9D=A2=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=89=93=E5=BC=80=EF=BC=9B=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=BC=80=E5=90=AF=E6=88=98=E6=96=97=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E8=A3=85=E5=A4=87=E5=BA=93=E5=AD=98=E6=95=B0=E9=87=8F=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 110 +++++++++++++----- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index dbfe5083..6a69ba70 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.42 +// @version 2.90.43 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -305,7 +305,9 @@ } return false; } - + if (!eventpane) { + return false; + } // 减少因在恒定世界处于战斗中时打开eh触发了遭遇而导致的错失 // 缓存当前链接,等战斗结束时再自动打开,下次打开链接时: // 1. 若新的遭遇未出现,进入已缓存的战斗链接 @@ -315,7 +317,8 @@ } else if (getValue('battle')) { //战斗中 eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 } else { // 战斗外,自动跳转 - $ajax.openNoFetch(`${href}/${url}`); + $ajax.fetch(`${href}/${url}`); + gotoBattle(); } return false; } @@ -429,6 +432,29 @@ // ----------methods---------- // 通用// + function goto() { // 前进 + window.location.href = window.location; + setTimeout(goto, 5000); + } + + function gotoAlt(isAltOnly) { + const hv = 'hentaiverse.org'; + const alt = 'alt.' + hv; + if (window.location.host === hv) { + window.location.href = window.location.href.replace(`://${hv}`, `://${alt}`) + } else if (!isAltOnly && window.location.host === alt) { + window.location.href = window.location.href.replace(`://${alt}`, `://${hv}`) + } + } + + async function gotoBattle() { + if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + gotoAlt(true); + } else { + goto(); + } + } + function pauseAsync(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -731,21 +757,6 @@ } } - 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) { // 全局变量 const hvAA = window.hvAA || {}; if (key === undefined && value === undefined) { @@ -980,6 +991,7 @@ '
      ', '
      ', + '
      ', '
      ', '
      ;
      ', @@ -1001,6 +1013,7 @@ '
      ', '
      : ', ' 耐久度耐久度Durability%; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', + '
      ; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      [C!]检查物品库存檢查物品庫存Check is item needs supply;遭遇战前检查遭遇戰前檢查Check before encounter', '
      ', ' 体力药水體力藥水Health Potion', @@ -2429,6 +2442,11 @@ ready.repair = await asyncCheckRepair(); await tryEncounter(); } catch (e) { console.error(e) } })(), + // equipment storage + (async () => { try { + ready.storage = await asyncCheckEquStorage(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), // arena data updateArena(), ]); @@ -2454,6 +2472,7 @@ case option.restoreStamina && !ready.item: case option.encounterSupply && !ready.supply: case option.encounterRepair && !ready.repair: + case option.encounterEquStorage && !ready.storage: return; } } @@ -2693,6 +2712,31 @@ } catch (e) { console.error(e) }; return false; } + async function asyncCheckEquStorage() { + try { + const option = g('option'); + if (!option.equStorage) { + return true; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckEquStorage(); + } + $async.logSwitch(arguments); + let count; + if (hvVersion < 91) { + const href = `?s=Character&ss=in`; + const doc = $doc(await $ajax.fetch(href)); + count = gE('#eqinv_bot>div>div>div', doc).innerText.match(/: (\d+) \/ \d+/)[1]; + } else { + const href = `?s=Bazaar&ss=am`; + const doc = $doc(await $ajax.fetch(href)); + count = gE('#equipblurb>table>tbody>tr>td:nth-child(2)', doc).innerText; + } + return count * 1 <= option.equStorageValue; + } catch (e) { console.error(e) }; return false; + } + function checkBattleReady(method, condition = {}) { if (getValue('disabled')) { setTimeout(method, _1s); @@ -2800,7 +2844,12 @@ } catch (e) { console.error(e) } } - function onEncounter() { + async function onEncounter() { + if (!(await $ajax.fetch(href))) { // perhaps network connect not available + await pauseAsync(_1m); + onEncounter(); + return; + } if (getValue('disabled') || getValue('battle') || !checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { return; } @@ -2870,7 +2919,7 @@ try { // 闲置竞技场 let id; let arena = getValue('arena', true); - + const option = g('option'); const writeArenaStart = function () { document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); if (id !== 'gr') { @@ -2882,7 +2931,7 @@ } console.log('arena:', getValue('arena', true)); if (arena.array.length === 0) { - setTimeout(autoSwitchIsekai, (g('option').isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); + setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); return; } $async.logSwitch(arguments); @@ -2929,7 +2978,7 @@ } staminaCost.gr += 1 - let href; + let query; let token = arena.token[id]; const cost = staminaCost[id]; if (id === 'gr') { @@ -2939,26 +2988,27 @@ arena.arrayDone.push('gr'); return; } - href = 'gr'; + query = 'gr'; } else if (id >= 105) { - href = 'rb'; + query = 'rb'; } else if (id >= 19) { - href = 'ar&page=2'; + query = 'ar&page=2'; } else { - href = 'ar'; + query = 'ar'; } - href = `?s=Battle&ss=${href}`; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: g('option').encounter, staminaLow: id === 'gr' ? g('option').staminaGrindFest : undefined })) { + query = `?s=Battle&ss=${query}`; + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { $async.logSwitch(arguments); return; } if (hvVersion < 91) { token = `&inittoken=${token}`; } else { - token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(href))).value}`; + token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; } writeArenaStart(); - $ajax.open(href, `initid=${id === 'gr' ? 1 : id}${token}`); + $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); + gotoBattle(); $async.logSwitch(arguments); } catch (e) { console.error(e) } } From a0cd1e15ede940197657a4a89fd27b53788094cc Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 01:47:55 +0800 Subject: [PATCH 088/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6a69ba70..659d002b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2406,6 +2406,7 @@ async function asyncOnIdle() { try { + updateEncounter(false); if (getValue('disabled')) { await pauseAsync(_1s); return await asyncOnIdle(); From 46aab36bf19a33244be7cf7bd9a3c899a388f809 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 01:55:34 +0800 Subject: [PATCH 089/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 659d002b..c323f88d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -448,6 +448,7 @@ } async function gotoBattle() { + loadOption(); if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { gotoAlt(true); } else { From 9d6b7a44e89ff3ee3e9994b4b4705bc79cf33c8f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 02:32:19 +0800 Subject: [PATCH 090/216] Refactor battle navigation logic in hvAutoAttack --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c323f88d..fc0a0548 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -317,8 +317,8 @@ } else if (getValue('battle')) { //战斗中 eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 } else { // 战斗外,自动跳转 - $ajax.fetch(`${href}/${url}`); - gotoBattle(); + loadOption(); + $ajax.openNoFetch(`${g('option').altBattleFirst ? href.replace('hentaiverse.org', 'alt.hentaiverse.org').replave('alt.alt', 'alt') : href}/${url}`); } return false; } @@ -447,15 +447,6 @@ } } - async function gotoBattle() { - loadOption(); - if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { - gotoAlt(true); - } else { - goto(); - } - } - function pauseAsync(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -3010,7 +3001,11 @@ } writeArenaStart(); $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); - gotoBattle(); + if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + gotoAlt(true); + } else { + goto(); + } $async.logSwitch(arguments); } catch (e) { console.error(e) } } From 1ecd67dee052946118d6fedf9c7cfde90cca6588 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 02:56:07 +0800 Subject: [PATCH 091/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index fc0a0548..86245a83 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -318,7 +318,7 @@ eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 } else { // 战斗外,自动跳转 loadOption(); - $ajax.openNoFetch(`${g('option').altBattleFirst ? href.replace('hentaiverse.org', 'alt.hentaiverse.org').replave('alt.alt', 'alt') : href}/${url}`); + $ajax.openNoFetch(`${g('option').altBattleFirst ? href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt') : href}/${url}`); } return false; } From 5a6c0b20e7c9966cc3781e8b47f5f5adcf052bcb Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 03:08:10 +0800 Subject: [PATCH 092/216] Bump version to 2.90.44 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 86245a83..d168e829 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.43 +// @version 2.90.44 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From 9b8d22b6f7bc55d71c16ac4299398ccee4006e2f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 03:28:15 +0800 Subject: [PATCH 093/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d168e829..ec6aa60c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -15,6 +15,7 @@ // @include http*://alt.hentaiverse.org/* // @include http*://e-hentai.org/* // @connect hentaiverse.org +// @connect alt.hentaiverse.org // @connect e-hentai.org // @compatible Firefox + Greasemonkey // @compatible Chrome/Chromium + Tampermonkey From 33480bb26ec151fa95dcb9d46ec543ac97c7a95b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 05:17:09 +0800 Subject: [PATCH 094/216] =?UTF-8?q?2.90.45=20=E4=BC=98=E5=8C=96=E9=81=AD?= =?UTF-8?q?=E9=81=87=E6=88=98=E5=9C=A8=E5=BD=93=E5=A4=A9=E6=9C=89=E9=94=99?= =?UTF-8?q?=E5=A4=B1=E4=B8=94=E6=AC=A1=E6=95=B0=E5=B7=B2=E7=94=A8=E5=AE=8C?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E5=80=92=E8=AE=A1=E6=97=B6=E5=8F=8Aeh?= =?UTF-8?q?=E7=AB=99=E8=BF=94=E5=9B=9E=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ec6aa60c..4392c93c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.44 +// @version 2.90.45 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -15,7 +15,6 @@ // @include http*://alt.hentaiverse.org/* // @include http*://e-hentai.org/* // @connect hentaiverse.org -// @connect alt.hentaiverse.org // @connect e-hentai.org // @compatible Firefox + Greasemonkey // @compatible Chrome/Chromium + Tampermonkey @@ -290,7 +289,7 @@ setEncounter(encounter); } for (let e of encounter) { - if (e.encountered) { + if (e.encountered || time(0) - e.time >= 30 * _1m) { continue; } url = e.href; @@ -306,17 +305,18 @@ } return false; } - if (!eventpane) { - return false; - } // 减少因在恒定世界处于战斗中时打开eh触发了遭遇而导致的错失 // 缓存当前链接,等战斗结束时再自动打开,下次打开链接时: // 1. 若新的遭遇未出现,进入已缓存的战斗链接 // 2. 若新的遭遇已出现,则前一次已超时失效错过,重新获取新的一次 if (!isEngage) { // 战斗外,非自动跳转 - eventpane.style.cssText += 'color:red;' // 链接标红提醒 + if (eventpane) { + eventpane.style.cssText += 'color:red;' // 链接标红提醒 + } } else if (getValue('battle')) { //战斗中 - eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 + if (eventpane) { + eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 + } } else { // 战斗外,自动跳转 loadOption(); $ajax.openNoFetch(`${g('option').altBattleFirst ? href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt') : href}/${url}`); @@ -2794,13 +2794,12 @@ return await updateEncounter(engage, isInBattle); } 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) { + if (encounter.filter(e => e.href && (e.encountered || (time(0) - e.time >= 30 * _1m))).length >= 24) { cd = Math.floor(encounter[0].time / _1d + 1) * _1d - now; } else if (!last) { cd = 0; @@ -2818,7 +2817,7 @@ return ui; })(); - const missed = count - encountered.length; + const missed = count - encounter.filter(e => e.encountered && e.href); if (count === 24) { ui.style.cssText += 'color:orange!important;'; } else if (!cd) { From 8a6fe154be639d153bfa02446293a11c15a8b996 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 05:19:47 +0800 Subject: [PATCH 095/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 4392c93c..f761f170 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2817,7 +2817,7 @@ return ui; })(); - const missed = count - encounter.filter(e => e.encountered && e.href); + const missed = count - encounter.filter(e => e.encountered && e.href).length; if (count === 24) { ui.style.cssText += 'color:orange!important;'; } else if (!cd) { From c67a57f07f5cf0d1ad3e7a4cf5adcade52b8619f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 14:43:07 +0800 Subject: [PATCH 096/216] =?UTF-8?q?2.90.46=20=E4=BF=AE=E6=AD=A3=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=AE=B0=E5=BD=95=E5=AF=B9=E6=97=A7=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E5=85=BC=E5=AE=B9=E9=97=AE=E9=A2=98=EF=BC=9B=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=9F=A5=EF=BC=9A=E6=88=98?= =?UTF-8?q?=E6=96=97=E4=B8=AD=E9=80=94=E6=9B=B4=E6=96=B0=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E6=97=B6=E5=8F=AF=E8=83=BD=E5=9B=A0=E6=8A=80=E8=83=BD=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9C=AA=E8=83=BD=E8=8E=B7=E5=8F=96=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f761f170..72d45a2c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.45 +// @version 2.90.46 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -639,7 +639,7 @@ 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])) : _objArr ? out.concat(Object.keys(_objArr)) : out; }); out = out.sort(); for (let i = 1; i < out.length; i++) { @@ -4323,7 +4323,7 @@ if (!ranges) { continue; } - if (ability) { + if (ability && ability[ab]) { range = ranges[ability[ab].level]; } break; From 95a1ca6008a7124dfcea65aa71284ebc09ea2885 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 14:45:55 +0800 Subject: [PATCH 097/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 72d45a2c..5f7f3179 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4323,7 +4323,7 @@ if (!ranges) { continue; } - if (ability && ability[ab]) { + if (ability && ability[ab] && ability[ab].level) { range = ranges[ability[ab].level]; } break; From 5547c3421b84cc1ecb2c3ce3b7ba765e78c3566a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 14:49:28 +0800 Subject: [PATCH 098/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5f7f3179..90215344 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.46 +// @version 2.90.47 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -639,7 +639,7 @@ function getKeys(objArr, prop) { let out = []; objArr.forEach((_objArr) => { - out = prop ? out.concat(Object.keys(_objArr[prop])) : _objArr ? out.concat(Object.keys(_objArr)) : out; + out = !_objArr ? out :(prop && _objArr[prop]) ? out.concat(Object.keys(_objArr[prop])) : out.concat(Object.keys(_objArr)); }); out = out.sort(); for (let i = 1; i < out.length; i++) { @@ -4443,7 +4443,7 @@ continue; } const ability = getValue('ability', true); - if (ability) { + if (ability && ability[ab] && ability[ab].level) { range = ranges[ability[ab].level]; } break; From 72c6a12bd79fc2673962039c1074b6855214794b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 14:58:43 +0800 Subject: [PATCH 099/216] 2.90.48 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 90215344..9aa1764c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.47 +// @version 2.90.48 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1404,7 +1404,7 @@ getKeys(statsOld, i).forEach((key) => { _html = `${_html}${key}`; statsOld.forEach((_statsOld) => { - if (key in _statsOld[i]) { + if (_statsOld[i] && (key in _statsOld[i])) { _html = `${_html}${_statsOld[i][key]}`; } else { _html = `${_html}`; From 8128d9b6bb945a1145f2603ef2e711da22532f23 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 15:12:20 +0800 Subject: [PATCH 100/216] =?UTF-8?q?2.90.49=20=E4=BF=AE=E6=AD=A3=E4=B8=BA?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E6=9C=8D=E5=8A=A1=E5=99=A8=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E4=BA=86=E6=88=98=E6=96=97=E5=86=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E9=A1=B5=E9=9D=A2=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9aa1764c..d63a6160 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.48 +// @version 2.90.49 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3000,7 +3000,7 @@ token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; } writeArenaStart(); - $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); + await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { gotoAlt(true); } else { From 49c1d1530fc26beb4da68c7c88225d0d62a8da2a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 15:35:46 +0800 Subject: [PATCH 101/216] =?UTF-8?q?2.90.50=20=E5=A2=9E=E5=8A=A0idleArena?= =?UTF-8?q?=20debug=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d63a6160..0a361217 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.49 +// @version 2.90.50 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2914,6 +2914,7 @@ let arena = getValue('arena', true); const option = g('option'); const writeArenaStart = function () { + console.log('Arena Start', id); document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); if (id !== 'gr') { arena.arrayDone.push(id); @@ -2949,6 +2950,7 @@ id = undefined; } if (!id) { + console.log('No Arena Id Available'); setValue('arena', arena); $async.logSwitch(arguments); return; @@ -2991,6 +2993,7 @@ } query = `?s=Battle&ss=${query}`; if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { + console.log('Check Battle Ready Failed'); $async.logSwitch(arguments); return; } From d0f4cbe0dc5d19ce2a446989038744602109b838 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 15:38:38 +0800 Subject: [PATCH 102/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0a361217..2ae8d135 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3004,9 +3004,12 @@ } writeArenaStart(); await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); + console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + console.log('Arena goto alt'); gotoAlt(true); } else { + console.log('Arena goto'); goto(); } $async.logSwitch(arguments); From 32bfeed23b0f1cde4154ebac390b37c256536a27 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 15:44:11 +0800 Subject: [PATCH 103/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3alt=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2ae8d135..1a29a46d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -442,9 +442,9 @@ const hv = 'hentaiverse.org'; const alt = 'alt.' + hv; if (window.location.host === hv) { - window.location.href = window.location.href.replace(`://${hv}`, `://${alt}`) - } else if (!isAltOnly && window.location.host === alt) { - window.location.href = window.location.href.replace(`://${alt}`, `://${hv}`) + window.location.href = window.location.href.replace(`://${hv}`, `://${alt}`); + } else if (window.location.host === alt) { + window.location.href = isAltOnly ? window.location : window.location.href.replace(`://${alt}`, `://${hv}`); } } @@ -2950,7 +2950,7 @@ id = undefined; } if (!id) { - console.log('No Arena Id Available'); + console.log('No Arena Id Available', arena); setValue('arena', arena); $async.logSwitch(arguments); return; From 8bc13bf7364b7b600553e4a357b087ed1b8eeff4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 16:00:17 +0800 Subject: [PATCH 104/216] =?UTF-8?q?2.90.51=20gf=E7=9A=84idleArena=E8=80=90?= =?UTF-8?q?=E5=8A=9Bcost=E6=9B=B4=E6=94=B9=E4=B8=BA0=EF=BC=88=E5=8D=B3?= =?UTF-8?q?=E5=8F=AA=E6=8C=89=E7=85=A7=E9=85=8D=E7=BD=AE=E4=B8=AD=E7=9A=84?= =?UTF-8?q?gf=E5=8D=95=E7=8B=AC=E7=9A=84=E8=80=90=E5=8A=9B=E9=98=88?= =?UTF-8?q?=E5=80=BC=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 915 +++++++++--------- 1 file changed, 446 insertions(+), 469 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1a29a46d..bf874546 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.50 +// @version 2.90.51 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2397,86 +2397,84 @@ window.location.href = `${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`; } - async function asyncOnIdle() { - try { - updateEncounter(false); - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncOnIdle(); - } - $async.logSwitch(arguments); - const option = g('option'); - const ready = { - isChecked: () => ready.supply && ready.repair, - }; - const idleStart = time(0); - await Promise.all([ - // ability - (async () => { try { - ready.ability = await asyncSetAbilityData() || true; - await tryEncounter(); - } catch (e) { console.error(e) } })(), - // stamina & hathperk - (async () => { try { - ready.stamina = await Promise.all([ - asyncSetStamina(), - asyncSetEnergyDrinkHathperk(), - ]) || true; - await tryEncounter(); - } catch (e) { console.error(e) } })(), - // item & supply - (async () => { try { - ready.item = await asyncGetItems() || true; - await tryEncounter(); - ready.supply = await asyncCheckSupply(); - await tryEncounter(); - } catch (e) { console.error(e) } })(), - // repair - (async () => { try { - ready.repair = await asyncCheckRepair(); - await tryEncounter(); - } catch (e) { console.error(e) } })(), - // equipment storage - (async () => { try { - ready.storage = await asyncCheckEquStorage(); - await tryEncounter(); - } catch (e) { console.error(e) } })(), - // arena data - updateArena(), - ]); - if (!ready.isChecked()) { + async function asyncOnIdle() { try { + updateEncounter(false); + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncOnIdle(); + } + $async.logSwitch(arguments); + const option = g('option'); + const ready = { + isChecked: () => ready.supply && ready.repair, + }; + const idleStart = time(0); + await Promise.all([ + // ability + (async () => { try { + ready.ability = await asyncSetAbilityData() || true; + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // stamina & hathperk + (async () => { try { + ready.stamina = await Promise.all([ + asyncSetStamina(), + asyncSetEnergyDrinkHathperk(), + ]) || true; + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // item & supply + (async () => { try { + ready.item = await asyncGetItems() || true; + await tryEncounter(); + ready.supply = await asyncCheckSupply(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // repair + (async () => { try { + ready.repair = await asyncCheckRepair(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // equipment storage + (async () => { try { + ready.storage = await asyncCheckEquStorage(); + await tryEncounter(); + } catch (e) { console.error(e) } })(), + // arena data + updateArena(), + ]); + if (!ready.isChecked()) { + return; + } + if (option.idleArena && option.idleArenaValue) { + startUpdateArena(idleStart); + } else { + console.log("skip arena check"); + } + setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); + $async.logSwitch(arguments); + + async function tryEncounter() { + if (ready.encounterUpdated) { return; } - if (option.idleArena && option.idleArenaValue) { - startUpdateArena(idleStart); - } else { - console.log("skip arena check"); - } - setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); - $async.logSwitch(arguments); - - async function tryEncounter() { - if (ready.encounterUpdated) { - return; - } - if (option.encounter) { - switch (true) { - case !ready.ability: - case !ready.stamina: - case option.restoreStamina && !ready.item: - case option.encounterSupply && !ready.supply: - case option.encounterRepair && !ready.repair: - case option.encounterEquStorage && !ready.storage: - return; - } + if (option.encounter) { + switch (true) { + case !ready.ability: + case !ready.stamina: + case option.restoreStamina && !ready.item: + case option.encounterSupply && !ready.supply: + case option.encounterRepair && !ready.repair: + case option.encounterEquStorage && !ready.storage: + return; } - ready.encounterUpdated = true; - $async.logSwitch(arguments); - await updateEncounter(option.encounter); - $async.logSwitch(arguments); } - } catch (e) { console.error(e) } - } + ready.encounterUpdated = true; + $async.logSwitch(arguments); + await updateEncounter(option.encounter); + $async.logSwitch(arguments); + } + } catch (e) { console.error(e) } } function setEncounter(encounter) { return g('encounter', setValue('encounter', encounter)); @@ -2515,221 +2513,207 @@ return getToday(Object.values(dict)).sort((x, y) => x.time < y.time ? 1 : x.time > y.time ? -1 : 0); } - async function asyncSetAbilityData() { - try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetAbilityData(); - } - $async.logSwitch(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']; - switch (type) { - case 'deprecating1': - case 'deprecating2': - case 'elemental': - case 'forbidden': - case 'divine': - break; - default: - return; + async function asyncSetAbilityData() { try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetAbilityData(); + } + $async.logSwitch(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']; + switch (type) { + case 'deprecating1': + case 'deprecating2': + case 'elemental': + case 'forbidden': + case 'divine': + break; + default: + return; + } + 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), } - 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); - $async.logSwitch(arguments); - } catch (e) { console.error(e) } - } - - async function asyncSetEnergyDrinkHathperk() { - try { - if (isIsekai || !g('option').restoreStamina) { - return; - } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetEnergyDrinkHathperk(); - } - $async.logSwitch(arguments); - let currentID = getCurrentUser(); - let perk = getValue('staminaHathperk') ?? {}; - if (perk[currentID]) { - return; - } - 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 && perks[25].innerHTML.includes('Obtained')) { - perk[currentID] = true; - setValue('staminaHathperk', perk); - } - $async.logSwitch(arguments); - } catch (e) { console.error(e) } - } + }); + } catch (e) { console.error(e) } + })); + setValue('ability', ability); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - async function asyncSetStamina() { - try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetStamina(); - } - $async.logSwitch(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); - $async.logSwitch(arguments); - } catch (e) { console.error(e) } - } + async function asyncSetEnergyDrinkHathperk() { try { + if (isIsekai || !g('option').restoreStamina) { + return; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetEnergyDrinkHathperk(); + } + $async.logSwitch(arguments); + let currentID = getCurrentUser(); + let perk = getValue('staminaHathperk') ?? {}; + if (perk[currentID]) { + return; + } + 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 && perks[25].innerHTML.includes('Obtained')) { + perk[currentID] = true; + setValue('staminaHathperk', perk); + } + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } - async function asyncGetItems() { - try { - if (!g('option').checkSupply && (isIsekai || !g('option').restoreStamina)) { - return; + async function asyncSetStamina() { try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncSetStamina(); + } + $async.logSwitch(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); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } + + async function asyncGetItems() { try { + if (!g('option').checkSupply && (isIsekai || !g('option').restoreStamina)) { + return; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncGetItems(); + } + $async.logSwitch(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); + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } + + async function asyncCheckSupply() { try { + if (!g('option').checkSupply) { + return true; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckSupply(); + } + $async.logSwitch(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; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncGetItems(); + const [name, count] = item; + const threshold = thresholdList[id] ?? 0; + if ((count ?? 0) >= threshold) { + continue; } - $async.logSwitch(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); - $async.logSwitch(arguments); - } catch (e) { console.error(e) } - } + needs.push(`\n${name}(${count}<${threshold})`); + } + if (needs.length) { + console.log(`Needs supply:${needs}`); + document.title = `[C!]` + document.title; + } + $async.logSwitch(arguments); + return !needs.length; + } catch (e) { console.error(e) } return false; } - async function asyncCheckSupply() { - try { - if (!g('option').checkSupply) { - return true; - } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckSupply(); - } - $async.logSwitch(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; + async function asyncCheckRepair() { try { + if (!g('option').repair) { + return true; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckRepair(); + } + $async.logSwitch(arguments); + let eqps; + if (hvVersion < 91) { + const href = `?s=Forge&ss=re`; + const doc = $doc(await $ajax.fetch(href)); + const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); + 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; } - const [name, count] = item; - const threshold = thresholdList[id] ?? 0; - if ((count ?? 0) >= threshold) { - continue; + const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); + return gE('.messagebox_error', )?.innerText ? undefined : id; + } catch (e) { console.error(e) } })); + } else { + const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped`; + const doc = $doc(await $ajax.fetch(href)); + const token = gE('#equipform>input[name="postoken"]', doc).value; + eqps = await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { + const id = gE('input', eqp).value; + const condition = 1 * gE('td:last-child', eqp).textContent.replace('%', ''); + if (condition > g('option').repairValue) { + return; } - needs.push(`\n${name}(${count}<${threshold})`); - } - if (needs.length) { - console.log(`Needs supply:${needs}`); - document.title = `[C!]` + document.title; - } - $async.logSwitch(arguments); - return !needs.length; - } catch (e) { console.error(e) } return false; - } - - async function asyncCheckRepair() { - try { - if (!g('option').repair) { - return true; - } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckRepair(); - } - $async.logSwitch(arguments); - let eqps; - if (hvVersion < 91) { - const href = `?s=Forge&ss=re`; - const doc = $doc(await $ajax.fetch(href)); - const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); - 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; - } - const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); - return gE('.messagebox_error', )?.innerText ? undefined : id; - } catch (e) { console.error(e) } })); - } else { - const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped`; - const doc = $doc(await $ajax.fetch(href)); - const token = gE('#equipform>input[name="postoken"]', doc).value; - eqps = await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { - const id = gE('input', eqp).value; - const condition = 1 * gE('td:last-child', eqp).textContent.replace('%', ''); - if (condition > g('option').repairValue) { - return; - } - const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); - return gE(`#e${id}`, after) ? id : undefined; - } catch (e) { console.error(e) } })); - } - eqps = eqps.filter(e=>e); - if (eqps.length) { - console.log('eqps need repair: ', eqps); - document.title = `[R!]` + document.title; - } - $async.logSwitch(arguments); - return !eqps.length; - } catch (e) { console.error(e) }; return false; - } - - async function asyncCheckEquStorage() { - try { - const option = g('option'); - if (!option.equStorage) { - return true; - } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckEquStorage(); - } - $async.logSwitch(arguments); - let count; - if (hvVersion < 91) { - const href = `?s=Character&ss=in`; - const doc = $doc(await $ajax.fetch(href)); - count = gE('#eqinv_bot>div>div>div', doc).innerText.match(/: (\d+) \/ \d+/)[1]; - } else { - const href = `?s=Bazaar&ss=am`; - const doc = $doc(await $ajax.fetch(href)); - count = gE('#equipblurb>table>tbody>tr>td:nth-child(2)', doc).innerText; - } - return count * 1 <= option.equStorageValue; - } catch (e) { console.error(e) }; return false; - } + const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); + return gE(`#e${id}`, after) ? id : undefined; + } catch (e) { console.error(e) } })); + } + eqps = eqps.filter(e=>e); + if (eqps.length) { + console.log('eqps need repair: ', eqps); + document.title = `[R!]` + document.title; + } + $async.logSwitch(arguments); + return !eqps.length; + } catch (e) { console.error(e) }; return false; } + + async function asyncCheckEquStorage() { try { + const option = g('option'); + if (!option.equStorage) { + return true; + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await asyncCheckEquStorage(); + } + $async.logSwitch(arguments); + let count; + if (hvVersion < 91) { + const href = `?s=Character&ss=in`; + const doc = $doc(await $ajax.fetch(href)); + count = gE('#eqinv_bot>div>div>div', doc).innerText.match(/: (\d+) \/ \d+/)[1]; + } else { + const href = `?s=Bazaar&ss=am`; + const doc = $doc(await $ajax.fetch(href)); + count = gE('#equipblurb>table>tbody>tr>td:nth-child(2)', doc).innerText; + } + return count * 1 <= option.equStorageValue; + } catch (e) { console.error(e) }; return false; } function checkBattleReady(method, condition = {}) { if (getValue('disabled')) { @@ -2783,59 +2767,57 @@ } } - async function updateEncounter(engage, isInBattle) { - try { - if (!g('option').encounter && !g('option').encounterDisplay) { - console.log("skip encounter check"); - return false; - } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await updateEncounter(engage, isInBattle); - } - const encounter = getEncounter(); - 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 (encounter.filter(e => e.href && (e.encountered || (time(0) - e.time >= 30 * _1m))).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 - encounter.filter(e => e.encountered && e.href).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); + async function updateEncounter(engage, isInBattle) { try { + if (!g('option').encounter && !g('option').encounterDisplay) { + console.log("skip encounter check"); return false; - } catch (e) { console.error(e) } - } + } + if (getValue('disabled')) { + await pauseAsync(_1s); + return await updateEncounter(engage, isInBattle); + } + const encounter = getEncounter(); + 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 (encounter.filter(e => e.href && (e.encountered || (time(0) - e.time >= 30 * _1m))).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 - encounter.filter(e => e.encountered && e.href).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); + return false; + } catch (e) { console.error(e) } } async function onEncounter() { if (!(await $ajax.fetch(href))) { // perhaps network connect not available @@ -2871,150 +2853,145 @@ } catch (e) { console.error(e) } } - async function updateArena(forceUpdateToken = false) { - try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await updateArena(forceUpdateToken); - } - 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)); - getStartBattleButtons(doc).forEach(btn => { arena.token[btn.id] = btn.token ?? null; }); - } 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(); - } - arena.arrayDone = arena.arrayDone.filter(id => id === 'gr' || !Object.keys(arena.token).includes(id.toString())); - return setValue('arena', arena); - } catch (e) { console.error(e) } - } + async function updateArena(forceUpdateToken = false) { try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await updateArena(forceUpdateToken); + } + 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)); + getStartBattleButtons(doc).forEach(btn => { arena.token[btn.id] = btn.token ?? null; }); + } 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(); + } + arena.arrayDone = arena.arrayDone.filter(id => id === 'gr' || !Object.keys(arena.token).includes(id.toString())); + return setValue('arena', arena); + } catch (e) { console.error(e) } } - async function idleArena() { - try { // 闲置竞技场 - let id; - let arena = getValue('arena', true); - const option = g('option'); - const writeArenaStart = function () { - console.log('Arena Start', id); - document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); - if (id !== 'gr') { - arena.arrayDone.push(id); - } else { - arena.gr--; - } - setValue('arena', arena); + async function idleArena() { try { // 闲置竞技场 + let id; + let arena = getValue('arena', true); + const option = g('option'); + const writeArenaStart = function () { + console.log('Arena Start', id); + document.title = _alert(-1, '闲置竞技场开始', '閒置競技場開始', 'Idle Arena start'); + if (id !== 'gr') { + arena.arrayDone.push(id); + } else { + arena.gr--; } - console.log('arena:', getValue('arena', true)); - if (arena.array.length === 0) { - setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); - return; + setValue('arena', arena); + } + console.log('arena:', getValue('arena', true)); + if (arena.array.length === 0) { + setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s); + return; + } + $async.logSwitch(arguments); + const array = [...arena.array]; + const RBundone = []; + while (array.length > 0) { + id = array.pop() * 1; + id = isNaN(id) ? 'gr' : id; + if (arena.arrayDone?.includes(id)) { + id = undefined; + continue; } - $async.logSwitch(arguments); - const array = [...arena.array]; - 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 >= 105) { - arena.token = (await updateArena(true)).token; - if (id in arena.token) { - break; - } - } - id = undefined; } - if (!id) { - console.log('No Arena Id Available', arena); + id = undefined; + } + if (!id) { + console.log('No Arena Id Available', arena); + setValue('arena', arena); + $async.logSwitch(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: 0 + } + let stamina = getValue('stamina'); + const lastTime = getValue('staminaTime'); + let timeNow = Math.floor(time(0) / 1000 / 60 / 60); + stamina += lastTime ? timeNow - lastTime : 0; + for (let id in staminaCost) { + staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) + } + + let query; + let token = arena.token[id]; + const cost = staminaCost[id]; + if (id === 'gr') { + if (arena.gr <= 0) { setValue('arena', arena); - $async.logSwitch(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 id in staminaCost) { - staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) - } - staminaCost.gr += 1 - - let query; - let token = arena.token[id]; - const cost = staminaCost[id]; - if (id === 'gr') { - if (arena.gr <= 0) { - setValue('arena', arena); - idleArena(); - arena.arrayDone.push('gr'); - return; - } - query = 'gr'; - } else if (id >= 105) { - query = 'rb'; - } else if (id >= 19) { - query = 'ar&page=2'; - } else { - query = 'ar'; - } - query = `?s=Battle&ss=${query}`; - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { - console.log('Check Battle Ready Failed'); - $async.logSwitch(arguments); + idleArena(); + arena.arrayDone.push('gr'); return; } - if (hvVersion < 91) { - token = `&inittoken=${token}`; - } else { - token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; - } - writeArenaStart(); - await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); - console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); - if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { - console.log('Arena goto alt'); - gotoAlt(true); - } else { - console.log('Arena goto'); - goto(); - } + query = 'gr'; + } else if (id >= 105) { + query = 'rb'; + } else if (id >= 19) { + query = 'ar&page=2'; + } else { + query = 'ar'; + } + query = `?s=Battle&ss=${query}`; + if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { + console.log('Check Battle Ready Failed'); $async.logSwitch(arguments); - } catch (e) { console.error(e) } - } + return; + } + if (hvVersion < 91) { + token = `&inittoken=${token}`; + } else { + token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; + } + writeArenaStart(); + await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); + console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); + if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + console.log('Arena goto alt'); + gotoAlt(true); + } else { + console.log('Arena goto'); + goto(); + } + $async.logSwitch(arguments); + } catch (e) { console.error(e) } } // 战斗中// function onBattleRound() { // 主程序 From 643a0bdad953ca88eca7e29f2b1e38912eeb2983 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 17:10:02 +0800 Subject: [PATCH 105/216] =?UTF-8?q?2.90.51=20=E8=B0=83=E6=95=B4=E9=81=AD?= =?UTF-8?q?=E9=81=87=E6=88=98=E8=BF=9B=E5=85=A5=E6=88=98=E6=96=97=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E8=AE=B0=E5=BD=95=E6=97=B6=E6=9C=BA=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=8F=AF=E8=83=BD=E5=AD=98=E5=9C=A8=E7=9A=84?= =?UTF-8?q?=E6=9C=AA=E8=AE=B0=E5=BD=95=E9=97=AE=E9=A2=98=EF=BC=9B=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=97=A5=E5=BF=97=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 115 +++++++++--------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index bf874546..ac1b404e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.51 +// @version 2.90.52 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -223,19 +223,20 @@ function initAsync() { const $async = { list: [], - logSwitch: function (args) { - try { - const argsStr = Array.from(args).join(','); - const name = `${args.callee.name}${argsStr === '' ? argsStr : `(${argsStr})`}`; - const state = $async.list.indexOf(name) === -1; - if (!state) { - $async.list.splice($async.list.indexOf(name), 1); - } else { - $async.list.push(name); - } - console.log(`${state ? 'Start' : 'End'} ${name}\n`, JSON.parse(JSON.stringify($async.list))); - } catch (e) { } - } + logSwitchStrict: function (name, state) { try { + if (!state) { + $async.list.splice($async.list.indexOf(name), 1); + } else { + $async.list.push(name); + } + console.log(`${state ? 'Start' : 'End'} ${name}\n`, JSON.parse(JSON.stringify($async.list))); + } catch (e) { } }, + logSwitch: function (args) { try { + const argsStr = Array.from(args).join(','); + const name = `${args.callee.name}${argsStr === '' ? argsStr : `(${argsStr})`}`; + const state = $async.list.indexOf(name) === -1; + $async.logSwitchStrict(name, state); + } catch (e) { } } } return $async; } @@ -280,7 +281,7 @@ if (url === undefined) { // 新一天 encounter = []; } - encounter.unshift({ href: url, time: now }); + encounter.unshift({ href: url + `time=${now}`, time: now }); setEncounter(encounter); } else { if (encounter.length) { @@ -2444,6 +2445,7 @@ updateArena(), ]); if (!ready.isChecked()) { + $async.logSwitch(arguments); return; } if (option.idleArena && option.idleArenaValue) { @@ -2712,6 +2714,7 @@ const doc = $doc(await $ajax.fetch(href)); count = gE('#equipblurb>table>tbody>tr>td:nth-child(2)', doc).innerText; } + $async.logSwitch(arguments); return count * 1 <= option.equStorageValue; } catch (e) { console.error(e) }; return false; } @@ -2825,7 +2828,9 @@ onEncounter(); return; } + $async.logSwitchStrict('updateEncounter', true); if (getValue('disabled') || getValue('battle') || !checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { + $async.logSwitchStrict('updateEncounter', false); return; } setEncounter(getEncounter()); // 离开页面前保存 @@ -2833,25 +2838,26 @@ setValue('lastHref', window.top.location.href); } $ajax.openNoFetch('https://e-hentai.org/news.php?encounter'); + $async.logSwitchStrict('updateEncounter', false); } - async function startUpdateArena(idleStart, startIdleArena = true) { - try { - const now = time(0); - if (!idleStart) { - await updateArena(); - } - let timeout = g('option').idleArenaTime * _1s; - if (idleStart) { - timeout -= time(0) - idleStart; - } - if (startIdleArena) { - setTimeout(idleArena, timeout); - } - 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 startUpdateArena(idleStart, startIdleArena = true) { try { + $async.logSwitchStrict('startUpdateArena', true); + const now = time(0); + if (!idleStart) { + await updateArena(); + } + let timeout = g('option').idleArenaTime * _1s; + if (idleStart) { + timeout -= time(0) - idleStart; + } + if (startIdleArena) { + setTimeout(idleArena, timeout); + } + const last = getValue('arena', true)?.date ?? now; + setTimeout(startUpdateArena, Math.max(0, Math.floor(last / _1d + 1) * _1d - now)); + $async.logSwitchStrict('startUpdateArena', false); + } catch (e) { console.error(e) } } async function updateArena(forceUpdateToken = false) { try { if (getValue('disabled')) { @@ -3522,33 +3528,30 @@ g('bossAll', gE(`${monsterStateKeys.lv}[style^="background"]`, 'all').length); const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[style*="background"]`, 'all').length; g('bossAlive', g('bossAll') - bossDead); + 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/ }, + } + if (document.body.innerHTML.match(types.ba.reg)) { + const encounter = getEncounter(); + if (encounter[0]) { + encounter[0].encountered = time(0); + setEncounter(encounter); + } + } 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); - } - return true; - } - }, - } battle.tower = (temp.match(/\(Floor (\d+)\)/) ?? [null])[1] * 1; const id = (temp.match(/\d+/) ?? [null])[0] * 1; battle.roundType = undefined; From 9789aa3b8545b0a0c234566ce26d22d0b9305d37 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 17:42:58 +0800 Subject: [PATCH 106/216] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=81=AD=E9=81=87?= =?UTF-8?q?=E6=88=98=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ac1b404e..80c719be 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -281,7 +281,7 @@ if (url === undefined) { // 新一天 encounter = []; } - encounter.unshift({ href: url + `time=${now}`, time: now }); + encounter.unshift({ href: url, time: now }); setEncounter(encounter); } else { if (encounter.length) { @@ -2456,7 +2456,7 @@ setTimeout(autoSwitchIsekai, (option.isekaiTime * (Math.random() * 20 + 90) / 100) * _1s - (time(0) - idleStart)); $async.logSwitch(arguments); - async function tryEncounter() { + async function tryEncounter() { try { if (ready.encounterUpdated) { return; } @@ -2475,7 +2475,7 @@ $async.logSwitch(arguments); await updateEncounter(option.encounter); $async.logSwitch(arguments); - } + } catch (e) { console.error(e) } } } catch (e) { console.error(e) } } function setEncounter(encounter) { @@ -2723,9 +2723,12 @@ setTimeout(method, _1s); return; } - if (condition.checkEncounter && getEncounter()[0]?.href && !getEncounter()[0]?.encountered) { - $debug.log(getEncounter()); - return; + if (condition.checkEncounter) { + const encounter = getEncounter(); + if (encounter[0]?.href && !encounter[0]?.encountered) { + $debug.log(getEncounter()); + return; + } } const staminaChecked = checkStamina(condition.staminaLow, condition.staminaCost); console.log(`stamina check done:\n${condition.staminaLow ? `low: ${condition.staminaLow}\n` : ''}${condition.staminaCost ? `cost: ${condition.staminaCost}\n` : ''}status: ${staminaChecked === 1 ? 'succeed' : staminaChecked === 0 ? 'failed' : 'failed with nature recover'}`); @@ -2822,7 +2825,7 @@ return false; } catch (e) { console.error(e) } } - async function onEncounter() { + async function onEncounter() { try { if (!(await $ajax.fetch(href))) { // perhaps network connect not available await pauseAsync(_1m); onEncounter(); @@ -2839,7 +2842,7 @@ } $ajax.openNoFetch('https://e-hentai.org/news.php?encounter'); $async.logSwitchStrict('updateEncounter', false); - } + } catch (e) { console.error(e) } } async function startUpdateArena(idleStart, startIdleArena = true) { try { $async.logSwitchStrict('startUpdateArena', true); @@ -2977,7 +2980,7 @@ } query = `?s=Battle&ss=${query}`; if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { - console.log('Check Battle Ready Failed'); + console.log('Check Battle Ready Failed', 'id:', id, cost); $async.logSwitch(arguments); return; } @@ -3340,13 +3343,13 @@ function clearBattleUnresponsive() { Object.keys(battleUnresponsive).forEach(t => clearTimeout(battleUnresponsive[t].timeout)); } - async function onBattleUnresponsive(method) { + async function onBattleUnresponsive(method) { try { if (getValue('disabled')) { await pauseAsync(_1s); return await onBattleUnresponsive(); } method(); - } + } catch (e) { console.error(e) } } let obj, a, cost; const eventStart = cE('a'); @@ -3401,7 +3404,7 @@ recordUsage2(); } onRoundEnd(); - async function onRoundEnd() { + async function onRoundEnd() { try { if (getValue('disabled')) { await pauseAsync(_1s); return await onRoundEnd(); @@ -3422,38 +3425,36 @@ } clearBattleUnresponsive(); - async function onNewRound() { - try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await onNewRound(); - } - if (gE('#btcp')?.innerHTML.includes("finishbattle.png")) { - goto(); - return; - } - 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(); + async function onNewRound() { try { + if (getValue('disabled')) { + await pauseAsync(_1s); + return await onNewRound(); + } + if (gE('#btcp')?.innerHTML.includes("finishbattle.png")) { + goto(); + return; + } + 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; } - ['#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); - onStepInDone(); - onBattleRound(); - } catch (e) { e => console.error(e) } - } - } + goto(); + return; + } + ['#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); + onStepInDone(); + onBattleRound(); + } catch (e) { e => console.error(e) } } + } catch (e) { console.error(e) } } }; gE('body').appendChild(eventEnd); @@ -3542,13 +3543,6 @@ tw: { reg: /^Initializing The Tower/ }, ba: { reg: /^Initializing random encounter/ }, } - if (document.body.innerHTML.match(types.ba.reg)) { - const encounter = getEncounter(); - if (encounter[0]) { - encounter[0].encountered = time(0); - setEncounter(encounter); - } - } const battleLog = gE('#textlog>tbody>tr>td', 'all'); if (!battle.roundType) { const temp = battleLog[battleLog.length - 1].textContent; @@ -3567,6 +3561,13 @@ break; } } + if (battle.roundType === 'ba' || document.body.innerHTML.match(/Initializing random encounter/)) { + const encounter = getEncounter(); + if (encounter[0]) { + encounter[0].encountered = time(0); + setEncounter(encounter); + } + } 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; From c2b9d8b10ae5a7808372d8ec9b26662ef4a7bc23 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 18:11:27 +0800 Subject: [PATCH 107/216] =?UTF-8?q?2.90.53=20=E8=B0=83=E6=95=B4=E9=81=AD?= =?UTF-8?q?=E9=81=87=E6=88=98=E8=BF=9B=E5=85=A5=E5=88=A4=E5=AE=9A=E5=8F=8A?= =?UTF-8?q?=E9=81=AD=E9=81=87=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 80c719be..37bcd787 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.52 +// @version 2.90.53 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -252,8 +252,11 @@ if (window.location.href.indexOf(`?s=Battle&ss=ba`) !== -1) { const encounterURL = window.location.href?.split('/')[3]; const encounter = getEncounter(); - if (!encounter.filter(e => e.href === encounterURL).length) { + const filtered = encounter.filter(e => e.href === encounterURL); + if (!filtered.length) { encounter.unshift({ href: encounterURL, time: time(0), encountered: time(0) }); + } else { + filtered[0].encountered = time(0); } setEncounter(encounter); } @@ -2726,7 +2729,7 @@ if (condition.checkEncounter) { const encounter = getEncounter(); if (encounter[0]?.href && !encounter[0]?.encountered) { - $debug.log(getEncounter()); + console.log(getEncounter()); return; } } @@ -2815,9 +2818,15 @@ 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; + if (engage ) { + if (!cd) { + onEncounter(); + return true; + } + if (cd < 30* _1m && encounter[0].href && !encounter[0].encountered) { + $ajax.openNoFetch(encounter[0].href); + 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; // 让倒计时显示更平滑 From 0ef5f65b0036f220bc86e604b39f8c1d682976ab Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 17 Nov 2025 18:12:55 +0800 Subject: [PATCH 108/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 37bcd787..8960edb8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -256,7 +256,7 @@ if (!filtered.length) { encounter.unshift({ href: encounterURL, time: time(0), encountered: time(0) }); } else { - filtered[0].encountered = time(0); + filtered[0].encountered ??= time(0); } setEncounter(encounter); } From 70312f62c09c93aeaccb5725b62f15100ae2b7ea Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 18 Nov 2025 04:21:38 +0800 Subject: [PATCH 109/216] =?UTF-8?q?2.90.54=20=E5=A2=9E=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=EF=BC=9A=E5=8E=8B=E6=A6=A8=E5=B1=8A=E5=8F=AF=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8D=95=E7=8B=AC=E7=9A=84=E5=BA=93=E5=AD=98=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8960edb8..2e0d8271 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.53 +// @version 2.90.54 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1041,6 +1041,36 @@ ' 生命卷轴生命捲軸Scroll of Life', ' 众神卷轴眾神捲軸Scroll of the Gods', '
      ', + '
      [C!!]压榨届使用单独的库存检查壓榨屆使用單獨的庫存檢查Standalone supply check for Grind Fest', + '
      ', + ' 体力药水體力藥水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', + '
      ', '
      ', '
      ', @@ -2431,7 +2461,7 @@ (async () => { try { ready.item = await asyncGetItems() || true; await tryEncounter(); - ready.supply = await asyncCheckSupply(); + ready.supply = checkSupply(); await tryEncounter(); } catch (e) { console.error(e) } })(), // repair @@ -2618,18 +2648,13 @@ $async.logSwitch(arguments); } catch (e) { console.error(e) } } - async function asyncCheckSupply() { try { + function checkSupply(isGFStandalone) { if (!g('option').checkSupply) { return true; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckSupply(); - } - $async.logSwitch(arguments); const items = g('items'); - const thresholdList = g('option').checkItem; - const checkList = g('option').isCheck; + const thresholdList = isGFStandalone ? g('option').checkItemGF : g('option').checkItem; + const checkList = isGFStandalone ? g('option').isCheckGF : g('option').isCheck; const needs = []; for (let id in checkList) { const item = items[id]; @@ -2645,11 +2670,10 @@ } if (needs.length) { console.log(`Needs supply:${needs}`); - document.title = `[C!]` + document.title; + document.title = `[C!${isGFStandalone ? '!' : ''}]` + document.title; } - $async.logSwitch(arguments); return !needs.length; - } catch (e) { console.error(e) } return false; } + } async function asyncCheckRepair() { try { if (!g('option').repair) { @@ -2988,6 +3012,12 @@ query = 'ar'; } query = `?s=Battle&ss=${query}`; + + if (id === 'gr' && option.checkSupplyGF && !checkSupply(true)) { + console.log('Check Battle Ready Failed', 'id:', id, cost); + $async.logSwitch(arguments); + return; + } if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { console.log('Check Battle Ready Failed', 'id:', id, cost); $async.logSwitch(arguments); From 8f6c95141c0d927675caeccdbd35f85e3a56118b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 18 Nov 2025 04:32:39 +0800 Subject: [PATCH 110/216] =?UTF-8?q?2.90.55=20=E5=A2=9E=E5=8A=A0=E5=8E=8B?= =?UTF-8?q?=E6=A6=A8=E5=B1=8A=E9=A2=9D=E5=A4=96=E8=80=90=E4=B9=85=E5=BA=A6?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2e0d8271..ffacf09f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.54 +// @version 2.90.55 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1009,7 +1009,7 @@ '
      ', '
      : ', - ' 耐久度耐久度Durability%; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', + ' 耐久度耐久度Durability% 或 压榨届耐久度或 壓榨屆耐久度OR Grind Fest Durability%
      遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      ; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      [C!]检查物品库存檢查物品庫存Check is item needs supply;遭遇战前检查遭遇戰前檢查Check before encounter', '
      ', @@ -1041,7 +1041,7 @@ ' 生命卷轴生命捲軸Scroll of Life', ' 众神卷轴眾神捲軸Scroll of the Gods', '
      ', - '
      [C!!]压榨届使用单独的库存检查壓榨屆使用單獨的庫存檢查Standalone supply check for Grind Fest', + '
      [C!!]压榨届使用额外的库存检查壓榨屆使用額外的庫存檢查Extra supply check for Grind Fest', '
      ', ' 体力药水體力藥水Health Potion', ' 体力长效药體力長效藥Health Draught', @@ -2675,7 +2675,7 @@ return !needs.length; } - async function asyncCheckRepair() { try { + async function asyncCheckRepair(isGrindFestStandalone) { try { if (!g('option').repair) { return true; } @@ -2685,6 +2685,11 @@ } $async.logSwitch(arguments); let eqps; + const threshold = isGrindFestStandalone ? g('option').repairValueGF : g('option').repairValue; + if (!threshold) { // skip because default repair has been checked before idleArena>GF + $async.logSwitch(arguments); + return true; + } if (hvVersion < 91) { const href = `?s=Forge&ss=re`; const doc = $doc(await $ajax.fetch(href)); @@ -2692,7 +2697,7 @@ 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) { + if (condition > threshold) { return; } const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); @@ -2705,7 +2710,7 @@ eqps = await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { const id = gE('input', eqp).value; const condition = 1 * gE('td:last-child', eqp).textContent.replace('%', ''); - if (condition > g('option').repairValue) { + if (condition > threshold) { return; } const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); @@ -3013,7 +3018,7 @@ } query = `?s=Battle&ss=${query}`; - if (id === 'gr' && option.checkSupplyGF && !checkSupply(true)) { + if (id === 'gr' && (option.checkSupplyGF && !checkSupply(true)) || (option.repairValueGF && !await asyncCheckRepair(true))) { console.log('Check Battle Ready Failed', 'id:', id, cost); $async.logSwitch(arguments); return; From 83103534130827e76a9d35a963d6cd1693257158 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 18 Nov 2025 19:24:28 +0800 Subject: [PATCH 111/216] =?UTF-8?q?2.90.56=20=E8=B0=83=E6=95=B4ui=E5=8F=8A?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=A3=85=E5=A4=87=E6=A3=80=E6=9F=A5=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ffacf09f..72180f2a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.55 +// @version 2.90.56 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -899,11 +899,11 @@ optionBox.innerHTML = [ '
      ', '

      hvAutoAttack

      ', - ' 更新历史更新歷史ChangeLog', - ' 使用说明README', ' ', (g('option')?.optionStandalone ? isIsekai ? '当前为异世界单独配置當前為異世界單獨配置Using Isekai standalone option' : '当前为恒定世界单独配置當前為恆定世界單獨配置Using Persistent standalone option' : ''), - ' by Koko191
      ', + '
      更新历史更新歷史ChangeLog', + ' 使用说明README', + ' by Koko191
      ', '
      ', '
      ', @@ -1485,9 +1485,10 @@ if (group.length + 1 === gE('select[name="groupChoose"]>option', 'all', customizeBox).length) { return; } - gE('select[name="groupChoose"]', customizeBox).textContent = ''; + const select = gE('select[name="groupChoose"]', customizeBox); + select.textContent = ''; for (let i = 0; i <= group.length; i++) { - const option = gE('select[name="groupChoose"]', customizeBox).appendChild(cE('option')); + const option = select.appendChild(cE('option')); if (i === group.length) { option.value = 'new'; option.textContent = 'new'; @@ -1515,6 +1516,7 @@ gE('.customizeBox').style.zIndex = 5; gE('.customizeBox').style.top = `${position.bottom - bodyPosition.top}px`; gE('.customizeBox').style.left = `${position.left - bodyPosition.left}px`; + gE('.customizeBox').style.cssText += `display: block; height: ${gE('.customizeGroup', 'all', g('customizeTarget')).length * 30 + 30}px;` }; // 标签页-主要选项 gE('input[name="pauseHotkeyStr"]', optionBox).onkeyup = function (e) { @@ -1969,6 +1971,7 @@ '', '', ].join(''); + customizeBox.style.cssText += 'display: none;'; customizeBox.innerHTML = [ '??', `${String.fromCharCode(0x21F1.toString(10))}`, @@ -3017,8 +3020,7 @@ query = 'ar'; } query = `?s=Battle&ss=${query}`; - - if (id === 'gr' && (option.checkSupplyGF && !checkSupply(true)) || (option.repairValueGF && !await asyncCheckRepair(true))) { + if (id === 'gr' && ((option.checkSupplyGF && !checkSupply(true)) || (option.repairValueGF && !await asyncCheckRepair(true)))) { console.log('Check Battle Ready Failed', 'id:', id, cost); $async.logSwitch(arguments); return; From 650b6c1fe57a32d634e01dfcc4bf55ec17b51fd2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 18 Nov 2025 19:50:05 +0800 Subject: [PATCH 112/216] =?UTF-8?q?2.90.57=20=E4=BF=AE=E6=AD=A3=E6=9D=83?= =?UTF-8?q?=E9=87=8Ddebuff=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 72180f2a..17c23962 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.56 +// @version 2.90.57 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3813,7 +3813,7 @@ weight += yggdrasilExtraWeight; // yggdrasilExtraWeight.defalut -1000 } for (j in skillLib) { - if (gE(`img[src*="${skillLib[j].img}"]`, monsterBuff[i])) { + if (gE(`img[src*="/${skillLib[j].img}"]`, monsterBuff[i])) { weight += g('option').weight[j]; } } From 13bf40a217aa8cd958ccd7c6e3f803a071a809b2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 18 Nov 2025 21:48:44 +0800 Subject: [PATCH 113/216] =?UTF-8?q?2.90.58=20=E5=A2=9E=E5=8A=A0=E6=96=B0?= =?UTF-8?q?=E7=9A=84buff/debuff=E6=9D=83=E9=87=8D=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 146 +++++++++++++++--- 1 file changed, 127 insertions(+), 19 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 17c23962..7e4731fc 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.57 +// @version 2.90.58 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -50,6 +50,15 @@ const _1m = 60 * _1s; const _1h = 60 * _1m; const _1d = 24 * _1h; + const attackStatusType = [ + '物理物理Physical', + 'Fire', + 'Cold', + 'Elec', + 'Wind', + 'Divine', + 'Forbidden', + ]; const monsterStateKeys = { obj: `div.btm1`, lv: `div.btm2`, name: `div.btm3`, bars: `div.btm4>div.btm5`, buffs: `div.btm6` } const [$async, $debug, $ajax] = [initAsync(), initDebug(), initAjax()]; for (let check of [checkIsHV, checkIsWindowTop, checkOption]) { @@ -1230,11 +1239,11 @@ '
      ', ' 攻击规则攻擊規則Attack Rule 示例Example', - '
      1. 初始血量权重=Log10(目标血量/场上最低血量)初始血量權重=Log10(目標血量/場上最低血量)BaseHpWeight = BaseHpRatio*Log10(TargetHP/MaxHPOnField)
      ', + '
      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)
      ', + '
      2. 初始权重与下述各Buff权重相加初始權重與下述各Buff權重相加PW(X) = BaseHpWeight + Accumulated_Weight_of_Deprecating_Spells_In_Effect(X)
      ', ' 虚弱(We)虛弱(We)Weaken: ', ' 致盲(Bl)致盲(Bl)Blind: ', ' 缓慢(Slo)緩慢(Slo)Slow: ', @@ -1247,10 +1256,39 @@ ' 枯竭(Dr)枯竭(Dr)Drain: ', ' 魔磁网(MN)魔磁網(MN)MagNet: ', ' 眩晕(St)眩暈(St)Stunned:
      ', - ' 魔力合流(CM)魔力合流(CM)Coalesced Mana:
      ', + ' 魔力合流()魔力合流(CM)Coalesced Mana:
      ', + ' 焚燒的靈魂(BS)焚燒的靈魂(BS)Burning Soul: ', + ' 鮮美的靈魂(RS)鮮美的靈魂(RS)Ripened Soul:
      ', + + ' 敌方增益,暂不清楚具体效果,按0权重计算敵方增益,暫不清楚具體效果,按0權重計算Enemy Procs, Evvecf value unknown, weight as 0 for now.:
      ', + + ' 吸收结界(AW)吸收結界(AW)Absorbing Ward: ', + ' 姊妹们的盛怒(FoS)姊妹們的盛怒(FoS)Fury of the Sisters:
      ', + ' 未来的悲叹(LoF)未來的悲歎(LoF)Lamentations of the Future: ', + ' 昔日的凄叫(SoP)昔日的淒叫(SoP)Screams of the Past:
      ', + ' 此刻的恸哭(WoP)此刻的慟哭(WoP)Wailings of the Present:
      ', + + ' 降抗性和攻击模式属性相同时降抗性和攻擊模式屬性相同時While elements between Resistance-lower-debuff and Attack-Mode matches [' + attackStatusType[g('attackStatus')] + '] :
      ', + + ' 灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin: ', + ' 冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs:
      ', + ' 湍流的空气(TA)湍流的空氣(TA)Turbulent Air: ', + ' 深层的烧伤(DB)深層的燒傷(DB)Deep Burns:
      ', + ' 崩溃的防御(BD)崩潰的防禦(BD)Breached Defense: ', + ' 钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack:
      ', + + ' 降抗性和攻击模式属性不相同时降抗性和攻擊模式屬性不相同時While elements between Resistance-lower-debuff and Attack-Mode NOT matches [' + attackStatusType[g('attackStatus')] + '] :
      ', + + ' 灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin: ', + ' 冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs:
      ', + ' 湍流的空气(TA)湍流的空氣(TA)Turbulent Air: ', + ' 深层的烧伤(DB)深層的燒傷(DB)Deep Burns:
      ', + ' 崩溃的防御(BD)崩潰的防禦(BD)Breached Defense: ', + ' 钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack:
      ', + '
      ', - '
      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
      ', + '
      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%)`
      ', @@ -3080,15 +3118,7 @@ const div = gE('#hvAABox2').appendChild(cE('div')); div.className = 'hvAALog'; } - const status = [ - '物理物理Physical', - 'Fire', - 'Cold', - 'Elec', - 'Wind', - 'Divine', - 'Forbidden', - ]; + function getBattleTypeDisplay(isTitle) { const battleInfoList = { 'gr': { @@ -3204,7 +3234,7 @@ const currentTurn = (battle.turn ?? 0) + 1; gE('.hvAALog').innerHTML = [ - `攻击模式攻擊模式Attack Mode: ${status[g('attackStatus')]}`, + `攻击模式攻擊模式Attack Mode: ${attackStatusType[g('attackStatus')]}`, `${isIsekai ? '异世界異世界Isekai' : '恒定世界恆定世界Persistent'}`, // 战役模式显示 `${getBattleTypeDisplay()}`, // 战役模式显示 `R${battle.roundNow}/${battle.roundAll}:T${currentTurn}`, @@ -3794,6 +3824,67 @@ name: 'Bleeding Wound', img: 'wpn_bleed', }, + AW: { + name: 'Absorbing Ward', + img: 'absorb', + }, + + FoS: { + name: 'Fury of the Sisters', + img: 'trio_furyofthesisters', + }, + LoF: { + name: 'Lamentations of the Future', + img: 'trio_skuld', + }, + SoP: { + name: 'Screams of the Past', + img: 'trio_urd', + }, + WoP: { + name: 'Wailings of the Present', + img: 'trio_verdandi', + }, + + SS: { + name: 'Searing Skin', + img: 'firedot', + elem: 2, + }, + FL: { + name: 'Freezing Limbs', + img: 'coldslow', + elem: 1, + }, + TA: { + name: 'Turbulent Air', + img: 'windmiss', + elem: 4, + }, + DB: { + name: 'Deep Burns', + img: 'elecweak', + elem: 3, + }, + BD: { + name: 'Breached Defense', + img: 'holybreach', + elem: 6, + }, + BA: { + name: 'Blunted Attack', + img: 'darknerf', + elem: 5, + }, + + BS: { + name: 'Burning Soul', + img: 'soulfire', + }, + RS: { + name: 'Ripened Soul', + img: 'ripesoul', + }, }; const monsterBuff = gE(monsterStateKeys.buffs, 'all'); const hpMin = Math.min.apply(null, hpArray); @@ -3807,14 +3898,31 @@ continue; } let weight = baseHpRatio * Math.log10(monsterStatus[i].hpNow / hpMin); // > 0 生命越低权重越低优先级越高 - monsterStatus[i].hpWeight = weight; + // monsterStatus[i].hpWeight = weight; const name = gE(`${monsterStateKeys.name}>div>div`, monsterBuff[i].parentNode).innerText; if (yggdrasilExtraWeight && ('Yggdrasil' === name || '世界树 Yggdrasil' === name)) { // 默认设置下,任何情况都优先击杀群体大量回血的boss"Yggdrasil" weight += yggdrasilExtraWeight; // yggdrasilExtraWeight.defalut -1000 } + const known = {}; for (j in skillLib) { - if (gE(`img[src*="/${skillLib[j].img}"]`, monsterBuff[i])) { - weight += g('option').weight[j]; + if (!gE(`img[src*="/${skillLib[j].img}"]`, monsterBuff[i])) { + continue; + } + known[skillLib[j].img] = skillLib[j]; + if (skillLib[j].elem && skillLib[j].elem !== g('attackStatus')) { + weight += g('option').weight[`${j}1`] ?? 0; + continue; + } + weight += g('option').weight[j] ?? 0; + } + let unknown = gE(`img`, 'all', monsterBuff[i]); + if (unknown?.length) { + unknown = Array.from(unknown).filter(buff => { + const img = buff.src.match(/\/y\/e\/(.*)\.png/)[1]; + return !(Object.keys(known).includes(img)); + }).map(buff=>`${buff.getAttribute('onmouseover').match(/^battle.set_infopane_effect\('(.+)', '.*', .+\)/)[1]}: ${buff.src.match(/\/y\/e\/(.*)\.png/)[1]}`); + if (unknown.length) { + console.log('unsupported buff weight:', unknown); } } monsterStatus[i].finWeight = weight; From b03de62a3b2e9276185a8efd6c1793d6df9ffa8f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 19 Nov 2025 00:54:31 +0800 Subject: [PATCH 114/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 7e4731fc..b9c98ba7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -589,10 +589,10 @@ return; } const button = parent.appendChild(cE('button')); - button.innerHTML = '暂停暫停Pause'; + button.innerHTML = `暂停暫停Pause(${g('option').pauseHotkeyStr})`; if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - button.innerHTML = '继续繼續Continue'; + button.innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; } button.className = 'pauseChange'; button.onclick = pauseChange; @@ -617,7 +617,7 @@ return; } const button = parent.appendChild(cE('button')); - button.innerHTML = '步进步進StepIn'; + button.innerHTML = `步进步進StepIn(${g('option').stepInHotkeyStr})`; button.className = 'stepIn'; button.onclick = stepIn; } @@ -2334,7 +2334,7 @@ function pauseChange() { // 暂停状态更改 if (getValue('disabled')) { if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '暂停暫停Pause'; + gE('.pauseChange').innerHTML = `暂停暫停Pause(${g('option').pauseHotkeyStr})`; } document.title = gE('#navbar') ? 'The Hentaiverse' : getValue('disabled'); delValue(0); @@ -2343,7 +2343,7 @@ } } else { if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = '继续繼續Continue'; + gE('.pauseChange').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; } setValue('disabled', document.title); document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); @@ -3256,7 +3256,7 @@ if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - gE('#hvAABox2>button').innerHTML = '继续繼續Continue'; + gE('#hvAABox2>button').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; return; } battle = getValue('battle', true); From 2bb408cc7be07ed9a71478960e8e89a18f0f9c0c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 19 Nov 2025 13:16:45 +0800 Subject: [PATCH 115/216] =?UTF-8?q?2.90.59=20=E4=BF=AE=E6=AD=A3ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b9c98ba7..7946039d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.58 +// @version 2.90.59 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1288,7 +1288,7 @@ '
      ', '
      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
      ', + '
      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%)`
      ', From ec9cbb96359a9cb2af8f783fd45f4adec8db6ae5 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 19 Nov 2025 17:24:49 +0800 Subject: [PATCH 116/216] =?UTF-8?q?2.90.60=20=E6=B7=BB=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E5=85=88=E7=AD=89=E5=BE=85=E9=81=AD=E9=81=87=E6=88=98=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 7946039d..1ec65c8d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.59 +// @version 2.90.60 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -998,7 +998,10 @@ '
      ', '
      ', - '
      ', + '

      ', + '
      ', + '
      ', '
      ;
      ', ' 进行的竞技场相对应等级進行的競技場相對應等級The levels of the Arena you want to complete: ', @@ -2857,7 +2860,7 @@ } const encounter = getEncounter(); const count = encounter.filter(e => e.href).length; - + const option = g('option'); const now = time(0); const last = encounter[0]?.time ?? getValue('lastEH', true) ?? 0; // 上次遭遇 或 上次打开EH 或 0 let cd; @@ -2878,30 +2881,30 @@ } return ui; })(); - + const waitCD = option.encounterWaitCD ?? 0; const missed = count - encounter.filter(e => e.encountered && e.href).length; if (count === 24) { ui.style.cssText += 'color:orange!important;'; - } else if (!cd) { + } else if (cd <= waitCD) { 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 ) { + if (engage) { if (!cd) { onEncounter(); return true; } - if (cd < 30* _1m && encounter[0].href && !encounter[0].encountered) { + if (cd < 30 * _1m && encounter[0].href && !encounter[0].encountered) { $ajax.openNoFetch(encounter[0].href); 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; // 让倒计时显示更平滑 + let interval = cd > _1h ? _1m : (!option.encounterQuickCheck || cd > _1m) ? _1s : 80; + interval = (option.encounterQuickCheck && cd > _1m) ? (interval - cd % interval) / 4 : interval; // 让倒计时显示更平滑 setTimeout(() => updateEncounter(engage), interval); - return false; + return cd <= waitCD; } catch (e) { console.error(e) } } async function onEncounter() { try { From 76c8b74f96d8366dd941aee4725738a1e72e7263 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 20 Nov 2025 15:51:33 +0800 Subject: [PATCH 117/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1ec65c8d..fd9e2c51 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2484,7 +2484,7 @@ $async.logSwitch(arguments); const option = g('option'); const ready = { - isChecked: () => ready.supply && ready.repair, + isChecked: () => ready.supply && ready.repair && ready.encounter, }; const idleStart = time(0); await Promise.all([ @@ -2550,7 +2550,7 @@ } ready.encounterUpdated = true; $async.logSwitch(arguments); - await updateEncounter(option.encounter); + ready.encounter ||= await updateEncounter(option.encounter); $async.logSwitch(arguments); } catch (e) { console.error(e) } } } catch (e) { console.error(e) } } From a090fc56b487fc324b9c61baf59408c4d592141d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 20 Nov 2025 20:02:35 +0800 Subject: [PATCH 118/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index fd9e2c51..5cc6c7fc 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2550,7 +2550,7 @@ } ready.encounterUpdated = true; $async.logSwitch(arguments); - ready.encounter ||= await updateEncounter(option.encounter); + ready.encounter ||= !(await updateEncounter(option.encounter)); $async.logSwitch(arguments); } catch (e) { console.error(e) } } } catch (e) { console.error(e) } } From 4fba280fa9500a3173af7e0ba9831faefbb6f6bb Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 21 Nov 2025 15:07:59 +0800 Subject: [PATCH 119/216] 2.90.61 fix async ready condition --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5cc6c7fc..38a4030e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.60 +// @version 2.90.61 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2904,7 +2904,7 @@ let interval = cd > _1h ? _1m : (!option.encounterQuickCheck || cd > _1m) ? _1s : 80; interval = (option.encounterQuickCheck && cd > _1m) ? (interval - cd % interval) / 4 : interval; // 让倒计时显示更平滑 setTimeout(() => updateEncounter(engage), interval); - return cd <= waitCD; + return engage && cd <= waitCD; } catch (e) { console.error(e) } } async function onEncounter() { try { From a398f9e87290330fe939e360b7fb83a3a1cc9d9f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 21 Nov 2025 18:12:20 +0800 Subject: [PATCH 120/216] 2.90.62 apply riddle popup to adjust new version, rimove RiddleLimite+ since out of --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 90 +++---------------- 1 file changed, 14 insertions(+), 76 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 38a4030e..5052d741 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.61 +// @version 2.90.62 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -341,6 +341,14 @@ if (!isFrame) { return true; } + if (window.opener) { + if (gE('#riddlecounter')) { + return true; + } + window.opener.document.location.href = window.location.href; + window.close(); + return false; + } 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); @@ -387,7 +395,7 @@ return false; } if (!g('option').riddlePopup || window.opener) { - riddleAlert(); // 答题警报 + setAlarm('Riddle'); return true; } window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); @@ -592,7 +600,7 @@ button.innerHTML = `暂停暫停Pause(${g('option').pauseHotkeyStr})`; if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - button.innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + button.innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; } button.className = 'pauseChange'; button.onclick = pauseChange; @@ -938,8 +946,6 @@ ' ; ', '
      在任意页面停留

      在任意頁面停留

      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: ', @@ -2345,8 +2351,9 @@ onBattleRound(); } } else { + console.trace('pauseChange'); if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + gE('.pauseChange').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; } setValue('disabled', document.title); document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); @@ -2379,75 +2386,6 @@ } } - // 答题// - function riddleAlert() { // 答题警报 - if (window.opener) { - 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; - } - }; - 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 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; - } - 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)]); - } - }; - for (let i = 0; i < 30; i++) { - setTimeout(checkTime, i * _1s); - } - - 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 quickSite() { // 快捷站点 const quickSiteBar = gE('body').appendChild(cE('div')); @@ -3259,7 +3197,7 @@ if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - gE('#hvAABox2>button').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + gE('#hvAABox2>button').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; return; } battle = getValue('battle', true); From d18034a92f8560fd2cff4bb78b20e7cc6fa3d4f9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 21 Nov 2025 18:16:13 +0800 Subject: [PATCH 121/216] 2.90.63 apply riddle popup to adjust new version, remove RiddleLimite+ since out of date --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5052d741..417e7919 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.62 +// @version 2.90.63 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -338,7 +338,7 @@ } function checkIsWindowTop() { - if (!isFrame) { + if (!isFrame && !window.opener) { return true; } if (window.opener) { From 193ac5239c4310d32c0b4b7da78ead5dc6cfa55c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 02:25:13 +0800 Subject: [PATCH 122/216] 2.90.64 fix SkipWhileDefeat bugs --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 417e7919..767f6d0b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.63 +// @version 2.90.64 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -473,6 +473,14 @@ return new Promise(resolve => setTimeout(resolve, ms)); } + function setTimeoutOrExecute(resolve, ms) { + if (ms) { + setTimeout(resolve, ms); + return; + } + resolve(); + } + function gE(ele, mode, parent) { // 获取元素 if (typeof ele === 'object') { return ele; @@ -2750,7 +2758,8 @@ return true; } if (staminaChecked === 0) { // failed currently - setTimeout(method, Math.floor(time(0) / _1h + 1) * _1h - time(0)); + const now = time(0); + setTimeout(method, Math.floor(now / _1h + 1) * _1h - now); document.title = `[S!]` + document.title; } else { // case -1: // failed with nature recover document.title = `[S!!]` + document.title; @@ -3287,13 +3296,14 @@ if (!range) { return { id: getMonsterID(target), rank: Number.MAX_SAFE_INTEGER }; } - const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (g('option').centralExtraRatio / 100) ?? 0 : 0)); + const option = g('option'); + const centralExtraWeight = -1 * Math.log10(1 + (isWeaponAttack ? (option.centralExtraRatio / 100) ?? 0 : 0)); 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 unreachableWeight = option.unreachableWeight; let minRank = Number.MAX_SAFE_INTEGER; for (let i = order - range; i <= order + range; i++) { if (i < 0 || i >= msTemp.length || msTemp[i].isDead) { @@ -3323,7 +3333,8 @@ } function autoPause() { - if (g('option').autoPause && checkCondition(g('option').pauseCondition)) { + const option = g('option'); + if (option.autoPause && checkCondition(option.pauseCondition)) { pauseChange(); return true; } @@ -3331,7 +3342,8 @@ } function autoDefend() { - if (g('option').defend && checkCondition(g('option').defendCondition)) { + const option = g('option'); + if (option.defend && checkCondition(option.defendCondition)) { gE('#ckey_defend').click(); return true; } @@ -3340,15 +3352,12 @@ function setExitBattleTimeout(alarm) { setAlarm(alarm); - if (alarm === 'SkipDefeated') return; - delValue(1); - if (g('option').ExitBattleWaitTime) { - setTimeout(() => { - $ajax.open(getValue('lastHref')); - }, g('option').ExitBattleWaitTime * _1s); + const option = g('option'); + if (alarm === 'Defeat' && !option.autoSkipDefeated) { return; } - $ajax.open(getValue('lastHref')); + delValue(1); + setTimeoutOrExecute(() => $ajax.open(getValue('lastHref')), option.ExitBattleWaitTime * _1s); } function reloader() { @@ -3372,13 +3381,14 @@ const eventStart = cE('a'); eventStart.id = 'eventStart'; eventStart.onclick = function () { + const option = g('option'); a = unsafeWindow.info; - for (let t in g('option').battleUnresponsive) { - if (g('option').battleUnresponsive[t]) { - battleUnresponsive[t].timeout = setTimeout(() => onBattleUnresponsive(battleUnresponsive[t].method), Math.max(1, g('option').battleUnresponsiveTime[t]) * _1s); + for (let t in option.battleUnresponsive) { + if (option.battleUnresponsive[t]) { + battleUnresponsive[t].timeout = setTimeout(() => onBattleUnresponsive(battleUnresponsive[t].method), Math.max(1, option.battleUnresponsiveTime[t]) * _1s); } } - if (g('option').recordUsage) { + if (option.recordUsage) { obj = { mode: a.mode, }; @@ -3397,6 +3407,7 @@ const eventEnd = cE('a'); eventEnd.id = 'eventEnd'; eventEnd.onclick = function () { + const option = g('option'); const timeNow = time(0); g('runSpeed', (1000 / (timeNow - g('timeNow'))).toFixed(2)); g('timeNow', timeNow); @@ -3405,7 +3416,7 @@ const bossDead = gE(`${monsterStateKeys.obj}[style*="opacity"] ${monsterStateKeys.lv}[style*="background"]`, 'all').length; g('bossAlive', g('bossAll') - bossDead); const battleLog = gE('#textlog>tbody>tr>td', 'all'); - if (g('option').recordUsage) { + if (option.recordUsage) { obj.log = battleLog; recordUsage(obj); } @@ -3414,10 +3425,10 @@ onBattleRound(); return; } - if (g('option').dropMonitor) { + if (option.dropMonitor) { dropMonitor(battleLog); } - if (g('option').recordUsage) { + if (option.recordUsage) { recordUsage2(); } onRoundEnd(); @@ -3426,19 +3437,12 @@ await pauseAsync(_1s); return await onRoundEnd(); } - if (g('battle').roundNow === g('battle').roundAll) { // Next Round - if (g('monsterAlive') > 0) { // Defeat - setExitBattleTimeout(g('option').autoSkipDefeated ? 'SkipDefeated' : 'Defeat'); - } - if (g('battle').roundNow === g('battle').roundAll) { // Victory - setExitBattleTimeout('Victory'); - } - } else { - if (g('option').NewRoundWaitTime) { - setTimeout(onNewRound, g('option').NewRoundWaitTime * _1s); - } else { - onNewRound(); - } + if (g('monsterAlive') > 0) { // Defeat + setExitBattleTimeout('Defeat'); + } else if (g('battle').roundNow === g('battle').roundAll) { // Victory + setExitBattleTimeout('Victory'); + } else { // Next Round + setTimeoutOrExecute(onNewRound, option.NewRoundWaitTime * _1s); } clearBattleUnresponsive(); From 61384ad880cd7aef46c460a2ab2448d46a3e810d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 04:34:24 +0800 Subject: [PATCH 123/216] 2.90.65 fix ui bug and optimize page reload --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 767f6d0b..c3c28ce1 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.64 +// @version 2.90.65 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -455,17 +455,24 @@ // ----------methods---------- // 通用// function goto() { // 前进 - window.location.href = window.location; + window.location.reload(); setTimeout(goto, 5000); } function gotoAlt(isAltOnly) { const hv = 'hentaiverse.org'; const alt = 'alt.' + hv; + const current = window.location.href; + let next; if (window.location.host === hv) { - window.location.href = window.location.href.replace(`://${hv}`, `://${alt}`); + next = current.replace(`://${hv}`, `://${alt}`); } else if (window.location.host === alt) { - window.location.href = isAltOnly ? window.location : window.location.href.replace(`://${alt}`, `://${hv}`); + next = isAltOnly ? current : current.replace(`://${alt}`, `://${hv}`); + } + if (current === next) { + window.location.reload(); + } else { + window.location.href = next; } } @@ -605,10 +612,10 @@ return; } const button = parent.appendChild(cE('button')); - button.innerHTML = `暂停暫停Pause(${g('option').pauseHotkeyStr})`; + button.innerHTML = `暂停暫停Pause${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - button.innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + button.innerHTML = `继续繼續Continue${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; } button.className = 'pauseChange'; button.onclick = pauseChange; @@ -633,7 +640,7 @@ return; } const button = parent.appendChild(cE('button')); - button.innerHTML = `步进步進StepIn(${g('option').stepInHotkeyStr})`; + button.innerHTML = `步进步進StepIn${(g('option').stepInHotkey && g('option').stepInHotkeyStr) ? `(${g('option').stepInHotkeyStr})` : '' }`; button.className = 'stepIn'; button.onclick = stepIn; } @@ -2351,7 +2358,7 @@ function pauseChange() { // 暂停状态更改 if (getValue('disabled')) { if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = `暂停暫停Pause(${g('option').pauseHotkeyStr})`; + gE('.pauseChange').innerHTML = `暂停暫停Pause${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; } document.title = gE('#navbar') ? 'The Hentaiverse' : getValue('disabled'); delValue(0); @@ -2361,7 +2368,7 @@ } else { console.trace('pauseChange'); if (gE('.pauseChange')) { - gE('.pauseChange').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + gE('.pauseChange').innerHTML = `继续繼續Continue${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; } setValue('disabled', document.title); document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); @@ -3206,7 +3213,7 @@ if (getValue('disabled')) { // 如果禁用 document.title = _alert(-1, 'hvAutoAttack暂停中', 'hvAutoAttack暫停中', 'hvAutoAttack Paused'); - gE('#hvAABox2>button').innerHTML = `继续繼續Continue(${g('option').pauseHotkeyStr})`; + gE('#hvAABox2>button').innerHTML = `继续繼續Continue${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; return; } battle = getValue('battle', true); @@ -3686,7 +3693,7 @@ if (bugLog[i].textContent.match(isBug)) { bugLog[i].className = 'tlbWARN'; setTimeout(() => { // 间隔时间以避免持续刷新 - window.location.href = window.location;// 刷新移除问题元素 + window.location.reload();// 刷新移除问题元素 }, 700); } else { bugLog[i].className = 'tlbQRA'; From 719ba9e41615590e7e1fead2a46dc7993aa5caec Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 13:03:35 +0800 Subject: [PATCH 124/216] 2.90.66 Window load and reload --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c3c28ce1..8e35591d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.65 +// @version 2.90.66 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -268,6 +268,8 @@ filtered[0].encountered ??= time(0); } setEncounter(encounter); + $ajax.openNoFetch(getValue('lastHref')); + return; } try { @@ -472,7 +474,7 @@ if (current === next) { window.location.reload(); } else { - window.location.href = next; + $ajax.openNoFetch(next); } } @@ -2425,7 +2427,7 @@ // 若不启用自动跳转 return; } - window.location.href = `${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`; + $ajax.openNoFetch(`${href.slice(0, href.indexOf('.org') + 4)}/${isIsekai ? '' : 'isekai/'}`); } async function asyncOnIdle() { try { @@ -3364,7 +3366,7 @@ return; } delValue(1); - setTimeoutOrExecute(() => $ajax.open(getValue('lastHref')), option.ExitBattleWaitTime * _1s); + setTimeoutOrExecute(() => $ajax.openNoFetch(getValue('lastHref')), option.ExitBattleWaitTime * _1s); } function reloader() { From 70723be6770b23cf46f565bdb25a5a7da85ecd30 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 13:07:32 +0800 Subject: [PATCH 125/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8e35591d..d3e9c204 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -471,11 +471,12 @@ } else if (window.location.host === alt) { next = isAltOnly ? current : current.replace(`://${alt}`, `://${hv}`); } - if (current === next) { - window.location.reload(); - } else { $ajax.openNoFetch(next); - } + // if (current === next) { + // goto(); + // } else { + // $ajax.openNoFetch(next); + // } } function pauseAsync(ms) { @@ -3035,7 +3036,7 @@ writeArenaStart(); await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); - if (g('option').altBattleFirst && await $ajax.fetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + if (g('option').altBattleFirst && await $ajax.fetch(window.location.host)) { console.log('Arena goto alt'); gotoAlt(true); } else { From c450590b93909101e7348330f45b549853407da4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 13:36:45 +0800 Subject: [PATCH 126/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d3e9c204..f5710c36 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -465,13 +465,13 @@ const hv = 'hentaiverse.org'; const alt = 'alt.' + hv; const current = window.location.href; - let next; + let next = current; if (window.location.host === hv) { next = current.replace(`://${hv}`, `://${alt}`); } else if (window.location.host === alt) { next = isAltOnly ? current : current.replace(`://${alt}`, `://${hv}`); } - $ajax.openNoFetch(next); + $ajax.openNoFetch(next); // if (current === next) { // goto(); // } else { From e2b3601baac0e9d16cd070c2925a353ef9df846e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 15:03:18 +0800 Subject: [PATCH 127/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f5710c36..64b28b59 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3036,7 +3036,7 @@ writeArenaStart(); await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); - if (g('option').altBattleFirst && await $ajax.fetch(window.location.host)) { + if (g('option').altBattleFirst && await $ajax.openNoFetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { console.log('Arena goto alt'); gotoAlt(true); } else { From c20cef92703b6489d5ef3692e8647f8e3e7aa439 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 15:35:49 +0800 Subject: [PATCH 128/216] 2.90.67 window.close try-catch and debug log --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 64b28b59..f782846a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -348,7 +348,11 @@ return true; } window.opener.document.location.href = window.location.href; - window.close(); + try { + window.close(); + } catch { + console.log(`[Failed closing popup] opener: ${window.opener}, opener.href: ${window.opener.document.location.href}, next: ${window.location.href}`); + } return false; } if (!window.top.location.href.match(`/equip/`) && (gE('#riddlecounter') || !gE('#navbar'))) { @@ -472,11 +476,6 @@ next = isAltOnly ? current : current.replace(`://${alt}`, `://${hv}`); } $ajax.openNoFetch(next); - // if (current === next) { - // goto(); - // } else { - // $ajax.openNoFetch(next); - // } } function pauseAsync(ms) { From 8da29b9ae404e3aa3b657a4ec26feb52003fd7a2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 16:11:27 +0800 Subject: [PATCH 129/216] 2.90.68 Ajax skip duplication fetch requst --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f782846a..106e5a07 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.66 +// @version 2.90.68 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -143,6 +143,11 @@ return list; }, add: function (method, url, data, onload, onerror, context = {}, headers = {}) { + const isDuplicate = this.queue.some(req => req.method === method && req.url === url && JSON.stringify(req.data) === JSON.stringify(data)); + if (isDuplicate) { + console.log('Skip duplicated fetch:', url, method, data); + return; + } method = !data ? 'GET' : method ?? 'POST'; if (method === 'POST') { headers['Content-Type'] ??= 'application/x-www-form-urlencoded'; From f040d337edd8eb5418cc705e77df2b5f83c840f7 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 17:27:59 +0800 Subject: [PATCH 130/216] 2.90.69 fix encounter nullable check; skip ability update if failed fetch or nothing changed --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 106e5a07..33de46d2 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.68 +// @version 2.90.69 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2561,6 +2561,7 @@ const html = await $ajax.fetch('?s=Character&ss=ab'); const doc = $doc(html); let ability = {}; + const loadSucceed = true; await Promise.all(Array.from(gE('#ability_treelist>div>img', 'all', doc)).map(async img => { try { const _ = img.getAttribute('onclick')?.match(/(\?s=(.*)tree=(.*))'/); @@ -2586,9 +2587,14 @@ 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) } + } catch (e) { + console.error(e); + loadSucceed = false; + } })); - setValue('ability', ability); + if (loadSucceed && JSON.stringify(ability) !== JSON.stringify(getValue('ability'))) { + setValue('ability', ability); + } $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -2857,7 +2863,7 @@ onEncounter(); return true; } - if (cd < 30 * _1m && encounter[0].href && !encounter[0].encountered) { + if (cd < 30 * _1m && encounter[0]?.href && !encounter[0].encountered) { $ajax.openNoFetch(encounter[0].href); return true; } From 883ced6e4d1b2e119830f3c075bf69057922008d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 17:39:17 +0800 Subject: [PATCH 131/216] fix dodying #170 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 33de46d2..80cec47b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -536,10 +536,10 @@ }); } - function getStartBattleButtons(document = undefined) { + function getStartBattleButtons(doc = undefined) { const buttons = []; - document ??= window.document; - gE(`img[src*="startchallenge.png"], img[src*="startgrindfest.png"]`, 'all', document).forEach((btn) => { + doc ??= document; + gE(`img[src*="startchallenge.png"], img[src*="startgrindfest.png"]`, 'all', doc).forEach((btn) => { const onclick = btn.getAttribute('onclick'); const key = btn.getAttribute('src').match(`${unsafeWindow.IMG_URL}(.*)/start(.*).png`)[1] === 'grindfest' ? 'gr' : undefined; let temp = hvVersion < 91 ? onclick.match(/init_battle\((\d+),\s*(\d+,)*'(.*?)'\)/) : onclick.match(/init_battle\((\d+)(,\d+)*\)/); From cd16d5b6054c158a9bad951ad89582f6829836df Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 22:31:33 +0800 Subject: [PATCH 132/216] 2.90.70 Try fixing iframe/popup to window.top relocation/close bugs --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 80cec47b..f19db3ab 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.69 +// @version 2.90.70 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -345,34 +345,52 @@ } function checkIsWindowTop() { - if (!isFrame && !window.opener) { - return true; - } - if (window.opener) { - if (gE('#riddlecounter')) { + const currentUrl = window.self.location.href; + if (!isFrame) { + if (!window.opener || window.opener.closed || gE('#riddlecounter')) { return true; } - window.opener.document.location.href = window.location.href; - try { - window.close(); - } catch { - console.log(`[Failed closing popup] opener: ${window.opener}, opener.href: ${window.opener.document.location.href}, next: ${window.location.href}`); - } + window.opener.location.href = currentUrl; + const isFirefox = typeof InstallTrigger !== 'undefined'; + tryClose(3, isFirefox ? 500 : 300); return false; } - if (!window.top.location.href.match(`/equip/`) && (gE('#riddlecounter') || !gE('#navbar'))) { + + if (gE('#riddlecounter') || gE('#battle_main')) { if (!window.top.location.href.endsWith(`?s=Battle`)) { setValue('lastHref', window.top.location.href); } - window.top.location.href = window.self.location.href; + window.top.location.href = currentUrl; + return false; } - if (window.location.href.indexOf(`?s=Battle&ss=ar`) !== -1 || window.location.href.indexOf(`?s=Battle&ss=rb`) !== -1) { + if (currentUrl.match(/\?s=Battle&ss=(ar|rb)/)) { loadOption(); setArenaDisplay(); } return false; } + async function safeClose(delay) { + try { window.close() } catch (e) { } + await pauseAsync(delay); + return !window || window.closed; + } + + async function tryClose(attempts, delay) { try { + await pauseAsync(delay); + window.opener = null; + window.open('', '_self'); + if (await safeClose(delay)) return; + window.location.href = 'about:blank'; + if (await safeClose(delay)) return; + attempts--; + if (attempts <= 0) { + document.body.innerHTML = '
      Auto close popup failed. Please manually close window.
      '; + return; + } + await tryClose(attempts, delay); + } catch (e) { console.error('Opener reload or popup close failed:', e) } } + function checkOption() { g('version', GM_info ? GM_info.script.version.substr(0, 4) : scriptVersion); if (!getValue('option')) { From d11a305a12ac1e6be9093ea8dcca41af998849d7 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 22 Nov 2025 22:37:20 +0800 Subject: [PATCH 133/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f19db3ab..ecb89b96 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -347,7 +347,7 @@ function checkIsWindowTop() { const currentUrl = window.self.location.href; if (!isFrame) { - if (!window.opener || window.opener.closed || gE('#riddlecounter')) { + if (!window.opener || window.opener === window.self || window.opener.closed || gE('#riddlecounter')) { return true; } window.opener.location.href = currentUrl; From b834588819d6b6fe709ba59cb43d287d1a669a6e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 23 Nov 2025 00:29:05 +0800 Subject: [PATCH 134/216] 2.90.71 deprecating abilities' level and range --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ecb89b96..5021b042 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.70 +// @version 2.90.71 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4391,16 +4391,19 @@ name: 'Sleep', id: '222', img: 'sleep', + range: { 4207: [0, 0, 1] }, }, Bl: { name: 'Blind', id: '231', img: 'blind', + range: { 4206: [0, 0, 1] }, }, Slo: { name: 'Slow', id: '221', img: 'slow', + range: { 4211: [0, 0, 0, 1, 1] }, }, Im: { name: 'Imperil', @@ -4412,11 +4415,13 @@ name: 'MagNet', id: '233', img: 'magnet', + range: { 4211: [0, 0, 0, 0, 1] }, }, Si: { name: 'Silence', id: '232', img: 'silence', + range: { 4211: [0, 0, 0, 1] }, }, Dr: { name: 'Drain', @@ -4433,6 +4438,7 @@ name: 'Confuse', id: '223', img: 'confuse', + range: { 4207: [0, 0, 1] }, }, }; if (!isOn(skillLib[buff].id)) { // 技能不可用 From 9286d1959862daf9a12f3d4b38f51a21cd173c2f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 23 Nov 2025 01:40:10 +0800 Subject: [PATCH 135/216] =?UTF-8?q?2.90.72=20=E9=87=8D=E6=96=B0=E5=8A=A0?= =?UTF-8?q?=E8=BD=BDopener=E6=97=B6=E5=A2=9E=E5=8A=A0try-catch=EF=BC=8C?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=98=BE=E7=A4=BA=E5=85=B7=E4=BD=93?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=92=8C=E5=89=8D=E5=90=8Ehref=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E5=86=8D=E6=AC=A1=E4=BD=BF=E7=94=A8opener=E5=8E=9F?= =?UTF-8?q?=E6=9C=AC=E7=9A=84url=E8=BF=9B=E8=A1=8C=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5021b042..9f6d5b8f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.71 +// @version 2.90.72 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -350,7 +350,12 @@ if (!window.opener || window.opener === window.self || window.opener.closed || gE('#riddlecounter')) { return true; } - window.opener.location.href = currentUrl; + try { + window.opener.location.href = currentUrl; + } catch (e) { + console.log(e, `opener: ${window.opener.location.href}, current: ${currentUrl}`); + window.opener.location.href = window.opener.location.href; + } const isFirefox = typeof InstallTrigger !== 'undefined'; tryClose(3, isFirefox ? 500 : 300); return false; From 9107e008427460642eec65761bd4098c9f4f278a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 23 Nov 2025 11:22:46 +0800 Subject: [PATCH 136/216] =?UTF-8?q?2.90.73=20=E8=B0=83=E6=95=B4=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E6=9A=82=E5=81=9C=E7=BB=93=E6=9D=9F=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E4=BB=8E=E9=80=92=E5=BD=92=E6=94=B9=E4=B8=BA=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=EF=BC=9B=E8=B0=83=E6=95=B4=E7=AB=9E=E6=8A=80=E5=9C=BA?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E5=89=8D=E7=9A=84=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 122 ++++++------------ 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9f6d5b8f..875fb78c 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.72 +// @version 2.90.73 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -353,7 +353,7 @@ try { window.opener.location.href = currentUrl; } catch (e) { - console.log(e, `opener: ${window.opener.location.href}, current: ${currentUrl}`); + console.error(e, `opener: ${window.opener.location.href}, current: ${currentUrl}`); window.opener.location.href = window.opener.location.href; } const isFirefox = typeof InstallTrigger !== 'undefined'; @@ -482,7 +482,7 @@ setValue('battleCode', `${time(1)}: ${g('battle')?.roundType?.toUpperCase()}-${g('battle')?.roundAll}`); } onBattleRound(); - updateEncounter(false, true); + updateEncounter(false); return true; } @@ -510,6 +510,12 @@ return new Promise(resolve => setTimeout(resolve, ms)); } + async function waitPause(ms = _1s) { + while (getValue('disabled')) { + await pauseAsync(ms); + } + } + function setTimeoutOrExecute(resolve, ms) { if (ms) { setTimeout(resolve, ms); @@ -2396,7 +2402,6 @@ onBattleRound(); } } else { - console.trace('pauseChange'); if (gE('.pauseChange')) { gE('.pauseChange').innerHTML = `继续繼續Continue${(g('option').pauseHotkey && g('option').pauseHotkeyStr) ? `(${g('option').pauseHotkeyStr})` : '' }`; } @@ -2459,11 +2464,8 @@ } async function asyncOnIdle() { try { - updateEncounter(false); - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncOnIdle(); - } + await updateEncounter(false); + await waitPause(); $async.logSwitch(arguments); const option = g('option'); const ready = { @@ -2576,10 +2578,7 @@ } async function asyncSetAbilityData() { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetAbilityData(); - } + await waitPause(); $async.logSwitch(arguments); const html = await $ajax.fetch('?s=Character&ss=ab'); const doc = $doc(html); @@ -2625,10 +2624,7 @@ if (isIsekai || !g('option').restoreStamina) { return; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetEnergyDrinkHathperk(); - } + await waitPause(); $async.logSwitch(arguments); let currentID = getCurrentUser(); let perk = getValue('staminaHathperk') ?? {}; @@ -2649,10 +2645,7 @@ } catch (e) { console.error(e) } } async function asyncSetStamina() { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncSetStamina(); - } + await waitPause(); $async.logSwitch(arguments); const html = await $ajax.fetch(window.location.href); setValue('staminaTime', Math.floor(time(0) / 1000 / 60 / 60)); @@ -2664,10 +2657,7 @@ if (!g('option').checkSupply && (isIsekai || !g('option').restoreStamina)) { return; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncGetItems(); - } + await waitPause(); $async.logSwitch(arguments); const html = await $ajax.fetch('?s=Character&ss=it'); const items = {}; @@ -2712,10 +2702,7 @@ if (!g('option').repair) { return true; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckRepair(); - } + await waitPause(); $async.logSwitch(arguments); let eqps; const threshold = isGrindFestStandalone ? g('option').repairValueGF : g('option').repairValue; @@ -2764,10 +2751,7 @@ if (!option.equStorage) { return true; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await asyncCheckEquStorage(); - } + await waitPause(); $async.logSwitch(arguments); let count; if (hvVersion < 91) { @@ -2783,11 +2767,8 @@ return count * 1 <= option.equStorageValue; } catch (e) { console.error(e) }; return false; } - function checkBattleReady(method, condition = {}) { - if (getValue('disabled')) { - setTimeout(method, _1s); - return; - } + async function checkBattleReady(method, condition = {}) { + await waitPause(); if (condition.checkEncounter) { const encounter = getEncounter(); if (encounter[0]?.href && !encounter[0]?.encountered) { @@ -2839,15 +2820,11 @@ } } - async function updateEncounter(engage, isInBattle) { try { + async function updateEncounter(engage) { try { if (!g('option').encounter && !g('option').encounterDisplay) { console.log("skip encounter check"); return false; } - if (getValue('disabled')) { - await pauseAsync(_1s); - return await updateEncounter(engage, isInBattle); - } const encounter = getEncounter(); const count = encounter.filter(e => e.href).length; const option = g('option'); @@ -2866,7 +2843,7 @@ const ui = gE('body').appendChild(cE('a')); ui.className = 'encounterUI'; ui.title = `${time(3, last)}\nEncounter Time: ${count}`; - if (!isInBattle) { + if (!gE('#battle_main')) { ui.href = 'https://e-hentai.org/news.php?encounter'; } return ui; @@ -2883,10 +2860,12 @@ ui.innerHTML = `${formatTime(cd).slice(0, 2).map(cdi => cdi.toString().padStart(2, '0')).join(`:`)}[${encounter.length ? (count >= 24 ? `☯` : count) : `✪`}${missed ? `-${missed}` : ``}]`; if (engage) { if (!cd) { + await waitPause(); onEncounter(); return true; } if (cd < 30 * _1m && encounter[0]?.href && !encounter[0].encountered) { + await waitPause(); $ajax.openNoFetch(encounter[0].href); return true; } @@ -2898,13 +2877,11 @@ } catch (e) { console.error(e) } } async function onEncounter() { try { - if (!(await $ajax.fetch(href))) { // perhaps network connect not available + while (!(await $ajax.fetch(href))) { // perhaps network connect not available await pauseAsync(_1m); - onEncounter(); - return; } $async.logSwitchStrict('updateEncounter', true); - if (getValue('disabled') || getValue('battle') || !checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { + if (getValue('disabled') || getValue('battle') || !await checkBattleReady(onEncounter, { staminaLow: g('option').staminaEncounter })) { $async.logSwitchStrict('updateEncounter', false); return; } @@ -2935,10 +2912,7 @@ } catch (e) { console.error(e) } } async function updateArena(forceUpdateToken = false) { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await updateArena(forceUpdateToken); - } + await waitPause(); let arena = getValue('arena', true) ?? {}; const isToday = arena.date && time(2, arena.date) === time(2); if (forceUpdateToken || !isToday || !arena.isOptionUpdated) { @@ -2946,7 +2920,6 @@ 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 => { @@ -3033,9 +3006,9 @@ } let query; - let token = arena.token[id]; - const cost = staminaCost[id]; - if (id === 'gr') { + if (id !== 'gr') { + query = id >= 105 ? 'rb' : 'ar'; + } else { if (arena.gr <= 0) { setValue('arena', arena); idleArena(); @@ -3043,33 +3016,30 @@ return; } query = 'gr'; - } else if (id >= 105) { - query = 'rb'; - } else if (id >= 19) { - query = 'ar&page=2'; - } else { - query = 'ar'; } query = `?s=Battle&ss=${query}`; if (id === 'gr' && ((option.checkSupplyGF && !checkSupply(true)) || (option.repairValueGF && !await asyncCheckRepair(true)))) { - console.log('Check Battle Ready Failed', 'id:', id, cost); + console.log('Check gr Battle Ready Failed in supply/repair', 'id:', id); $async.logSwitch(arguments); return; } - if (!checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { + const cost = staminaCost[id]; + if (!await checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { console.log('Check Battle Ready Failed', 'id:', id, cost); $async.logSwitch(arguments); return; } + let token = arena.token[id]; if (hvVersion < 91) { token = `&inittoken=${token}`; } else { token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; } + await waitPause(); writeArenaStart(); await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); - console.log('Arena Fetch Done.', 'altBattleFirst:', g('option').altBattleFirst); - if (g('option').altBattleFirst && await $ajax.openNoFetch(href.replace('://hentaiverse', '://alt.hentaiverse'))) { + console.log('Arena Fetch Done.', 'altBattleFirst:', option.altBattleFirst); + if (option.altBattleFirst && await $ajax.fetch(href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt'))) { console.log('Arena goto alt'); gotoAlt(true); } else { @@ -3413,10 +3383,7 @@ Object.keys(battleUnresponsive).forEach(t => clearTimeout(battleUnresponsive[t].timeout)); } async function onBattleUnresponsive(method) { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await onBattleUnresponsive(); - } + await waitPause(); method(); } catch (e) { console.error(e) } } @@ -3476,10 +3443,7 @@ } onRoundEnd(); async function onRoundEnd() { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await onRoundEnd(); - } + await waitPause(); if (g('monsterAlive') > 0) { // Defeat setExitBattleTimeout('Defeat'); } else if (g('battle').roundNow === g('battle').roundAll) { // Victory @@ -3490,10 +3454,7 @@ clearBattleUnresponsive(); async function onNewRound() { try { - if (getValue('disabled')) { - await pauseAsync(_1s); - return await onNewRound(); - } + await waitPause(); if (gE('#btcp')?.innerHTML.includes("finishbattle.png")) { goto(); return; @@ -4656,8 +4617,7 @@ try { colorText = eval(colorText.replace('', rank).replace('', weights.length)); } - catch { - } + catch { } getMonster(id).style.cssText += `background: ${colorText};`; } gE(monsterStateKeys.name, getMonster(id)).style.cssText += 'display: flex; flex-direction: row;' @@ -4999,7 +4959,7 @@ } } } catch (e) { - console.log(e); + console.error(e); document.title = e; } })(); From 68d40ea1fa1952a6ae001b99890d9f1a1c9f05c3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 23 Nov 2025 15:17:14 +0800 Subject: [PATCH 137/216] =?UTF-8?q?2.90.74=20=E4=B8=8D=E5=90=AF=E7=94=A8ri?= =?UTF-8?q?ddlepopup=E6=97=B6=E8=B7=B3=E8=BF=87window.close=E7=9A=84?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=EF=BC=8C=E9=81=BF=E5=85=8DFirefox=E4=B8=AD?= =?UTF-8?q?=E4=B8=8D=E5=90=AF=E7=94=A8=E6=97=B6=E4=B9=9F=E4=BC=9A=E5=8F=97?= =?UTF-8?q?=E5=85=B6=E4=B8=8D=E5=85=BC=E5=AE=B9=E5=BD=B1=E5=93=8D=EF=BC=9B?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=B9=E7=AA=97=E7=AD=94=E9=A2=98=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=ADFirefox=E4=B8=8D=E5=85=BC=E5=AE=B9=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=EF=BC=9B=E5=A2=9E=E5=8A=A0=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E4=B8=AD=E7=9A=84=E6=8A=A5=E9=94=99=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=8C=E6=AF=8F=E4=B8=AA=E4=BF=A1=E6=81=AF=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E6=98=BE=E7=A4=BA=E9=81=BF=E5=85=8D=E5=9B=A0=E8=B7=A8?= =?UTF-8?q?=E5=9F=9F=E9=97=AE=E9=A2=98=E8=A2=AB=E5=AE=8C=E5=85=A8=E9=98=BB?= =?UTF-8?q?=E6=8C=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 875fb78c..c94c9d59 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.73 +// @version 2.90.74 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -347,13 +347,18 @@ function checkIsWindowTop() { const currentUrl = window.self.location.href; if (!isFrame) { - if (!window.opener || window.opener === window.self || window.opener.closed || gE('#riddlecounter')) { + loadOption(); + if (!g('option').riddlePopup || !window.opener || window.opener === window.self || window.opener.closed || gE('#riddlecounter')) { return true; } try { window.opener.location.href = currentUrl; } catch (e) { - console.error(e, `opener: ${window.opener.location.href}, current: ${currentUrl}`); + console.error(e); + console.error(`current: ${currentUrl}`); + console.error(`opener: ${window.opener}`); + console.error(`opener.location: ${window.opener.location}`); + console.error(`opener.location.href: ${window.opener.location.href}`); window.opener.location.href = window.opener.location.href; } const isFirefox = typeof InstallTrigger !== 'undefined'; @@ -996,7 +1001,7 @@ ' ', ' ; ', '
      在任意页面停留

      在任意頁面停留

      Idle in any page for
      秒后,进行跳转秒後,進行跳轉s, start switch check
      ', - '
      小马答题小馬答題RIDDLE: ; ', + '
      小马答题小馬答題RIDDLE: ; ', '
      ', '
      脚本行为腳本行為Script Activity', '
      暂停相关暫停相關Pause with: ', From 88c1ba29152912f945d57c00bec6c2c1389635bb Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 23 Nov 2025 15:43:39 +0800 Subject: [PATCH 138/216] =?UTF-8?q?2.90.75=20Optimization=20for=20unsafeWi?= =?UTF-8?q?ndow.battle=20loading=EF=BC=9BCheck=20unsafeWindow.battle=20or?= =?UTF-8?q?=20reload=20before=20click=20monster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c94c9d59..f54fe71f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.74 +// @version 2.90.75 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3477,8 +3477,8 @@ return; } ['#battle_right', '#battle_left'].forEach(selector => { gE('#battle_main').replaceChild(gE(selector, doc), gE(selector)); }) - unsafeWindow.battle = new unsafeWindow.Battle(); - unsafeWindow.battle.clear_infopane(); + unsafeWindow.battle = undefined; + await loadUnsafeWindowBattle(); $debug.log('______________newRound', true); newRound(true); onStepInDone(); @@ -3543,6 +3543,14 @@ gE('head').appendChild(fakeApiResponse); } + async function loadUnsafeWindowBattle() { try { + while (!unsafeWindow.battle) { + await pauseAsync(300); + unsafeWindow.battle = new unsafeWindow.Battle(); + } + unsafeWindow.battle.clear_infopane(); + } catch(e) { console.error(e) }} + function newRound(isNew) { // New Round let battle = isNew ? {} : getValue('battle', true); if (!battle) { @@ -4253,6 +4261,14 @@ return false; } + async function clickMonster(id) { + if (!unsafeWindow.battle) { + console.log('loadUnsafeWindowBattle before click monster'); + await loadUnsafeWindowBattle(); + } + getMonster(id).click(); + } + /** * INNAT / WEAPON SKILLS * @@ -4314,7 +4330,7 @@ } gE(id).click(); const range = id in rangeSkills ? rangeSkills[id] : 0; - getMonster(getRangeCenter(target, range).id).click(); + clickMonster(getRangeCenter(target, range).id); return true; } return false; @@ -4467,7 +4483,7 @@ // buff剩余持续时间大于等于警报时间 if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { gE(skillLib[buff].id).click(); - getMonster(id).click(); + clickMonster(id); return true; } @@ -4554,7 +4570,7 @@ if (!target || target.isDead) { return false; } - getMonster(getRangeCenter(target, range, !attackStatus).id).click(); + clickMonster(getRangeCenter(target, range, !attackStatus).id); return true; } From 941ce5858e4a2394f45baff240888746b6627078 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 24 Nov 2025 03:33:02 +0800 Subject: [PATCH 139/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f54fe71f..5fcec4de 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -32,7 +32,6 @@ (function () { try { 'use strict'; - const standalone = ['option', 'arena', 'drop', 'stats', 'staminaLostLog', 'battleCode', 'disabled', 'stamina', 'staminaTime', 'lastHref', 'battle', 'monsterDB', 'monsterMID', 'ability']; const sharable = ['option']; const excludeStandalone = { 'option': ['optionStandalone', 'version', 'lang'] }; @@ -2619,7 +2618,16 @@ loadSucceed = false; } })); - if (loadSucceed && JSON.stringify(ability) !== JSON.stringify(getValue('ability'))) { + if (!loadSucceed) { + ability = getValue('ability'); + } + for (let ab of Object.keys(ability)) { + if (typeof ability[ab] !== 'object') { + break; + } + ability[ab] = ability[ab].level; // old version data + } + if (JSON.stringify(ability) !== JSON.stringify(getValue('ability'))) { setValue('ability', ability); } $async.logSwitch(arguments); @@ -2726,7 +2734,7 @@ return; } const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); - return gE('.messagebox_error', )?.innerText ? undefined : id; + return gE('.messagebox_error', )?.innerText ? undefined : json[id].t; } catch (e) { console.error(e) } })); } else { const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped`; @@ -2739,12 +2747,12 @@ return; } const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); - return gE(`#e${id}`, after) ? id : undefined; + return gE(`#e${id}`, after) ? gE('.lc', eqp).childNodes[2].textContent : undefined; } catch (e) { console.error(e) } })); } eqps = eqps.filter(e=>e); if (eqps.length) { - console.log('eqps need repair: ', eqps); + console.log('eqps need repair: ', eqps.join('\n')); document.title = `[R!]` + document.title; } $async.logSwitch(arguments); @@ -2803,7 +2811,7 @@ 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()); + console.log('stamina:', stamina, '\nstamina with nature recover:', stmNR, '\nnext arena stamina cost: ', cost); if (stamina - cost >= (low ?? g('option').staminaLow) && stmNRChecked) { return 1; } @@ -2922,14 +2930,9 @@ 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=rb' - ] - await Promise.all(arena.sites.map(async site => { + await Promise.all(['gr', 'ar', 'rb'].map(async site => { try { - const doc = $doc(await $ajax.fetch(site)); + const doc = $doc(await $ajax.fetch(`?s=Battle&ss=${site}`)); getStartBattleButtons(doc).forEach(btn => { arena.token[btn.id] = btn.token ?? null; }); } catch (e) { console.error(e) } })); @@ -3067,7 +3070,7 @@ }) battle.monsterStatus.sort(objArrSort('order')); }; - $debug.log('onBattle', `\n`, JSON.stringify(battle, null, 4)); + $debug.log('onBattle', `\n`, battle); //人物状态 if (gE('#vbh')) { g('hp', gE('#vbh>div>img').offsetWidth / 500 * 100); @@ -4440,8 +4443,8 @@ if (!ranges) { continue; } - if (ability && ability[ab] && ability[ab].level) { - range = ranges[ability[ab].level]; + if (ability) { + range = ranges[ability[ab]]; } break; } @@ -4560,8 +4563,8 @@ continue; } const ability = getValue('ability', true); - if (ability && ability[ab] && ability[ab].level) { - range = ranges[ability[ab].level]; + if (ability) { + range = ranges[ability[ab]]; } break; } From 3190092076d9040ab35ce7f2024b3c486e0d777d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 27 Nov 2025 13:09:45 +0800 Subject: [PATCH 140/216] 2.90.76 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 5fcec4de..1795ead6 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.75 +// @version 2.90.76 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -644,7 +644,9 @@ setPauseButton(parent); setPauseHotkey(); setStepInButton(parent); - setStepInHotkey(parent); + setStepInHotkey(); + setAltButton(parent); + setAltHotkey(); } function setPauseButton(parent) { @@ -699,6 +701,30 @@ }, false); } + function setAltButton(parent) { + if (!g('option').altButton) { + return; + } + const button = parent.appendChild(cE('button')); + button.innerHTML = (window.location.host.includes('alt') ? `ExitAlt` : `ToAlt`) + `${(g('option').altHotkey && g('option').altHotkeyStr) ? `(${g('option').altHotkeyStr})` : '' }`; + button.className = 'gotoAlt'; + button.onclick = () => gotoAlt(); + } + + function setAltHotkey() { + if (!g('option').altHotkey) { + return; + } + document.addEventListener('keydown', (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + return; + } + if (e.keyCode === g('option').altHotkeyCode) { + gotoAlt(); + } + }, 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 @@ -1009,6 +1035,8 @@ ' ; ', ' ', '
      ', + '
      ; ', + '
      ', '
      警告相关警告相關To Warn: ', ' ; ', ' ', @@ -1629,6 +1657,10 @@ this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; gE('input[name="stepInHotkeyCode"]', optionBox).value = e.keyCode; }; + gE('input[name="altHotkeyStr"]', optionBox).onkeyup = function (e) { + this.value = (/^[a-z]$/.test(e.key)) ? e.key.toUpperCase() : e.key; + gE('input[name="altHotkeyCode"]', 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'); @@ -4340,29 +4372,31 @@ } function useDeSkill() { // 自动施法DEBUFF技能 - if (!g('option').debuffSkillSwitch) { // 总开关是否开启 + const option = g('option'); + if (!option.debuffSkillSwitch) { // 总开关是否开启 return false; } + const monsterStatus = g('battle').monsterStatus; // 先处理特殊的 “先给全体上buff” let skillPack = ['We', 'Im']; for (let i = 0; i < skillPack.length; i++) { - if (g('option')[`debuffSkill${skillPack[i]}All`]) { // 是否启用 - if (checkCondition(g('option')[`debuffSkill${skillPack[i]}AllCondition`], g('battle').monsterStatus)) { // 检查条件 + if (option[`debuffSkill${skillPack[i]}All`]) { // 是否启用 + if (checkCondition(option[`debuffSkill${skillPack[i]}AllCondition`], monsterStatus)) { // 检查条件 continue; } } skillPack.splice(i, 1); i--; } - skillPack.sort((x, y) => g('option').debuffSkillOrderValue.indexOf(x) - g('option').debuffSkillOrderValue.indexOf(y)); + skillPack.sort((x, y) => option.debuffSkillOrderValue.indexOf(x) - option.debuffSkillOrderValue.indexOf(y)); let toAllCount = skillPack.length; - if (g('option').debuffSkill) { // 是否有启用的buff(不算两个特殊的) - skillPack = skillPack.concat(g('option').debuffSkillOrderValue.split(',')); + if (option.debuffSkill) { // 是否有启用的buff(不算两个特殊的) + skillPack = skillPack.concat(option.debuffSkillOrderValue.split(',')); } for (let i in skillPack) { let buff = skillPack[i]; if (i >= toAllCount) { // 非先全体 - if (!buff || !checkCondition(g('option')[`debuffSkill${buff}Condition`], g('battle').monsterStatus)) { // 检查条件 + if (!buff || !option.debuffSkill[buff] || !checkCondition(option[`debuffSkill${buff}Condition`], monsterStatus)) { // 检查条件 continue; } } From 68b9a5e867e4e5a79a71f91ca9662dc5ed62a054 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 27 Nov 2025 13:28:59 +0800 Subject: [PATCH 141/216] 2.90.76 fix condition --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1795ead6..d1fdecf6 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1266,6 +1266,7 @@ '
      ', '
      ', + '
      Debuff释放条件Debuff釋放條件Cast debuff spells Condition{{debuffSkillCondition}}
      ', '

      ', ' 沉眠(Sl)沉眠(Sl)Sleep: ', ' 致盲(Bl)致盲(Bl)Blind: ', @@ -2097,12 +2098,13 @@ '', '', '', + '', '', '', '', - '', - '', - '', + '', + '', + '', '', ].join(''); customizeBox.style.cssText += 'display: none;'; @@ -2355,6 +2357,9 @@ isCd(id) { // is cool down done return isOn(id) ? 1 : 0; }, + spirit() { + return gE('#ckey_spirit[src*="spirit_a"]') ? 1 : 0; + }, buffTurn(img) { return getBuffTurnFromImg(getPlayerBuff(img), 0); }, @@ -4373,10 +4378,11 @@ function useDeSkill() { // 自动施法DEBUFF技能 const option = g('option'); - if (!option.debuffSkillSwitch) { // 总开关是否开启 + const monsterStatus = g('battle').monsterStatus; + console.log(option.debuffSkillCondition, checkCondition(option.debuffSkillCondition)); + if (!option.debuffSkillSwitch || !checkCondition(option.debuffSkillCondition, monsterStatus)) { // 总开关是否开启 return false; } - const monsterStatus = g('battle').monsterStatus; // 先处理特殊的 “先给全体上buff” let skillPack = ['We', 'Im']; for (let i = 0; i < skillPack.length; i++) { From 33f117082617e3aaa134b350cd6ab877ac85dca9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 27 Nov 2025 13:30:00 +0800 Subject: [PATCH 142/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 1 - 1 file changed, 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index d1fdecf6..9651fe68 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4379,7 +4379,6 @@ function useDeSkill() { // 自动施法DEBUFF技能 const option = g('option'); const monsterStatus = g('battle').monsterStatus; - console.log(option.debuffSkillCondition, checkCondition(option.debuffSkillCondition)); if (!option.debuffSkillSwitch || !checkCondition(option.debuffSkillCondition, monsterStatus)) { // 总开关是否开启 return false; } From fc7af9fb540a9f5c9e9332aaf65ecb8ff73a1494 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 28 Nov 2025 17:10:00 +0800 Subject: [PATCH 143/216] =?UTF-8?q?=E8=B0=83=E6=95=B4UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 340 +++++++++--------- 1 file changed, 173 insertions(+), 167 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9651fe68..02a229d4 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -495,6 +495,7 @@ function goto() { // 前进 window.location.reload(); setTimeout(goto, 5000); + setTimeout(()=>{window.location.href = window.location.href}, 10000); } function gotoAlt(isAltOnly) { @@ -906,7 +907,7 @@ '#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;}', + '.hvAAButton{top:5px;left:1255px;position:absolute;z-index:9999;cursor:pointer;width:40px;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;}', @@ -918,7 +919,7 @@ '.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 input.hvAANumber{width:40px;text-align:right;}', '#hvAABox input[type=\'checkbox\']{top: 3px;}', '.hvAATab ul,.hvAATab ol{margin:0;}', '.hvAATab label{cursor:pointer;}', @@ -934,11 +935,12 @@ '.hvAATitle{font-weight:bolder;}', '.hvAAGoto{cursor:pointer;text-decoration:underline;}', '.customizeInput{width:193px}', + '.hvAATable>* {border: 1px solid;}', '.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{display:grid; grid-template-columns:repeat(3, 1fr)}', '.hvAAcheckItems>input.hvAANumber{width:32px}', '.hvAAConfig{width:100%;height:16px;}', '.hvAAButtonBox{position:relative;top:468px;}', @@ -1023,20 +1025,19 @@ '
      ', '
      异世界相关異世界相關Isekai: ', - ' ', ' ; ', - '
      在任意页面停留

      在任意頁面停留

      Idle in any page for
      秒后,进行跳转秒後,進行跳轉s, start switch check
      ', + '
      在任意页面停留在任意頁面停留While idle in any page for 秒后,自动切换恒定世界和异世界秒後,自動切換恆定世界和異世界s, auto switch between Isekai and Persistent
      ', '
      小马答题小馬答題RIDDLE: ; ', '
      ', '
      脚本行为腳本行為Script Activity', - '
      暂停相关暫停相關Pause with: ', - ' ; ', - '
      ', + '
      ', + ' ; ', + '
      ', ' ; ', - ' ', + ' ', '
      ', '
      ; ', - '
      ', + '
      ', '
      警告相关警告相關To Warn: ', ' ; ', ' ', @@ -1049,18 +1050,20 @@ '
      ', '
      战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed):
      ', - ' ', - ' ', - ' ', - '
      ', - ' ', - ' ', - ' ', - '
      ', - ' ', - ' ', - ' ', - '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '

      ', + '
      ', + '
      ', + '
      ', + '

      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
      ', '
      ', '
      ', @@ -1072,17 +1075,17 @@ '
      : {{pauseCondition}}
      ', '
      : {{fleeCondition}}
      ', '
      ', - '
      继续新回合延时繼續新回合延時New round wait time: (秒)(秒)(s)
      ', - '
      战斗结束退出延时戰鬥結束退出延時Exit battle wait time: (秒)(秒)(s)
      ', + '
      继续新回合延时繼續新回合延時New round wait time: (秒)(秒)(s)
      ', + '
      战斗结束退出延时戰鬥結束退出延時Exit battle wait time: (秒)(秒)(s)
      ', '
      当损失精力當損失精力If it lost Stamina: ', ' ;', ' ; ', ' ', '
      ', - '
      战斗页面停留戰鬥頁面停留If the page for : ', - ' ; ', - ' ', - '
      ', + '
      战斗页面停留戰鬥頁面停留If not active for : ', + '
      ; ', + '
      ', + '
      ', '
      ', '
      ', @@ -1092,7 +1095,7 @@ '
      ', '
      ;
      ', + ' 在任意页面停留在任意頁面停留Idle in any page for 秒后,开始竞技场秒後,開始競技場 (s), start Arena ;
      ', ' 进行的竞技场相对应等级進行的競技場相對應等級The levels of the Arena you want to complete: ', '
      ', ' ', @@ -1113,84 +1116,86 @@ ' 耐久度耐久度Durability% 或 压榨届耐久度或 壓榨屆耐久度OR Grind Fest Durability%
      遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      ; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      [C!]检查物品库存檢查物品庫存Check is item needs supply;遭遇战前检查遭遇戰前檢查Check before encounter', - '
      ', - ' 体力药水體力藥水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', + '
      ', + '
      体力药水體力藥水Health Potion
      ', + '
      体力长效药體力長效藥Health Draught
      ', + '
      体力秘药體力秘藥Health Elixir
      ', + '
      魔力药水魔力藥水Mana Potion
      ', + '
      魔力长效药魔力長效藥Mana Draught
      ', + '
      魔力秘药魔力秘藥Mana Elixir
      ', + '
      灵力药水靈力藥水Spirit Potion
      ', + '
      灵力长效药靈力長效藥Spirit Draught
      ', + '
      灵力秘药靈力秘藥Spirit Elixir
      ', + '
      花瓶花瓶Flower Vase
      ', + '
      泡泡糖泡泡糖Bubble-Gum
      ', + '
      终极秘药終極秘藥Last Elixir
      ', + '
      加速卷轴加速捲軸
      Scroll of Swiftness
      ', + '
      守护卷轴守護捲軸
      Scroll of Protection
      ', + '
      化身卷轴化身捲軸
      Scroll of the Avatar
      ', + '
      吸收卷轴吸收捲軸
      Scroll of Absorption
      ', + '
      幻影卷轴幻影捲軸
      Scroll of Shadows
      ', + '
      生命卷轴生命捲軸
      Scroll of Life
      ', + '
      众神卷轴眾神捲軸
      Scroll of the Gods
      ', + '
      火焰魔药火焰魔藥
      Infusion of Flames
      ', + '
      冰冷魔药冰冷魔藥
      Infusion of Frost
      ', + '
      闪电魔药閃電魔藥
      Infusion of Lightning
      ', + '
      风暴魔药風暴魔藥
      Infusion of Storms
      ', + '
      神圣魔药神聖魔藥
      Infusion of Divinity
      ', + '
      黑暗魔药黑暗魔藥
      Infusion of Darkness
      ', + '
      能量饮料能量飲料
      Energy Drink
      ', + '
      咖啡因糖果咖啡因糖果
      Caffeinated Candy
      ', '
      ', '
      [C!!]压榨届使用额外的库存检查壓榨屆使用額外的庫存檢查Extra supply check for Grind Fest', - '
      ', - ' 体力药水體力藥水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', + '
      ', + '
      体力药水體力藥水Health Potion
      ', + '
      体力长效药體力長效藥Health Draught
      ', + '
      体力秘药體力秘藥Health Elixir
      ', + '
      魔力药水魔力藥水Mana Potion
      ', + '
      魔力长效药魔力長效藥Mana Draught
      ', + '
      魔力秘药魔力秘藥Mana Elixir
      ', + '
      灵力药水靈力藥水Spirit Potion
      ', + '
      灵力长效药靈力長效藥Spirit Draught
      ', + '
      灵力秘药靈力秘藥Spirit Elixir
      ', + '
      花瓶花瓶Flower Vase
      ', + '
      泡泡糖泡泡糖Bubble-Gum
      ', + '
      终极秘药終極秘藥Last Elixir
      ', + '
      加速卷轴加速捲軸
      Scroll of Swiftness
      ', + '
      守护卷轴守護捲軸
      Scroll of Protection
      ', + '
      化身卷轴化身捲軸
      Scroll of the Avatar
      ', + '
      吸收卷轴吸收捲軸
      Scroll of Absorption
      ', + '
      幻影卷轴幻影捲軸
      Scroll of Shadows
      ', + '
      生命卷轴生命捲軸
      Scroll of Life
      ', + '
      众神卷轴眾神捲軸
      Scroll of the Gods
      ', + '
      火焰魔药火焰魔藥
      Infusion of Flames
      ', + '
      冰冷魔药冰冷魔藥
      Infusion of Frost
      ', + '
      闪电魔药閃電魔藥
      Infusion of Lightning
      ', + '
      风暴魔药風暴魔藥
      Infusion of Storms
      ', + '
      神圣魔药神聖魔藥
      Infusion of Divinity
      ', + '
      黑暗魔药黑暗魔藥
      Infusion of Darkness
      ', + '
      能量饮料能量飲料
      Energy Drink
      ', + '
      咖啡因糖果咖啡因糖果
      Caffeinated Candy
      ', '
      ', '
      ', '
      ', '
      施放顺序施放順序Cast Order:
      ', - ' ', - '
      ', - ' ', - ' ', - ' ', - '
      ', - ' ', - ' ', - '
      ', - ' ', - ' ', - '
      ', - ' ', - ' ', - '
      ', + '
      ' , + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      : {{itemHGCondition}}
      ', '
      : {{itemMGCondition}}
      ', '
      : {{itemSGCondition}}
      ', @@ -1337,48 +1342,49 @@ ' 不可命中目标的权重不可名中目標的權重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)Coalesced Mana:
      ', - ' 焚燒的靈魂(BS)焚燒的靈魂(BS)Burning Soul: ', - ' 鮮美的靈魂(RS)鮮美的靈魂(RS)Ripened Soul:
      ', - - ' 敌方增益,暂不清楚具体效果,按0权重计算敵方增益,暫不清楚具體效果,按0權重計算Enemy Procs, Evvecf value unknown, weight as 0 for now.:
      ', - - ' 吸收结界(AW)吸收結界(AW)Absorbing Ward: ', - ' 姊妹们的盛怒(FoS)姊妹們的盛怒(FoS)Fury of the Sisters:
      ', - ' 未来的悲叹(LoF)未來的悲歎(LoF)Lamentations of the Future: ', - ' 昔日的凄叫(SoP)昔日的淒叫(SoP)Screams of the Past:
      ', - ' 此刻的恸哭(WoP)此刻的慟哭(WoP)Wailings of the Present:
      ', - + '
      ', + '
      虚弱(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)Coalesced Mana
      ', + '
      焚燒的靈魂(BS)焚燒的靈魂(BS)Burning Soul
      ', + '
      鮮美的靈魂(RS)鮮美的靈魂(RS)Ripened Soul
      ', + '
      ', ' 降抗性和攻击模式属性相同时降抗性和攻擊模式屬性相同時While elements between Resistance-lower-debuff and Attack-Mode matches [' + attackStatusType[g('attackStatus')] + '] :
      ', - - ' 灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin: ', - ' 冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs:
      ', - ' 湍流的空气(TA)湍流的空氣(TA)Turbulent Air: ', - ' 深层的烧伤(DB)深層的燒傷(DB)Deep Burns:
      ', - ' 崩溃的防御(BD)崩潰的防禦(BD)Breached Defense: ', - ' 钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack:
      ', - + '
      ', + '
      灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin
      ', + '
      冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs
      ', + '
      湍流的空气(TA)湍流的空氣(TA)Turbulent Air
      ', + '
      深层的烧伤(DB)深層的燒傷(DB)Deep Burns
      ', + '
      崩溃的防御(BD)崩潰的防禦(BD)Breached Defense
      ', + '
      钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack
      ', + '
      ', ' 降抗性和攻击模式属性不相同时降抗性和攻擊模式屬性不相同時While elements between Resistance-lower-debuff and Attack-Mode NOT matches [' + attackStatusType[g('attackStatus')] + '] :
      ', - - ' 灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin: ', - ' 冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs:
      ', - ' 湍流的空气(TA)湍流的空氣(TA)Turbulent Air: ', - ' 深层的烧伤(DB)深層的燒傷(DB)Deep Burns:
      ', - ' 崩溃的防御(BD)崩潰的防禦(BD)Breached Defense: ', - ' 钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack:
      ', - + '
      ', + '
      灼烧的皮肤(SS)燒灼的皮膚(SS)Searing Skin
      ', + '
      冰封的肢体(FL)冰封的肢體(FL)Freezing Limbs
      ', + '
      湍流的空气(TA)湍流的空氣(TA)Turbulent Air
      ', + '
      深层的烧伤(DB)深層的燒傷(DB)Deep Burns
      ', + '
      崩溃的防御(BD)崩潰的防禦(BD)Breached Defense
      ', + '
      钝化的攻击(BA)鈍化的攻擊(BA)Blunted Attack
      ', + '
      ', + ' 敌方增益,暂不清楚具体效果,默认按0权重计算敵方增益,暫不清楚具體效果,默認按0權重計算Enemy Procs, Evvecf value unknown, weight default as 0 for now.:
      ', + '
      ', + '
      姊妹们的盛怒(FoS)姊妹們的盛怒(FoS)
      Fury of the Sisters
      ', + '
      未来的悲叹(LoF)未來的悲歎(LoF)
      Lamentations of the Future
      ', + '
      昔日的凄叫(SoP)昔日的淒叫(SoP)
      Screams of the Past
      ', + '
      此刻的恸哭(WoP)此刻的慟哭(WoP)
      Wailings of the Present
      ', + '
      吸收结界(AW)吸收結界(AW)
      Absorbing Ward
      ', + '
      ', '
      ', '
      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
      ', @@ -1409,39 +1415,39 @@ '
      ', '
      ', '
      自身自身Self', - '
      ' , - '
      Turns
      ', - '
      Rounds
      ', - '
      Battle
      ', - '
      Monster
      ', - '
      Boss
      ', - '
      闪避閃避Evade
      ', - '
      未命中未命中Miss
      ', - '
      集中集中Focus
      ', - '
      MP总消耗總消耗Cost
      ', - '
      OC总消耗總消耗Cost
      ', + '
      ' , + '
      Turns
      ', + '
      Rounds
      ', + '
      Battle
      ', + '
      Monster
      ', + '
      Boss
      ', + '
      闪避閃避Evade
      ', + '
      未命中未命中Miss
      ', + '
      集中集中Focus
      ', + '
      MP总消耗總消耗Cost
      ', + '
      OC总消耗總消耗Cost
      ', '
      ', '
      ', '
      操作操作Actions', - '
      ' , - '
      回复 (总量)回复 (總量)Restore (Amount)
      ', - '
      物品 (次数)物品 (次數)Items (Count)
      ', - '
      技能 (次数)技能 (次數)Magic (Count)
      ', - '
      伤害 (总量)傷害 (總量)Damage (Amount)
      ', - '
      熟练度 (总量)熟練度 (總量)Proficiency (Amount)
      ', + '
      ' , + '
      回复 (总量)回复 (總量)Restore (Amount)
      ', + '
      物品 (次数)物品 (次數)Items (Count)
      ', + '
      技能 (次数)技能 (次數)Magic (Count)
      ', + '
      伤害 (总量)傷害 (總量)Damage (Amount)
      ', + '
      熟练度 (总量)熟練度 (總量)Proficiency (Amount)
      ', '
      ', '
      ', '
      受伤 (总量)受傷 (總量)Hurt (Amount)', - '
      ' , - '
      平均平均Avg
      ', - '
      次数次數Count
      ', - '
      总量總量Total
      ', - '
      法术平均法術平均Magic Avg
      ', - '
      法术次数法術次數Magic Count
      ', - '
      法术总量法術總量Magic Total
      ', - '
      物理平均物理平均Physical Avg
      ', - '
      物理次数物理次數Physical Count
      ', - '
      物理总量物理總量Physical Total
      ', + '
      ' , + '
      平均平均Avg
      ', + '
      次数次數Count
      ', + '
      总量總量Total
      ', + '
      法术平均法術平均Magic Avg
      ', + '
      法术次数法術次數Magic Count
      ', + '
      法术总量法術總量Magic Total
      ', + '
      物理平均物理平均Physical Avg
      ', + '
      物理次数物理次數Physical Count
      ', + '
      物理总量物理總量Physical Total
      ', '
      ', '
      ', '
      ', From 2721f5171358f30c79d78fe4803a9cefcd14a74d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 28 Nov 2025 17:44:52 +0800 Subject: [PATCH 144/216] =?UTF-8?q?2.90.77=20buff/debuff=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E5=89=A9=E4=BD=99turns=E4=BD=8E=E4=BA=8E=E9=98=88=E5=80=BC?= =?UTF-8?q?=E6=97=B6=E5=8D=B3=E5=8F=AF=E9=87=8A=E6=94=BE=EF=BC=8C=E8=80=8C?= =?UTF-8?q?=E9=9D=9E=E6=97=A0buff=E6=89=8D=E9=87=8A=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 02a229d4..183ff572 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.76 +// @version 2.90.77 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1254,20 +1254,20 @@ ' ', '
      ', '
      Buff释放条件Buff釋放條件Cast spells Condition{{buffSkillCondition}}
      ', - '
      {{buffSkillHDCondition}}
      ', - '
      {{buffSkillMDCondition}}
      ', - '
      {{buffSkillSDCondition}}
      ', - '
      {{buffSkillFVCondition}}
      ', - '
      {{buffSkillBGCondition}}
      ', - '
      {{buffSkillPrCondition}}
      ', - '
      {{buffSkillSLCondition}}
      ', - '
      {{buffSkillSSCondition}}
      ', - '
      {{buffSkillHaCondition}}
      ', - '
      {{buffSkillAFCondition}}
      ', - '
      {{buffSkillHeCondition}}
      ', - '
      {{buffSkillReCondition}}
      ', - '
      {{buffSkillSVCondition}}
      ', - '
      {{buffSkillAbCondition}}
      ', + '
      {{buffSkillHDCondition}}
      ', + '
      {{buffSkillMDCondition}}
      ', + '
      {{buffSkillSDCondition}}
      ', + '
      {{buffSkillFVCondition}}
      ', + '
      {{buffSkillBGCondition}}
      ', + '
      {{buffSkillPrCondition}}
      ', + '
      {{buffSkillSLCondition}}
      ', + '
      {{buffSkillSSCondition}}
      ', + '
      {{buffSkillHaCondition}}
      ', + '
      {{buffSkillAFCondition}}
      ', + '
      {{buffSkillHeCondition}}
      ', + '
      {{buffSkillReCondition}}
      ', + '
      {{buffSkillSVCondition}}
      ', + '
      {{buffSkillAbCondition}}
      ', '
      ', '
      ', @@ -1295,15 +1295,15 @@ '
      ', '
      特殊Special
      {{debuffSkillWeAllCondition}}', '
      特殊Special
      {{debuffSkillImAllCondition}}', - '
      {{debuffSkillSleCondition}}
      ', - '
      {{debuffSkillBlCondition}}
      ', - '
      {{debuffSkillSloCondition}}
      ', - '
      {{debuffSkillImCondition}}
      ', - '
      {{debuffSkillMNCondition}}
      ', - '
      {{debuffSkillSiCondition}}
      ', - '
      {{debuffSkillDrCondition}}
      ', - '
      {{debuffSkillWeCondition}}
      ', - '
      {{debuffSkillCoCondition}}
      ', + '
      {{debuffSkillSleCondition}}
      ', + '
      {{debuffSkillBlCondition}}
      ', + '
      {{debuffSkillSloCondition}}
      ', + '
      {{debuffSkillImCondition}}
      ', + '
      {{debuffSkillMNCondition}}
      ', + '
      {{debuffSkillSiCondition}}
      ', + '
      {{debuffSkillDrCondition}}
      ', + '
      {{debuffSkillWeCondition}}
      ', + '
      {{debuffSkillCoCondition}}
      ', '
      ', '
      ', @@ -4200,20 +4200,21 @@ img: 'absorb', }, }; - if (!g('option').buffSkillSwitch) { + const option = g('option'); + if (!option.buffSkillSwitch) { return false; } - if (!g('option').buffSkill) { + if (!option.buffSkill) { return false; } - if (!checkCondition(g('option').buffSkillCondition)) { + if (!checkCondition(option.buffSkillCondition)) { return false; } let i; - const skillPack = g('option').buffSkillOrderValue.split(','); + const skillPack = 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`]) && !getPlayerBuff(skillLib[buff].img) && isOn(skillLib[buff].id)) { + if (option.buffSkill[buff] && checkCondition(option[`buffSkill${buff}Condition`]) && (getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)) <= (option.buffSkillThreshold ? option.buffSkillThreshold[buff] ?? 0 : 0)) && isOn(skillLib[buff].id)) { gE(skillLib[buff].id).click(); return true; } @@ -4495,8 +4496,14 @@ } // 获取目标 - let isDebuffed = (target) => getMonsterBuff(getMonsterID(target), skillLib[buff].img); - let debuffByIndex = isAll && g('option')[`debuffSkill${buff}AllByIndex`]; + const option = g('option'); + + let isDebuffed = (target) => { + const current = getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), skillLib[buff].img)); + const threshold = option.debuffSkillThreshold ? option.debuffSkillThreshold[buff] ?? 0 : 0; + return current > threshold; + }; + let debuffByIndex = isAll && option[`debuffSkill${buff}AllByIndex`]; let monsterStatus = g('battle').monsterStatus; if (debuffByIndex) { monsterStatus = JSON.parse(JSON.stringify(monsterStatus)); @@ -4508,7 +4515,7 @@ let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; - target = checkCondition(g('option')[`debuffSkill${buff}${isAll ? 'all' : ''}Condition`], [target]); + target = checkCondition(option[`debuffSkill${buff}${isAll ? 'all' : ''}Condition`], [target]); if (!target || target.isDead || isDebuffed(target)) { continue; } @@ -4529,7 +4536,7 @@ // 已有buff小于6个 // 未开启debuff失败警告 // buff剩余持续时间大于等于警报时间 - if (imgs.length < 6 || !g('option').debuffSkillTurnAlert || (g('option').debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= g('option').debuffSkillTurn[buff])) { + if (imgs.length < 6 || !option.debuffSkillTurnAlert || (option.debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= option.debuffSkillTurn[buff])) { gE(skillLib[buff].id).click(); clickMonster(id); return true; From df2235996550fad461841eff9ea92ea27829344b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 28 Nov 2025 21:14:36 +0800 Subject: [PATCH 145/216] =?UTF-8?q?2.90.78=20buff/debuff=20=E9=98=88?= =?UTF-8?q?=E5=80=BC=E5=B0=8F=E4=BA=8E0=E6=97=B6=E4=B8=8D=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E9=98=88=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 183ff572..3e7fdcc7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.77 +// @version 2.90.78 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1254,20 +1254,20 @@ ' ', '
      ', '
      Buff释放条件Buff釋放條件Cast spells Condition{{buffSkillCondition}}
      ', - '
      {{buffSkillHDCondition}}
      ', - '
      {{buffSkillMDCondition}}
      ', - '
      {{buffSkillSDCondition}}
      ', - '
      {{buffSkillFVCondition}}
      ', - '
      {{buffSkillBGCondition}}
      ', - '
      {{buffSkillPrCondition}}
      ', - '
      {{buffSkillSLCondition}}
      ', - '
      {{buffSkillSSCondition}}
      ', - '
      {{buffSkillHaCondition}}
      ', - '
      {{buffSkillAFCondition}}
      ', - '
      {{buffSkillHeCondition}}
      ', - '
      {{buffSkillReCondition}}
      ', - '
      {{buffSkillSVCondition}}
      ', - '
      {{buffSkillAbCondition}}
      ', + '
      {{buffSkillHDCondition}}
      ', + '
      {{buffSkillMDCondition}}
      ', + '
      {{buffSkillSDCondition}}
      ', + '
      {{buffSkillFVCondition}}
      ', + '
      {{buffSkillBGCondition}}
      ', + '
      {{buffSkillPrCondition}}
      ', + '
      {{buffSkillSLCondition}}
      ', + '
      {{buffSkillSSCondition}}
      ', + '
      {{buffSkillHaCondition}}
      ', + '
      {{buffSkillAFCondition}}
      ', + '
      {{buffSkillHeCondition}}
      ', + '
      {{buffSkillReCondition}}
      ', + '
      {{buffSkillSVCondition}}
      ', + '
      {{buffSkillAbCondition}}
      ', '
      ', '
      ', @@ -1295,15 +1295,15 @@ '
      ', '
      特殊Special
      {{debuffSkillWeAllCondition}}', '
      特殊Special
      {{debuffSkillImAllCondition}}', - '
      {{debuffSkillSleCondition}}
      ', - '
      {{debuffSkillBlCondition}}
      ', - '
      {{debuffSkillSloCondition}}
      ', - '
      {{debuffSkillImCondition}}
      ', - '
      {{debuffSkillMNCondition}}
      ', - '
      {{debuffSkillSiCondition}}
      ', - '
      {{debuffSkillDrCondition}}
      ', - '
      {{debuffSkillWeCondition}}
      ', - '
      {{debuffSkillCoCondition}}
      ', + '
      {{debuffSkillSleCondition}}
      ', + '
      {{debuffSkillBlCondition}}
      ', + '
      {{debuffSkillSloCondition}}
      ', + '
      {{debuffSkillImCondition}}
      ', + '
      {{debuffSkillMNCondition}}
      ', + '
      {{debuffSkillSiCondition}}
      ', + '
      {{debuffSkillDrCondition}}
      ', + '
      {{debuffSkillWeCondition}}
      ', + '
      {{debuffSkillCoCondition}}
      ', '
      ', '
      ', @@ -4214,10 +4214,14 @@ const skillPack = option.buffSkillOrderValue.split(','); for (i = 0; i < skillPack.length; i++) { let buff = skillPack[i]; - if (option.buffSkill[buff] && checkCondition(option[`buffSkill${buff}Condition`]) && (getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)) <= (option.buffSkillThreshold ? option.buffSkillThreshold[buff] ?? 0 : 0)) && isOn(skillLib[buff].id)) { - gE(skillLib[buff].id).click(); - return true; - } + if (!option.buffSkill[buff]) continue; + if (!isOn(skillLib[buff].id)) continue; + if (!checkCondition(option[`buffSkill${buff}Condition`])) continue; + const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + const threshold = option.buffSkillThreshold ? option.buffSkillThreshold[buff] ?? 0 : 0; + if (threshold >= 0 && current > threshold) continue; + gE(skillLib[buff].id).click(); + return true; } const draughtPack = { HD: { @@ -4501,7 +4505,7 @@ let isDebuffed = (target) => { const current = getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), skillLib[buff].img)); const threshold = option.debuffSkillThreshold ? option.debuffSkillThreshold[buff] ?? 0 : 0; - return current > threshold; + return threshold >= 0 && current > threshold; }; let debuffByIndex = isAll && option[`debuffSkill${buff}AllByIndex`]; let monsterStatus = g('battle').monsterStatus; From 69afeef5124265aec5af703718567c271dd91473 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 29 Nov 2025 02:47:33 +0800 Subject: [PATCH 146/216] =?UTF-8?q?2.90.79=20=E4=BC=98=E5=8C=96=E8=80=90?= =?UTF-8?q?=E5=8A=9B=E8=AF=BB=E5=8F=96=E5=8F=8A=E8=80=90=E5=8A=9B=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E6=A3=80=E6=B5=8B=EF=BC=9B=E4=BC=98=E5=8C=96=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E5=86=99=E5=85=A5=EF=BC=8C=E5=86=99=E5=85=A5=E5=89=8D?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=A4=E6=96=AD=E5=80=BC=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=9C=89=E6=94=B9=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 144 ++++++++---------- 1 file changed, 66 insertions(+), 78 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3e7fdcc7..a7299b10 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.78 +// @version 2.90.79 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -770,6 +770,9 @@ } function setLocal(item, value) { + if (JSON.stringify(getLocal(item)) === JSON.stringify(value)) { + return; + } if (typeof GM_setValue === 'undefined') { window.localStorage[`hvAA-${item}`] = (typeof value === 'string') ? value : JSON.stringify(value); } else { @@ -2527,10 +2530,7 @@ } catch (e) { console.error(e) } })(), // stamina & hathperk (async () => { try { - ready.stamina = await Promise.all([ - asyncSetStamina(), - asyncSetEnergyDrinkHathperk(), - ]) || true; + ready.stamina = await asyncSetStamina() || true; await tryEncounter(); } catch (e) { console.error(e) } })(), // item & supply @@ -2664,48 +2664,44 @@ if (!loadSucceed) { ability = getValue('ability'); } - for (let ab of Object.keys(ability)) { + for (let ab in ability) { if (typeof ability[ab] !== 'object') { break; } ability[ab] = ability[ab].level; // old version data } - if (JSON.stringify(ability) !== JSON.stringify(getValue('ability'))) { - setValue('ability', ability); - } - $async.logSwitch(arguments); - } catch (e) { console.error(e) } } - - async function asyncSetEnergyDrinkHathperk() { try { - if (isIsekai || !g('option').restoreStamina) { - return; - } - await waitPause(); - $async.logSwitch(arguments); - let currentID = getCurrentUser(); - let perk = getValue('staminaHathperk') ?? {}; - if (perk[currentID]) { - return; - } - 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 && perks[25].innerHTML.includes('Obtained')) { - perk[currentID] = true; - setValue('staminaHathperk', perk); - } + setValue('ability', ability); $async.logSwitch(arguments); } catch (e) { console.error(e) } } async function asyncSetStamina() { try { await waitPause(); $async.logSwitch(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); + const stamina = getValue('stamina') ?? {}; + [stamina.current, stamina.perk]= await Promise.all([ + getCurrentStamina(), + (async () => { try { + if (isIsekai || !g('option').restoreStamina) { + return; + } + let currentID = getCurrentUser(); + const perk = stamina.perk ?? {}; + if (perk[currentID]) { + return; + } + 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 && perks[25].innerHTML.includes('Obtained')) { + perk[currentID] = true; + } + return perk; + } catch(e) {console.error(e) }})() + ]); + setValue('stamina', stamina); $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -2832,7 +2828,7 @@ return; } } - const staminaChecked = checkStamina(condition.staminaLow, condition.staminaCost); + const staminaChecked = await checkStamina(condition.staminaLow, condition.staminaCost); console.log(`stamina check done:\n${condition.staminaLow ? `low: ${condition.staminaLow}\n` : ''}${condition.staminaCost ? `cost: ${condition.staminaCost}\n` : ''}status: ${staminaChecked === 1 ? 'succeed' : staminaChecked === 0 ? 'failed' : 'failed with nature recover'}`); if (staminaChecked === 1) { // succeed return true; @@ -2846,34 +2842,40 @@ } } - 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); + async function getCurrentStamina() { try { + return gE('#stamina_readout .fc4.far>div', $doc(await $ajax.fetch(window.location.href))).textContent.match(/\d+/)[0] * 1; + } catch(e) { console.error(e); }} + + async function checkStamina(low, cost) { + const stamina = getValue('stamina'); + const option = g('option'); + let now = time(0); + let hours = Math.floor(now / _1h); + let current = await getCurrentStamina(); + const stmNR = current + 24 - (hours % 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); - if (stamina - cost >= (low ?? g('option').staminaLow) && stmNRChecked) { - return 1; - } + const stmNRChecked = !cost || stmNR - cost >= option.staminaLowWithReNat; + console.log('stamina:', stamina, '\nstamina with nature recover:', stmNR); + if (current - cost >= (low ?? option.staminaLow) && stmNRChecked) return 1; let checked = 0; if (!stmNRChecked) { checked = -1; } - if (isIsekai || !g('option').restoreStamina) { - return checked; - } + // restore + if (isIsekai || !option.restoreStamina) return checked; const items = g('items'); - if (!items) { - return checked; - } - const recover = items[11402] ? 5 : items[11401] ? (getValue('staminaHathperk')??{})[getCurrentUser()] ? 20 : 10 : 0; - if (recover && stamina <= (100 - recover)) { - $ajax.open(window.location.href, 'recover=stamina'); - return checked; + if (!items) return checked; + const recoverItems = { 11401: true, 11402: false } + for (let id in recoverItems) { + if (!items[id]) continue; + const isPerk = (stamina.perk??{})[getCurrentUser()]; + const recover = recoverItems[id] ? isPerk ? 20 : 10 : 5; + if (current + recover >= 100) continue; // check if overflow by (20 or 10) -> (5) + const recovered = gE('#stamina_readout .fc4.far>div', $doc(await $ajax.fetch(window.location.href, 'recover=stamina'))).textContent.match(/\d+/)[0] * 1; + goto(); + break; } + return checked; } async function updateEncounter(engage) { try { @@ -3048,10 +3050,7 @@ 105: 1, 106: 1, 107: 1, 108: 1, 109: 1, 110: 1, 111: 1, 112: 1, gr: 0 } - let stamina = getValue('stamina'); - const lastTime = getValue('staminaTime'); - let timeNow = Math.floor(time(0) / 1000 / 60 / 60); - stamina += lastTime ? timeNow - lastTime : 0; + let stamina = await getCurrentStamina(); for (let id in staminaCost) { staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) } @@ -3076,7 +3075,7 @@ } const cost = staminaCost[id]; if (!await checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { - console.log('Check Battle Ready Failed', 'id:', id, cost); + console.log('Check Battle Ready Failed', 'id:', id); $async.logSwitch(arguments); return; } @@ -3277,7 +3276,6 @@ g('battle').turn = currentTurn; battle.turn = currentTurn; setValue('battle', battle); - killBug(); // 解决 HentaiVerse 可能出现的 bug if (g('option').autoFlee && checkCondition(g('option').fleeCondition)) { @@ -3675,8 +3673,6 @@ const monsterLvs = Array.from(gE(`${monsterStateKeys.lv}>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]; @@ -3705,12 +3701,8 @@ order++; } if (g('option').cacheMonsterHP) { - if (oldDB !== JSON.stringify(monsterDB)) { - setValue('monsterDB', monsterDB); - } - if (oldMID !== JSON.stringify(monsterMID)) { - setValue('monsterMID', monsterMID); - } + setValue('monsterDB', monsterDB); + setValue('monsterMID', monsterMID); } battle.monsterStatus = monsterStatus; @@ -5007,9 +4999,7 @@ console.table(stats); pauseChange(); } - if (JSON.stringify(stats) !== JSON.stringify(getValue('stats', true))) { - setValue('stats', stats); - } + setValue('stats', stats); } function recordUsage2() { @@ -5034,9 +5024,7 @@ delValue('stats'); return; } - if (JSON.stringify(stats) !== JSON.stringify(getValue('stats', true))) { - setValue('stats', stats); - } + setValue('stats', stats); } } catch (e) { console.error(e); From e61baf9ee2e6c0ea4688c860d13cc70d2e467a11 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 04:54:26 +0800 Subject: [PATCH 147/216] =?UTF-8?q?2.90.80=20=E8=B0=83=E6=95=B4=E5=85=A8?= =?UTF-8?q?=E4=BD=93debuff=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=9B=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=89=80=E6=9C=89=E6=B6=89=E5=8F=8A=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E7=9A=84=E9=80=89=E9=A1=B9=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E4=B8=BA=E5=85=B6=E5=A2=9E=E5=8A=A0=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC=EF=BC=88=E9=99=A4=E4=BA=86=E5=BC=95=E5=AF=BC?= =?UTF-8?q?=E6=8A=80=E8=83=BD=EF=BC=89=EF=BC=9B=E5=85=B6=E4=BB=96UI?= =?UTF-8?q?=E5=8F=8A=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 368 ++++++++++-------- 1 file changed, 214 insertions(+), 154 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a7299b10..b8e5535a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.79 +// @version 2.90.80 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -189,7 +189,7 @@ function ontimer() { const now = new Date().getTime(); const last = getValue('last_post'); - if (last && last - now < $ajax.interval) { + if (last && now - last >= $ajax.interval) { $ajax.next(); return; } @@ -492,6 +492,22 @@ // ----------methods---------- // 通用// + + function unique(arr) { + const newArr = []; + for (let i = 0; i < arr.length; i++) { + if (newArr.indexOf(arr[i]) === -1) { + newArr.push(arr[i]); + } + } + return newArr; + } + + function splitOrders(orderValue, defaultOrder) { + const order = orderValue?.split(',') ?? []; + return unique(order.concat(defaultOrder ?? [])); + } + function goto() { // 前进 window.location.reload(); setTimeout(goto, 5000); @@ -634,6 +650,7 @@ } option.skillT3Condition = newCondition; } + if (isFrame) { g('option', option); } else { @@ -1181,80 +1198,83 @@ '
      ', '
      ', - '
      施放顺序施放順序Cast Order:
      ', + '
      施放顺序(未配置的按照下面的顺序)施放順序(未配置的按照下面的順序)Cast Order(Using order below as default if not configed):
      ', '
      ' , - '
      ', '
      ', - '
      ', - '
      ', + '
      ', + '
      ', '
      ', - '
      ', - '
      ', - '
      ', '
      ', + '
      ', + '
      ', '
      ', - '
      ', - '
      ', - '
      ', '
      ', + '
      ', + '
      ', '
      ', + '
      ', + '
      ', + '
      ', '
      ', - '
      : {{itemHGCondition}}
      ', - '
      : {{itemMGCondition}}
      ', - '
      : {{itemSGCondition}}
      ', - '
      : {{itemMysticCondition}}
      ', - '
      : {{itemCureCondition}}
      ', + '
      : {{itemFCCondition}}
      ', - '
      : {{itemHPCondition}}
      ', '
      : {{itemHECondition}}
      ', + '
      : {{itemLECondition}}
      ', + '
      : {{itemHGCondition}}
      ', + '
      : {{itemHPCondition}}
      ', + '
      : {{itemCureCondition}}
      ', + '
      : {{itemMGCondition}}
      ', '
      : {{itemMPCondition}}
      ', '
      : {{itemMECondition}}
      ', + '
      : {{itemSGCondition}}
      ', '
      : {{itemSPCondition}}
      ', '
      : {{itemSECondition}}
      ', - '
      : {{itemLECondition}}
      ', - '
      : {{itemEDCondition}}
      ', - '
      : {{itemCCCondition}}
      ', + '
      : {{itemMysticCondition}}
      ', + '
      : {{itemCCCondition}}
      ', + '
      : {{itemEDCondition}}
      ', '
      ', ' 获得引导时(此时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里的相同裡的相同
      ', - ' ', - ' ', + ' 注意: 此处的施放顺序与注意: 此處的施放順序与Note: The cast order here is the same as inBUFF技能 Spells里的相同(但不使用默认顺序)裡的相同(但不使用默認順序)(But skip the default order)
      ', ' ', - '
      ', - ' ', - ' ', - ' ', + ' ', + '
      ', + ' ', ' ', - '
      ', + ' ', + ' ', + ' ', + '
      ', '
      : ', '
      施放顺序施放順序Cast Order:
      ', - ' ', ' ', - ' ', - ' ', + ' ', ' ', - '
      ', - ' ', - ' ', - ' ', + ' ', + ' ', + ' ', ' ', - '
      ', - '
      最后ReBuff: 重新施放最先消失的Buff最後ReBuff: 重新施放最先消失的BuffAt last, re-cast the spells which will expire first.
      ', + ' ', + ' ', + ' ', + ' ', + '
      ', + '
      最后ReBuff: 重新施放最先消失的Buff最後ReBuff: 重新施放最先消失的BuffAt last, re-cast the spells which will expire first.
      ', + '
      ', '
      ', - '
      施放顺序施放順序Cast Order: ', + '
      施放顺序(未配置的按照下面的顺序)施放順序(未配置的按照下面的順序)Cast Order(Using order below as default if not configed): ', '
      ', - ' ', - ' ', ' ', - '
      ', - ' ', - ' ', - ' ', - ' ', + ' ', + ' ', ' ', + ' ', + ' ', + ' ', + ' ', + ' ', '
      ', '
      Buff释放条件Buff釋放條件Cast spells Condition{{buffSkillCondition}}
      ', '
      {{buffSkillHDCondition}}
      ', @@ -1278,40 +1298,63 @@ '

      ', ' 沉眠(Sl)沉眠(Sl)Sleep: ', ' 致盲(Bl)致盲(Bl)Blind: ', - ' 缓慢(Slo)緩慢(Slo)Slow:
      ', - ' 陷危(Im)陷危(Im)Imperil: ', - ' 魔磁网(MN)魔磁網(MN)MagNet: ', - ' 沉默(Si)沉默(Si)Silence:
      ', + ' 虚弱(We)虛弱(We)Weaken:
      ', + ' 沉默(Si)沉默(Si)Silence: ', + ' 缓慢(Slo)緩慢(Slo)Slow: ', + ' 陷危(Im)陷危(Im)Imperil:
      ', + ' 混乱(Co)混亂(Co)Confuse: ', ' 枯竭(Dr)枯竭(Dr)Drain: ', - ' 虚弱(We)虛弱(We)Weaken: ', - ' 混乱(Co)混亂(Co)Confuse:
      ', - '
      施放顺序施放順序Cast Order:', + ' 魔磁网(MN)魔磁網(MN)MagNet:
      ', + '
      1. 特殊先给全体施放的顺序(未配置的按照下面的顺序)特殊先給全體施放的順序(未配置的按照下面的順序)Cast Order for Special Debuff all enemies first(Using order below as default if not configed):', + '
      ', + // Dr, MN无法覆盖全体 + ' ', + ' ', + ' ', + ' ', + ' ', + // ' ', + ' ', + // ' ', + ' ', + '
      ', + + '
      2. 单体施放顺序(未配置的按照下面的顺序)單體施放順序(未配置的按照下面的順序)Cast Order for each enemy(Using order below as default if not configed):', '
      ', ' ', ' ', + ' ', + ' ', ' ', + ' ', ' ', ' ', - ' ', - ' ', - ' ', - '
      ', - '
      特殊Special
      {{debuffSkillWeAllCondition}}', - '
      特殊Special
      {{debuffSkillImAllCondition}}', + ' ', + '
      ', + '
      特殊先给全体施放和单体施放使用共享的阈值和各自独立的条件特殊先給全體施放和單體施放使用共享的閾值和各自獨立的條件Using sharing threshold and standalone conditions between special cast for debuff all enemies first and cast for debuff each enemy
      ', + '
      特殊Special
      {{debuffSkillSleAllCondition}}', + '
      特殊Special
      {{debuffSkillBlAllCondition}}', + '
      特殊Special
      {{debuffSkillWeAllCondition}}', + '
      特殊Special
      {{debuffSkillSiAllCondition}}', + '
      特殊Special
      {{debuffSkillSloAllCondition}}', + '
      特殊Special
      {{debuffSkillImAllCondition}}', + '
      特殊Special
      {{debuffSkillCoAllCondition}}', + '
      {{debuffSkillSleCondition}}
      ', '
      {{debuffSkillBlCondition}}
      ', + '
      {{debuffSkillWeCondition}}
      ', + '
      {{debuffSkillSiCondition}}
      ', '
      {{debuffSkillSloCondition}}
      ', + '
      {{debuffSkillDrCondition}}
      ', '
      {{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: ', + + '
      施放顺序(未配置的按照下面的顺序)施放順序(未配置的按照下面的順序)Cast Order(Using order below as default if not configed): ', '
      ', '
      ', '
      : {{skillOFCCondition}}
      ', @@ -1807,6 +1850,19 @@ } gE('input[name="debuffSkillOrderValue"]').value = value; }; + gE('.debuffSkillOrderAll', 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="debuffSkillOrderAllValue"]'); + if (e.target.checked) { + value = value + ((value) ? `,${name}` : name); + } else { + value = value.replace(new RegExp(`(^|,)${name}(,|$)`), '$2').replace(/^,/, ''); + } + gE('input[name="debuffSkillOrderAllValue"]').value = value; + }; // 标签页-其他技能 gE('.skillOrder', optionBox).onclick = function (e) { if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { @@ -3933,17 +3989,15 @@ } function autoRecover() { // 自动回血回魔 - if (!g('option').item) { - return false; - } - if (!g('option').itemOrderValue) { + const option = g('option'); + if (!option.item) { return false; } - const name = g('option').itemOrderName.split(','); - const order = g('option').itemOrderValue.split(','); + const name = splitOrders(option.itemOrderName, ['FC', 'HE', 'LE', 'HG', 'HP', 'Cure', 'MG', 'MP', 'ME', 'SG', 'SP', 'SE', 'Mystic', 'CC', 'ED']); + const order = splitOrders(option.itemOrderValue, [11199, 11501, 10005, 11195, 311, 10006, 11295, 11299, 10007, 11395, 11399, 10008, 11402, 11401]); for (let i = 0; i < name.length; i++) { let id = order[i]; - if (g('option').item[name[i]] && checkCondition(g('option')[`item${name[i]}Condition`]) && isOn(id)) { + if (option.item[name[i]] && checkCondition(option[`item${name[i]}Condition`]) && isOn(id)) { (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); return true; } @@ -3952,19 +4006,20 @@ } function useScroll() { // 自动使用卷轴 - if (!g('option').scrollSwitch) { + const option = g('option'); + if (!option.scrollSwitch) { return false; } - if (!g('option').scroll) { + if (!option.scroll) { return false; } - if (!g('option').scrollRoundType) { + if (!option.scrollRoundType) { return false; } - if (!g('option').scrollRoundType[g('battle').roundType]) { + if (!option.scrollRoundType[g('battle').roundType]) { return false; } - if (!checkCondition(g('option').scrollCondition)) { + if (!checkCondition(option.scrollCondition)) { return false; } const scrollLib = { @@ -4014,15 +4069,15 @@ img1: 'absorb', }, }; - const scrollFirst = (g('option').scrollFirst) ? '_scroll' : ''; + const scrollFirst = (option.scrollFirst) ? '_scroll' : ''; for (const i in scrollLib) { - if (!g('option').scroll[i]) { + if (!option.scroll[i]) { continue; } if (!gE(`.bti3>div[onmouseover*="(${scrollLib[i].id})"]`)) { continue; } - if (!checkCondition(g('option')[`scroll${i}Condition`])) { + if (!checkCondition(option[`scroll${i}Condition`])) { continue; } for (let j = 1; j <= scrollLib[i].mult; j++) { @@ -4037,75 +4092,76 @@ } function useChannelSkill() { // 自动施法Channel技能 - if (!g('option').channelSkillSwitch) { + const option = g('option'); + if (!option.channelSkillSwitch) { return false; } - if (!g('option').channelSkill) { + if (!option.channelSkill) { return false; } if (!getPlayerBuff('channeling')) { return false; } const skillLib = { - Pr: { - name: 'Protection', - id: '411', - img: 'protection', + SS: { + name: 'Spirit Shield', + id: '423', + img: 'spiritshield', }, SL: { name: 'Spark of Life', id: '422', img: 'sparklife', }, - SS: { - name: 'Spirit Shield', - id: '423', - img: 'spiritshield', + Pr: { + name: 'Protection', + id: '411', + img: 'protection', + }, + Ab: { + name: 'Absorb', + id: '421', + img: 'absorb', + }, + SV: { + name: 'Shadow Veil', + id: '413', + img: 'shadowveil', + }, + Re: { + name: 'Regen', + id: '312', + img: 'regen', }, 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', + AF: { + name: 'Arcane Focus', + id: '432', + img: 'arcanemeditation', }, }; let i, j; - const skillPack = g('option').buffSkillOrderValue.split(','); - if (g('option').channelSkill) { + const skillPack = splitOrders(option.buffSkillOrderValue); + if (option.channelSkill) { for (i = 0; i < skillPack.length; i++) { j = skillPack[i]; - if (g('option').channelSkill[j] && !getPlayerBuff(skillLib[j].img) && isOn(skillLib[j].id)) { + if (option.channelSkill[j] && !getPlayerBuff(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(','); + if (option.channelSkill2) { + const order = splitOrders(option.channelSkill2OrderValue); for (i = 0; i < order.length; i++) { if (isOn(order[i])) { gE(order[i]).click(); @@ -4146,50 +4202,50 @@ function useBuffSkill() { // 自动施法BUFF技能 const skillLib = { - Pr: { - name: 'Protection', - id: '411', - img: 'protection', + SS: { + name: 'Spirit Shield', + id: '423', + img: 'spiritshield', }, SL: { name: 'Spark of Life', id: '422', img: 'sparklife', }, - SS: { - name: 'Spirit Shield', - id: '423', - img: 'spiritshield', + Pr: { + name: 'Protection', + id: '411', + img: 'protection', + }, + Ab: { + name: 'Absorb', + id: '421', + img: 'absorb', + }, + SV: { + name: 'Shadow Veil', + id: '413', + img: 'shadowveil', + }, + Re: { + name: 'Regen', + id: '312', + img: 'regen', }, 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', + AF: { + name: 'Arcane Focus', + id: '432', + img: 'arcanemeditation', }, }; const option = g('option'); @@ -4203,7 +4259,7 @@ return false; } let i; - const skillPack = option.buffSkillOrderValue.split(','); + const skillPack = splitOrders(option.buffSkillOrderValue, ['SS', 'SL', 'Pr', 'Ab', 'SV', 'Re', 'Ha', 'He', 'AF']); for (i = 0; i < skillPack.length; i++) { let buff = skillPack[i]; if (!option.buffSkill[buff]) continue; @@ -4238,7 +4294,7 @@ }, }; for (i in draughtPack) { - if (!getPlayerBuff(draughtPack[i].img) && g('option').buffSkill && g('option').buffSkill[i] && checkCondition(g('option')[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`)) { + if (!getPlayerBuff(draughtPack[i].img) && option.buffSkill && option.buffSkill[i] && checkCondition(option[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`)) { gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`).click(); return true; } @@ -4250,10 +4306,11 @@ if (g('attackStatus') === 0) { return false; } - if (!g('option').infusionSwitch) { + const option = g('option'); + if (!option.infusionSwitch) { return false; } - if (!checkCondition(g('option').infusionCondition)) { + if (!checkCondition(option.infusionCondition)) { return false; } @@ -4284,7 +4341,8 @@ } function autoFocus() { - if (g('option').focus && checkCondition(g('option').focusCondition)) { + const option = g('option'); + if (option.focus && checkCondition(option.focusCondition)) { gE('#ckey_focus').click(); return true; } @@ -4297,7 +4355,8 @@ if (spValue <= 1) { return false; } - 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"]'))) { + const option = g('option'); + if ((option.turnOnSS && checkCondition(option.turnOnSSCondition) && !gE('#ckey_spirit[src*="spirit_a"]')) || (option.turnOffSS && checkCondition(option.turnOffSSCondition) && gE('#ckey_spirit[src*="spirit_a"]'))) { gE('#ckey_spirit').click(); return true; } @@ -4318,14 +4377,15 @@ * 优先释放先天和武器技能 */ function autoSkill() { - if (!g('option').skillSwitch) { + const option = g('option'); + if (!option.skillSwitch) { return false; } if (!gE('#ckey_spirit[src*="spirit_a"]')) { return false; } - const skillOrder = (g('option').skillOrderValue || 'OFC,FRD,T3,T2,T1').split(','); + const skillOrder = splitOrders(option.skillOrderValue, ['OFC', 'FRD', 'T3', 'T2', 'T1']); const fightStyle = g('fightingStyle'); const skillLib = { OFC: '1111', @@ -4347,7 +4407,7 @@ 2403: 2, 1111: 4, } - const optionSkills = g('option').skill; + const optionSkills = option.skill; if (!optionSkills) { return; } @@ -4363,11 +4423,11 @@ if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { continue; } - if (g('option').skillOTOS && g('option').skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { + if (option.skillOTOS && option.skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { continue; } g('skillOTOS')[skill]++; - let target = checkCondition(g('option')[`skill${skill}Condition`], g('battle').monsterStatus); + let target = checkCondition(option[`skill${skill}Condition`], g('battle').monsterStatus); if (!target) { continue; } @@ -4386,7 +4446,7 @@ return false; } // 先处理特殊的 “先给全体上buff” - let skillPack = ['We', 'Im']; + let skillPack = splitOrders(option.debuffSkillOrderAllValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Im', 'Co']); for (let i = 0; i < skillPack.length; i++) { if (option[`debuffSkill${skillPack[i]}All`]) { // 是否启用 if (checkCondition(option[`debuffSkill${skillPack[i]}AllCondition`], monsterStatus)) { // 检查条件 @@ -4396,10 +4456,10 @@ skillPack.splice(i, 1); i--; } - skillPack.sort((x, y) => option.debuffSkillOrderValue.indexOf(x) - option.debuffSkillOrderValue.indexOf(y)); - let toAllCount = skillPack.length; + const toAllCount = skillPack.length; + if (option.debuffSkill) { // 是否有启用的buff(不算两个特殊的) - skillPack = skillPack.concat(option.debuffSkillOrderValue.split(',')); + skillPack = skillPack.concat(splitOrders(option.debuffSkillOrderValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Dr', 'Im', 'MN', 'Co'])); } for (let i in skillPack) { let buff = skillPack[i]; From fc7d7e7fab669f517bb172a42d4b5716f2654668 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 04:56:42 +0800 Subject: [PATCH 148/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b8e5535a..13b8a58e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4446,7 +4446,7 @@ return false; } // 先处理特殊的 “先给全体上buff” - let skillPack = splitOrders(option.debuffSkillOrderAllValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Im', 'Co']); + let skillPack = splitOrders(option.debuffSkillOrderAllValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Dr', 'Im', 'MN', 'Co']); for (let i = 0; i < skillPack.length; i++) { if (option[`debuffSkill${skillPack[i]}All`]) { // 是否启用 if (checkCondition(option[`debuffSkill${skillPack[i]}AllCondition`], monsterStatus)) { // 检查条件 From 80589521b77fcf8f954d20f654fa53864f74be97 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 05:06:15 +0800 Subject: [PATCH 149/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 13b8a58e..99922130 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.80 +// @version 2.90.81 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1236,7 +1236,7 @@ '
      ', ' 获得引导时(此时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里的相同(但不使用默认顺序)裡的相同(但不使用默認順序)(But skip the default order)
      ', + ' 注意: 此处的施放顺序与注意: 此處的施放順序与Note: The cast order here is the same as inBUFF技能 Spells里的相同裡的相同
      ', ' ', ' ', '
      ', @@ -4150,7 +4150,7 @@ }, }; let i, j; - const skillPack = splitOrders(option.buffSkillOrderValue); + const skillPack = splitOrders(option.buffSkillOrderValue, ['SS', 'SL', 'Pr', 'Ab', 'SV', 'Re', 'Ha', 'He', 'AF']); if (option.channelSkill) { for (i = 0; i < skillPack.length; i++) { j = skillPack[i]; From 53c6abf1385191dea0f01f968bb47bb38b54d365 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 05:46:50 +0800 Subject: [PATCH 150/216] =?UTF-8?q?2.90.81=20=E8=B0=83=E6=95=B4=E7=BA=A0?= =?UTF-8?q?=E6=AD=A3=E5=BC=95=E5=AF=BC=E6=8A=80=E8=83=BD=E6=9C=80=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E9=87=8A=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 99922130..72ff5362 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.81 +// @version 2.90.82 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1260,7 +1260,7 @@ ' ', ' ', '
      ', - '
      最后ReBuff: 重新施放最先消失的Buff最後ReBuff: 重新施放最先消失的BuffAt last, re-cast the spells which will expire first.
      ', + '
      最后ReBuff: 重新施放最先将要消失的Buff最後ReBuff: 重新施放最先將要消失的BuffAt last, re-cast the spells which will expire first.
      ', '
      ', '
      ', @@ -4170,32 +4170,42 @@ } } 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 = getBuffTurnFromImg(buff[i]); - if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/)) { - continue; - } else { - if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('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; - } - } + if (!buff.length) return false; + const name2Skill = { + 'Spirit Shield': 'SS', + 'Spark of Life': 'SL', + 'Protection': 'Pr', + 'Absorb': 'Ab', + 'Shadow Veil': 'SV', + 'Regen': 'Re', + 'Hastened': 'Ha', + 'Heartseeker': 'He', + 'Arcane Focus': 'AF', + }; + let id; + let minBuff; + let minTime; + for (i = 0; i < buff.length; i++) { + const spellName = buff[i].getAttribute('onmouseover').match(/'(.*?)'/)[1]; + const buffLastTime = getBuffTurnFromImg(buff[i]); + if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/) || (minTime && buffLastTime >= minTime)) { + continue; + } + if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('sparklife')) { + id = 422; + } else if (spellName in name2Skill) { + id = skillLib[name2Skill[spellName]].id; + } + if (!id || !isOn(id)) { + continue; } + minBuff = id; + minTime = buffLastTime; + break; + } + if (minBuff) { + gE(minBuff).click(); + return true; } return false; } From aa0e0c1e027f91fd6b00ae6e2c648a40e694f208 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 07:01:35 +0800 Subject: [PATCH 151/216] =?UTF-8?q?2.90.83=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E6=8A=80=E8=83=BD=E7=9B=B8=E5=85=B3=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=81=9C=E6=AD=A2=E5=BC=95=E5=AF=BC=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E4=B8=8Abuff=E7=9A=84=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 72ff5362..47dd22ec 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.82 +// @version 2.90.83 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1234,7 +1234,18 @@ '
      : {{itemEDCondition}}
      ', '
      ', - ' 获得引导时(此时1点MP施法与150%伤害)獲得引導時(此時1點MP施法與150%傷害)During Channeling effect (1 mp spell cost and 150% spell damage):', + '
      获得引导时(此时1点MP施法与150%伤害)獲得引導時(此時1點MP施法與150%傷害)During Channeling effect (1 mp spell cost and 150% spell damage):
      ', + '
      超过时不释放超過時不釋放Not cast if remain turns above: ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      先施放引导技能先施放引導技能First cast:
      ', ' 注意: 此处的施放顺序与注意: 此處的施放順序与Note: The cast order here is the same as inBUFF技能 Spells里的相同裡的相同
      ', ' ', @@ -4096,9 +4107,6 @@ if (!option.channelSkillSwitch) { return false; } - if (!option.channelSkill) { - return false; - } if (!getPlayerBuff('channeling')) { return false; } @@ -4148,60 +4156,58 @@ id: '432', img: 'arcanemeditation', }, + + 'Cloak of the Fallen': { + id: getPlayerBuff('sparklife') ? undefined : 422, + } }; - let i, j; - const skillPack = splitOrders(option.buffSkillOrderValue, ['SS', 'SL', 'Pr', 'Ab', 'SV', 'Re', 'Ha', 'He', 'AF']); if (option.channelSkill) { - for (i = 0; i < skillPack.length; i++) { - j = skillPack[i]; - if (option.channelSkill[j] && !getPlayerBuff(skillLib[j].img) && isOn(skillLib[j].id)) { - gE(skillLib[j].id).click(); - return true; - } + const skillPack = splitOrders(option.buffSkillOrderValue, ['SS', 'SL', 'Pr', 'Ab', 'SV', 'Re', 'Ha', 'He', 'AF']); + for (const buff of skillPack) { + const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; + if (threshold >= 0 && current >= threshold) continue; + + if (!option.channelSkill[buff] || getPlayerBuff(skillLib[buff].img)) continue; + + if (!isOn(skillLib[buff].id)) continue; + gE(skillLib[buff].id).click(); + return true; } } if (option.channelSkill2) { const order = splitOrders(option.channelSkill2OrderValue); - for (i = 0; i < order.length; i++) { - if (isOn(order[i])) { - gE(order[i]).click(); - return true; + for (const i = 0; i < order.length; i++) { + const id = order[id]; + const matched = Object.keys(skillLib).filter(s=>skillLib[s].id * 1 === 1 * id); + if (matched) { + const buff = matched[0]; + const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; + if (threshold >= 0 && current > threshold) continue; } + + if (!isOn(id)) continue; + gE(id).click(); + return true; } } - const buff = gE('#pane_effects>img', 'all'); - if (!buff.length) return false; - const name2Skill = { - 'Spirit Shield': 'SS', - 'Spark of Life': 'SL', - 'Protection': 'Pr', - 'Absorb': 'Ab', - 'Shadow Veil': 'SV', - 'Regen': 'Re', - 'Hastened': 'Ha', - 'Heartseeker': 'He', - 'Arcane Focus': 'AF', - }; - let id; - let minBuff; - let minTime; - for (i = 0; i < buff.length; i++) { - const spellName = buff[i].getAttribute('onmouseover').match(/'(.*?)'/)[1]; - const buffLastTime = getBuffTurnFromImg(buff[i]); - if (isNaN(buffLastTime) || buff[i].src.match(/_scroll.png$/) || (minTime && buffLastTime >= minTime)) { - continue; - } - if (spellName === 'Cloak of the Fallen' && !getPlayerBuff('sparklife')) { - id = 422; - } else if (spellName in name2Skill) { - id = skillLib[name2Skill[spellName]].id; - } - if (!id || !isOn(id)) { + let minBuff, minTime; + for (const buff in skillLib) { + const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + const threshold = option.channelThreshold ? option.channelThreshold[name] ?? 0 : 0; + if (threshold >= 0 && current > threshold) continue; + + current = isNaN(current) ? 0 : current; + if (getPlayerBuff(skillLib[buff].img).src.match(/_scroll.png$/) || (minTime && current >= minTime)) { continue; } + const id = skillLib[buff].id; + if (!current && !option.buffSkill[buff]) continue; + + if (!isOn(id)) continue; minBuff = id; - minTime = buffLastTime; - break; + minTime = current; } if (minBuff) { gE(minBuff).click(); From 32f5ae84294a67b2986c59582b03ae17e80557e0 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 14:59:52 +0800 Subject: [PATCH 152/216] =?UTF-8?q?2.90.84=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E6=8A=80=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 47dd22ec..51003aae 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.83 +// @version 2.90.84 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4178,7 +4178,7 @@ if (option.channelSkill2) { const order = splitOrders(option.channelSkill2OrderValue); for (const i = 0; i < order.length; i++) { - const id = order[id]; + const id = order[i]; const matched = Object.keys(skillLib).filter(s=>skillLib[s].id * 1 === 1 * id); if (matched) { const buff = matched[0]; From aeed919c72e40df3470a31906f0e80240570ec41 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 15:36:03 +0800 Subject: [PATCH 153/216] =?UTF-8?q?2.90.85=20=E5=A2=9E=E5=8A=A0=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E6=9C=80=E5=90=8Erebuff=E7=9A=84=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 51003aae..c321a1f7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.84 +// @version 2.90.85 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1271,7 +1271,7 @@ ' ', ' ', '
      ', - '
      最后ReBuff: 重新施放最先将要消失的Buff最後ReBuff: 重新施放最先將要消失的BuffAt last, re-cast the spells which will expire first.
      ', + '
      最后ReBuff: 重新施放最先将要消失的Buff最後ReBuff: 重新施放最先將要消失的BuffAt last, re-cast the spells which will expire first.
      ', '
      ', '
      ', @@ -4192,26 +4192,28 @@ return true; } } - let minBuff, minTime; - for (const buff in skillLib) { - const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); - const threshold = option.channelThreshold ? option.channelThreshold[name] ?? 0 : 0; - if (threshold >= 0 && current > threshold) continue; + if (option.channelRebuff) { + let minBuff, minTime; + for (const buff in skillLib) { + const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + const threshold = option.channelThreshold ? option.channelThreshold[name] ?? 0 : 0; + if (threshold >= 0 && current > threshold) continue; - current = isNaN(current) ? 0 : current; - if (getPlayerBuff(skillLib[buff].img).src.match(/_scroll.png$/) || (minTime && current >= minTime)) { - continue; - } - const id = skillLib[buff].id; - if (!current && !option.buffSkill[buff]) continue; + current = isNaN(current) ? 0 : current; + if (getPlayerBuff(skillLib[buff].img).src.match(/_scroll.png$/) || (minTime && current >= minTime)) { + continue; + } + const id = skillLib[buff].id; + if (!current && !option.buffSkill[buff]) continue; - if (!isOn(id)) continue; - minBuff = id; - minTime = current; - } - if (minBuff) { - gE(minBuff).click(); - return true; + if (!isOn(id)) continue; + minBuff = id; + minTime = current; + } + if (minBuff) { + gE(minBuff).click(); + return true; + } } return false; } From e593cede5a33ded78590c9d4ff9979b3e36b5a63 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 16:24:05 +0800 Subject: [PATCH 154/216] =?UTF-8?q?2.90.86=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E4=B8=AD=E7=9A=84=E5=BE=AA=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c321a1f7..1bd0087f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.85 +// @version 2.90.86 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4177,8 +4177,7 @@ } if (option.channelSkill2) { const order = splitOrders(option.channelSkill2OrderValue); - for (const i = 0; i < order.length; i++) { - const id = order[i]; + for (const id of order) { const matched = Object.keys(skillLib).filter(s=>skillLib[s].id * 1 === 1 * id); if (matched) { const buff = matched[0]; From 82258b88ec361d7e625cdd58da64007bf96b3c41 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 16:29:59 +0800 Subject: [PATCH 155/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1bd0087f..f5f906dd 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -4178,7 +4178,7 @@ if (option.channelSkill2) { const order = splitOrders(option.channelSkill2OrderValue); for (const id of order) { - const matched = Object.keys(skillLib).filter(s=>skillLib[s].id * 1 === 1 * id); + const matched = Object.keys(skillLib).filter(s => skillLib[s].id * 1 === 1 * id); if (matched) { const buff = matched[0]; const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); @@ -4195,7 +4195,7 @@ let minBuff, minTime; for (const buff in skillLib) { const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); - const threshold = option.channelThreshold ? option.channelThreshold[name] ?? 0 : 0; + const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; if (threshold >= 0 && current > threshold) continue; current = isNaN(current) ? 0 : current; From aa5cf7afc85b786f2a5efeff15d54dd896f91788 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 16:30:56 +0800 Subject: [PATCH 156/216] 2.90.87 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f5f906dd..1c35f9ce 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.86 +// @version 2.90.87 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From a062f090bffbbe1c4b943a40b095f8e9486161eb Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 16:35:06 +0800 Subject: [PATCH 157/216] =?UTF-8?q?2.90.88=20=E4=BF=AE=E6=AD=A3=E5=8F=98?= =?UTF-8?q?=E9=87=8F/=E5=B8=B8=E9=87=8F=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 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1c35f9ce..2c0b71f5 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.87 +// @version 2.90.88 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4194,7 +4194,7 @@ if (option.channelRebuff) { let minBuff, minTime; for (const buff in skillLib) { - const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); + let current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; if (threshold >= 0 && current > threshold) continue; From 78f15eee7946c425d4935d059208d41bba8025d7 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 16:52:30 +0800 Subject: [PATCH 158/216] =?UTF-8?q?2.90.89=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC3=20=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E4=B8=BA?= =?UTF-8?q?=E5=8D=B7=E8=BD=B4buff=E6=97=B6=20=E7=9A=84=E9=9D=9E=E7=A9=BA?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2c0b71f5..56519956 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.88 +// @version 2.90.89 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4199,7 +4199,7 @@ if (threshold >= 0 && current > threshold) continue; current = isNaN(current) ? 0 : current; - if (getPlayerBuff(skillLib[buff].img).src.match(/_scroll.png$/) || (minTime && current >= minTime)) { + if (getPlayerBuff(skillLib[buff].img)?.src.match(/_scroll.png$/) || (minTime && current >= minTime)) { continue; } const id = skillLib[buff].id; From 4467ed5be20389dc724265239c52bd0a4304fb2c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 17:02:02 +0800 Subject: [PATCH 159/216] =?UTF-8?q?2.90.90=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E7=9A=84=E9=98=88=E5=80=BC=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 56519956..2e611f39 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.89 +// @version 2.90.90 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4166,7 +4166,7 @@ for (const buff of skillPack) { const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; - if (threshold >= 0 && current >= threshold) continue; + if (threshold > 0 && current >= threshold) continue; if (!option.channelSkill[buff] || getPlayerBuff(skillLib[buff].img)) continue; @@ -4183,7 +4183,7 @@ const buff = matched[0]; const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; - if (threshold >= 0 && current > threshold) continue; + if (threshold > 0 && current > threshold) continue; } if (!isOn(id)) continue; @@ -4196,7 +4196,7 @@ for (const buff in skillLib) { let current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; - if (threshold >= 0 && current > threshold) continue; + if (threshold > 0 && current > threshold) continue; current = isNaN(current) ? 0 : current; if (getPlayerBuff(skillLib[buff].img)?.src.match(/_scroll.png$/) || (minTime && current >= minTime)) { From 9776de0703913babddd8a7108ab3539919d464a2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 18:01:15 +0800 Subject: [PATCH 160/216] =?UTF-8?q?2.90.91=20=E4=BF=AE=E6=AD=A3=E5=BC=95?= =?UTF-8?q?=E5=AF=BC2=E7=9A=84buff=E5=92=8C=E6=B2=BB=E7=96=97=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E5=8C=BA=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2e611f39..af45258e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.90 +// @version 2.90.91 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4167,9 +4167,7 @@ const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; if (threshold > 0 && current >= threshold) continue; - if (!option.channelSkill[buff] || getPlayerBuff(skillLib[buff].img)) continue; - if (!isOn(skillLib[buff].id)) continue; gE(skillLib[buff].id).click(); return true; @@ -4178,14 +4176,12 @@ if (option.channelSkill2) { const order = splitOrders(option.channelSkill2OrderValue); for (const id of order) { - const matched = Object.keys(skillLib).filter(s => skillLib[s].id * 1 === 1 * id); - if (matched) { - const buff = matched[0]; + const buff = Object.keys(skillLib).find(s => skillLib[s].id * 1 === 1 * id); + if (buff) { const current = getBuffTurnFromImg(getPlayerBuff(skillLib[buff].img)); const threshold = option.channelThreshold ? option.channelThreshold[buff] ?? 0 : 0; if (threshold > 0 && current > threshold) continue; } - if (!isOn(id)) continue; gE(id).click(); return true; @@ -4203,7 +4199,7 @@ continue; } const id = skillLib[buff].id; - if (!current && !option.buffSkill[buff]) continue; + if (!current && (!option.buffSkillSwitch || !option.buffSkill[buff])) continue; if (!isOn(id)) continue; minBuff = id; @@ -4462,6 +4458,7 @@ if (!option.debuffSkillSwitch || !checkCondition(option.debuffSkillCondition, monsterStatus)) { // 总开关是否开启 return false; } + // 先处理特殊的 “先给全体上buff” let skillPack = splitOrders(option.debuffSkillOrderAllValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Dr', 'Im', 'MN', 'Co']); for (let i = 0; i < skillPack.length; i++) { @@ -4485,7 +4482,8 @@ continue; } } - let succeed = useDebuffSkill(buff, i < toAllCount); + const exclusiveBuffs = undefined; i < toAllCount && g('battle').debuffAllExclusiveAtBeginDone && option.debuffAllExclusiveAtBegin ? Object.keys(option.debuffAllExclusiveAtBegin) : undefined; + let succeed = useDebuffSkill(buff, i < toAllCount, exclusiveBuffs); // 前 toAllCount 个都是先给全体上的 if (succeed) { return true; @@ -4494,7 +4492,7 @@ return false; } - function useDebuffSkill(buff, isAll = false) { + function useDebuffSkill(buff, isAll = false, exclusiveBuffs = undefined) { const skillLib = { Sle: { name: 'Sleep', @@ -4571,10 +4569,15 @@ // 获取目标 const option = g('option'); - let isDebuffed = (target) => { - const current = getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), skillLib[buff].img)); - const threshold = option.debuffSkillThreshold ? option.debuffSkillThreshold[buff] ?? 0 : 0; - return threshold >= 0 && current > threshold; + let isDebuffed = (target, b) => { + if (b || !exclusiveBuffs) { + const current = getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), skillLib[b ?? buff].img)); + const threshold = option.debuffSkillThreshold ? option.debuffSkillThreshold[b ?? buff] ?? 0 : 0; + return threshold >= 0 && current > threshold; + } + for (const exclusive of exclusiveBuffs) { + if (isDebuffed(target, exclusive)) return true; + } }; let debuffByIndex = isAll && option[`debuffSkill${buff}AllByIndex`]; let monsterStatus = g('battle').monsterStatus; From 1a29ec98cd4224aa66368df93f2dd264fa92d273 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 19:19:26 +0800 Subject: [PATCH 161/216] =?UTF-8?q?2.90.92=20=E5=A2=9E=E5=8A=A0=E7=89=B9?= =?UTF-8?q?=E6=AE=8A=E5=85=88=E9=87=8A=E6=94=BE=E5=85=A8=E4=BD=93debuff?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=8F=AF=E4=BB=A5=E5=B0=86=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E7=9A=84debuff=E8=A7=86=E4=BD=9C=E5=B7=B2=E8=A6=86=E7=9B=96?= =?UTF-8?q?=EF=BC=88=E4=BE=8B=E5=A6=82=E6=B2=89=E7=9C=A0=E3=80=81=E6=B2=89?= =?UTF-8?q?=E9=BB=98=E3=80=81=E8=87=B4=E7=9B=B2=E7=AD=89=E9=AB=98cd?= =?UTF-8?q?=E6=8A=80=E8=83=BD=EF=BC=89=EF=BC=8C=E4=BB=A5=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?debuff=E5=9C=A8=E6=80=AA=E7=89=A9=E4=B8=8A=E7=9A=84=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E7=8E=87=EF=BC=9B=E4=BF=AE=E6=AD=A3debuff=E8=B6=85?= =?UTF-8?q?=E8=BF=876=E4=B8=AA=E6=97=B6=E7=9A=84=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index af45258e..55d337d0 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.91 +// @version 2.90.92 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1316,7 +1316,7 @@ ' 混乱(Co)混亂(Co)Confuse: ', ' 枯竭(Dr)枯竭(Dr)Drain: ', ' 魔磁网(MN)魔磁網(MN)MagNet:
      ', - '
      1. 特殊先给全体施放的顺序(未配置的按照下面的顺序)特殊先給全體施放的順序(未配置的按照下面的順序)Cast Order for Special Debuff all enemies first(Using order below as default if not configed):', + '
      1. 特殊先给全体施放的顺序(未配置的按照下面的顺序)特殊先給全體施放的順序(未配置的按照下面的順序)Cast Order for Special Debuff all enemies first(Using order below as default if not configed):', '
      ', // Dr, MN无法覆盖全体 ' ', @@ -1330,7 +1330,20 @@ ' ', '
      ', - '
      2. 单体施放顺序(未配置的按照下面的顺序)單體施放順序(未配置的按照下面的順序)Cast Order for each enemy(Using order below as default if not configed):', + '
      1.a. 特殊先给全体施放时,视作覆盖的互斥Debuff特殊特殊先給全體施放時,視作覆蓋的互斥DebuffExclusive debuffs during \'Cast Order for Special Debuff all enemies first\':', + // Dr, MN无法覆盖全体 + ' ', + ' ', + ' ', + ' ', + ' ', + // ' ', + ' ', + // ' ', + ' ', + '
      ', + + '
      2. 单体施放顺序(未配置的按照下面的顺序)單體施放順序(未配置的按照下面的順序)Cast Order for each enemy(Using order below as default if not configed):', '
      ', ' ', ' ', @@ -4472,18 +4485,19 @@ } const toAllCount = skillPack.length; + const exclusiveBuffs = option.debuffAllExclusive ? Object.keys(option.debuffAllExclusive) : undefined; if (option.debuffSkill) { // 是否有启用的buff(不算两个特殊的) skillPack = skillPack.concat(splitOrders(option.debuffSkillOrderValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Dr', 'Im', 'MN', 'Co'])); } for (let i in skillPack) { let buff = skillPack[i]; - if (i >= toAllCount) { // 非先全体 + const isToAll = i < toAllCount; + if (!isToAll) { // 非先全体 if (!buff || !option.debuffSkill[buff] || !checkCondition(option[`debuffSkill${buff}Condition`], monsterStatus)) { // 检查条件 continue; } } - const exclusiveBuffs = undefined; i < toAllCount && g('battle').debuffAllExclusiveAtBeginDone && option.debuffAllExclusiveAtBegin ? Object.keys(option.debuffAllExclusiveAtBegin) : undefined; - let succeed = useDebuffSkill(buff, i < toAllCount, exclusiveBuffs); + let succeed = useDebuffSkill(buff, isToAll, isToAll && exclusiveBuffs.includes(buff) ? exclusiveBuffs : undefined); // 前 toAllCount 个都是先给全体上的 if (succeed) { return true; @@ -4586,8 +4600,7 @@ monsterStatus.sort(objArrSort('order')); } let max = isAll ? monsterStatus.length : 1; - - let id; + let id; let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; @@ -4612,10 +4625,12 @@ // 已有buff小于6个 // 未开启debuff失败警告 // buff剩余持续时间大于等于警报时间 - if (imgs.length < 6 || !option.debuffSkillTurnAlert || (option.debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= option.debuffSkillTurn[buff])) { + if (imgs.length < 6) { gE(skillLib[buff].id).click(); clickMonster(id); return true; + } else if (!option.debuffSkillTurnAlert || (option.debuffSkillTurn && getBuffTurnFromImg(imgs[imgs.length - 1]) >= option.debuffSkillTurn[buff])){ + return false; } _alert(0, '无法正常施放DEBUFF技能,请尝试手动打怪', '無法正常施放DEBUFF技能,請嘗試手動打怪', 'Can not cast de-skills normally, continue the script?\nPlease try attack manually.'); From 48f8409b182a548646b2a20251cf5d2a3a0bd805 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 19:23:16 +0800 Subject: [PATCH 162/216] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E4=B8=BADr=E3=80=81M?= =?UTF-8?q?N=E4=B9=9F=E8=A7=86=E4=BD=9C=E5=8F=AF=E4=BB=A5=E8=A2=AB?= =?UTF-8?q?=E4=BA=92=E6=96=A5=E8=A6=86=E7=9B=96=E8=80=8C=E5=9C=A8=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E5=85=A8=E4=BD=93debuff=E6=97=B6=E6=8E=92=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 55d337d0..6901aed2 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1337,9 +1337,9 @@ ' ', ' ', ' ', - // ' ', + ' ', ' ', - // ' ', + ' ', ' ', '
      ', From 3ea7e41c0958f4647d7d00641a8f8a850c381f33 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 19:24:13 +0800 Subject: [PATCH 163/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6901aed2..8baf3aaf 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1324,9 +1324,9 @@ ' ', ' ', ' ', - // ' ', + ' ', ' ', - // ' ', + ' ', ' ', '
      ', From b77627e88a92a9cac48eec1769f0283f6a025d9c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 19:27:41 +0800 Subject: [PATCH 164/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8baf3aaf..a69c390e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1361,7 +1361,9 @@ '
      特殊Special
      {{debuffSkillWeAllCondition}}', '
      特殊Special
      {{debuffSkillSiAllCondition}}', '
      特殊Special
      {{debuffSkillSloAllCondition}}', + '
      特殊Special
      {{debuffSkillDrAllCondition}}', '
      特殊Special
      {{debuffSkillImAllCondition}}', + '
      特殊Special
      {{debuffSkillMNAllCondition}}', '
      特殊Special
      {{debuffSkillCoAllCondition}}', '
      {{debuffSkillSleCondition}}
      ', From fa5271d66980584ed4331d6afb6e62e68464fdd6 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 4 Dec 2025 19:28:01 +0800 Subject: [PATCH 165/216] 2.90.93 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a69c390e..c837ae58 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.92 +// @version 2.90.93 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From 5450f83c45bf70c03dead4ba5dc718c02092b930 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Dec 2025 12:20:58 +0800 Subject: [PATCH 166/216] =?UTF-8?q?2.90.94=20=E4=BF=AE=E6=AD=A3debuff=20Ex?= =?UTF-8?q?clusive=E7=9A=84=E9=9D=9E=E7=A9=BA=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c837ae58..7af108de 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.93 +// @version 2.90.94 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -4499,7 +4499,7 @@ continue; } } - let succeed = useDebuffSkill(buff, isToAll, isToAll && exclusiveBuffs.includes(buff) ? exclusiveBuffs : undefined); + let succeed = useDebuffSkill(buff, isToAll, isToAll && exclusiveBuffs?.includes(buff) ? exclusiveBuffs : undefined); // 前 toAllCount 个都是先给全体上的 if (succeed) { return true; From b6f058450f4fc8dde6be69d89f13b128907c1fc4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Dec 2025 15:51:16 +0800 Subject: [PATCH 167/216] =?UTF-8?q?2.90.95=20=E8=B0=83=E6=95=B4=E8=8E=B7?= =?UTF-8?q?=E5=8F=96buff=E6=8C=81=E7=BB=AD=E6=97=B6=E9=97=B4=E7=9A=84?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=80=BC=EF=BC=8C=E5=B0=86=E6=B0=B8=E4=B9=85?= =?UTF-8?q?buff=E7=9A=84=E8=BF=94=E5=9B=9E=E5=80=BC=E6=94=B9=E4=B8=BAInfin?= =?UTF-8?q?ity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 7af108de..80fa009a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.94 +// @version 2.90.95 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2452,10 +2452,10 @@ return gE('#ckey_spirit[src*="spirit_a"]') ? 1 : 0; }, buffTurn(img) { - return getBuffTurnFromImg(getPlayerBuff(img), 0); + return getBuffTurnFromImg(getPlayerBuff(img)); }, targetBuffTurn(img) { - return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), img), 0); + return getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), img)); }, targetHp() { return target.hpNow / target.hp; @@ -3395,12 +3395,19 @@ } } - function getBuffTurnFromImg(buff, nanValue = NaN) { + function getBuffTurnFromImg(buff) { if (!buff) { return 0; } - buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2] * 1; - return isNaN(buff) ? nanValue : buff; + buff = buff.getAttribute('onmouseover').match(/\(.*,.*,(\s*)(.*?)\)$/)[2]; + if (!buff) { + buff = 0; + } else if (buff ==='permanent') { + buff = Infinity; + } else { + buff *= 1; + } + return buff; } function getMonsterID(s) { From 44fd85f44613eb60079d85516071d501c99bf862 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Dec 2025 16:17:02 +0800 Subject: [PATCH 168/216] Revise README with updated information and examples Updated the README to include new sections and examples. --- HentaiVerse/hvAutoAttack/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index 70a8eadb..54e3d59a 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -78,23 +78,24 @@ **注意**: 由于是字符串之间的比较,所以请加上引号,如"ar"/'ar' 6. `attackStatus`: 攻击模式 (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -7. `isCd`: 技能/物品是否cd,格式`_isCd_id` +7. `fightingStyle`: 战斗风格 (`1`: 二天, `2`: 单手, `3`: 双手, `4`: 双持, `5`: 法杖) +8. `isCd`: 技能/物品是否cd,格式`_isCd_id` **示例1**: Protection的id为411,则`_isCd_411,5,0`表示不可施放,`_isCd_411,5,1`表示可以施放 **示例2**: ManaElixir的id为11295,则`_isCd_11295,5,0`表示不可使用,`_isCd_11295,5,1`表示可以使用 -8. `buffTurn`: 人物Buff剩余时间,格式`_buffTurn_img` +9. `buffTurn`: 人物Buff剩余时间,格式`_buffTurn_img` **示例**: Protection的img为protection,则`_buffTurn_protection,5,0`表示不存在Protection的buff,`_buffTurn_protection,3,10`表示Protection的buff至少剩余10回合 -9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 +10. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 1. 默认情况的target均为权重优先级最高的目标 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff ![示例](https://github.com/user-attachments/assets/b4d0c57d-fdb1-464b-88d6-107643809339) -10. 空白(blank): 自己输入 (the value you want to put in) +11. 空白(blank): 自己输入 (the value you want to put in) #### 示例 @@ -391,3 +392,4 @@ + From d829f516bb0b341d988c8e39e4988adc71aa5db3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 5 Dec 2025 16:17:04 +0800 Subject: [PATCH 169/216] Update README_en.md --- HentaiVerse/hvAutoAttack/README_en.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README_en.md b/HentaiVerse/hvAutoAttack/README_en.md index fa416b60..ccd03f27 100644 --- a/HentaiVerse/hvAutoAttack/README_en.md +++ b/HentaiVerse/hvAutoAttack/README_en.md @@ -74,23 +74,24 @@ Four drop down lists and one button are visible in the box (**Note**: Because comparison between strings, please add quotation, such as `"ar"`/`'ar'`) 6. `attackStatus`: Attack Mode (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -7. `isCd`: whether the skill/item is cooldowning, format: `_isCd_id` +7. `fightingStyle`: Fighting Style (`1`: Niten, `2`: 1H, `3`: 2H, `4`: DW, `5`: Staff) +8. `isCd`: whether the skill/item is cooldowning, format: `_isCd_id` **example 1**: the id of Protection is 411 , `_isCd_411,5,0` means Protection can't be casted or `_isCd_411,5,1` means Protection can be casted **example 2**: the id of ManaElixir is 11295, `_isCd_11295,5,0` means ManaElixir can't be used or `_isCd_11295,5,1` means ManaElixir can be used -8. `buffTurn`: time the buff last in person, format`_buffTurn_img` +9. `buffTurn`: time the buff last in person, format`_buffTurn_img` **example**: the image of Protection is protection, `_buffTurn_protection,5,0` means you don't have the buff of Protection or `_buffTurn_protection,3,10` means the buff of Protection on you last at least 10 turns -9. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: +10. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: 1. The highest priority monster by rank in default situations. 2. Weapon skills (OFC, T1~T3, etc.), Offensive Spell skills (Tire2, Tire3): by each condition > for each ranked target > find the target fit all sub-condition in the condition and cast to it. Such as the pic below: condition for Merciful Blow: only cast to targets which with hp below 25% and a bleed buff. ![example](https://github.com/user-attachments/assets/da181eac-e634-41ad-97a7-ff59a7b28b6d) -10. blank: the value you want to put in +11. blank: the value you want to put in #### Example @@ -195,3 +196,4 @@ In this example, the script will attack enemy 1 next. * Old 1. see [README_Chinese#更新历史](https://github.com/dodying/UserJs/blob/master/HentaiVerse/hvAutoAttack/README.md#更新历史) + From f55b70da16d4b4ad9521988665cd2000107fd762 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Dec 2025 02:30:46 +0800 Subject: [PATCH 170/216] =?UTF-8?q?2.90.96=20=E8=B0=83=E6=95=B4=E9=81=AD?= =?UTF-8?q?=E9=81=87=E6=88=98UI=EF=BC=9B=E4=BF=AE=E6=AD=A3=E5=8F=8A?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=85=B3=E9=97=AD=E5=BC=B9=E7=AA=97=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E5=88=A4=E6=96=AD=E6=B5=81=E7=A8=8B=EF=BC=8C=E4=BB=85?= =?UTF-8?q?=E5=9C=A8opener=E4=B8=AD=E5=AD=98=E5=9C=A8#riddlecounter,#battl?= =?UTF-8?q?e=5Fmain=E6=97=B6=E4=BC=9A=E8=BF=9B=E8=A1=8C=E5=85=B3=E9=97=AD?= =?UTF-8?q?=EF=BC=88=E9=81=BF=E5=85=8D=E8=A3=85=E5=A4=87=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=E7=AD=89=E8=A2=AB=E5=85=B3=E9=97=AD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 80fa009a..09f0e946 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.95 +// @version 2.90.96 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -347,7 +347,13 @@ const currentUrl = window.self.location.href; if (!isFrame) { loadOption(); - if (!g('option').riddlePopup || !window.opener || window.opener === window.self || window.opener.closed || gE('#riddlecounter')) { + if (!g('option').riddlePopup || gE('#riddlecounter')) { // 未开启使用弹窗或仍处于答题 + return true; + } + if (!window.opener || window.opener === window.self || window.opener.closed) { // 没有仍存在的opener + return true; + } + if (!gE('#riddlecounter,#battle_main', window.opener)) { // opener不处于战斗或答题中 return true; } try { @@ -926,7 +932,7 @@ '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}', + '.hvAAPauseUI{top:30px;left:1246px;position:absolute;z-index:9999; width:80px}', '.hvAAButton{top:5px;left:1255px;position:absolute;z-index:9999;cursor:pointer;width:40px;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;}', @@ -964,6 +970,7 @@ '.hvAAcheckItems>input.hvAANumber{width:32px}', '.hvAAConfig{width:100%;height:16px;}', '.hvAAButtonBox{position:relative;top:468px;}', + '.hvAAPauseUI>.encounterUI{font-weight:bold;position:unset;font-size:10pt;text-decoration:none;}', '.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;}', @@ -2911,7 +2918,8 @@ } } const staminaChecked = await checkStamina(condition.staminaLow, condition.staminaCost); - console.log(`stamina check done:\n${condition.staminaLow ? `low: ${condition.staminaLow}\n` : ''}${condition.staminaCost ? `cost: ${condition.staminaCost}\n` : ''}status: ${staminaChecked === 1 ? 'succeed' : staminaChecked === 0 ? 'failed' : 'failed with nature recover'}`); + const option = g('option'); + console.log(`stamina check done:\nlow: ${condition.staminaLow ?? option.staminaLow}\n${condition.staminaCost ? `cost: ${condition.staminaCost}\n` : ''}status: ${staminaChecked === 1 ? 'succeed' : staminaChecked === 0 ? 'failed' : `failed with nature recover ${option.staminaLowWithReNat}`}`); if (staminaChecked === 1) { // succeed return true; } @@ -2980,7 +2988,7 @@ } cd = Math.max(0, cd); const ui = gE('.encounterUI') ?? (() => { - const ui = gE('body').appendChild(cE('a')); + const ui = (gE('.hvAAPauseUI') ?? gE('body')).appendChild(cE('a')); ui.className = 'encounterUI'; ui.title = `${time(3, last)}\nEncounter Time: ${count}`; if (!gE('#battle_main')) { @@ -4609,7 +4617,7 @@ monsterStatus.sort(objArrSort('order')); } let max = isAll ? monsterStatus.length : 1; - let id; + let id; let minRank = Number.MAX_SAFE_INTEGER; for (let i = 0; i < max; i++) { let target = buff === 'Dr' ? monsterStatus[max - i - 1] : monsterStatus[i]; From 85d01c66353cdd304fa4799047ebe6765104993b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Dec 2025 04:47:11 +0800 Subject: [PATCH 171/216] =?UTF-8?q?2.90.97=20=E5=A2=9E=E5=8A=A0=E5=AE=B9?= =?UTF-8?q?=E9=94=99=EF=BC=8C=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E5=BC=B9=E5=87=BA=E7=AA=97=E5=8F=A3=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=9B=A0=E8=B7=A8=E5=9F=9F=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96?= =?UTF-8?q?opener.document=E5=AF=BC=E8=87=B4=E7=9A=84=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E5=9C=A8=E6=88=98=E6=96=97?= =?UTF-8?q?=E5=86=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 09f0e946..8df578cf 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.96 +// @version 2.90.97 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -353,7 +353,11 @@ if (!window.opener || window.opener === window.self || window.opener.closed) { // 没有仍存在的opener return true; } - if (!gE('#riddlecounter,#battle_main', window.opener)) { // opener不处于战斗或答题中 + try { + if (!gE('#riddlecounter,#battle_main', window.opener.document)) { // opener不处于战斗或答题中 + return true; + } + } catch(e) { return true; } try { From 71568e20b66bd3e277750e1eccdad82fdae9610c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Dec 2025 18:12:19 +0800 Subject: [PATCH 172/216] =?UTF-8?q?2.90.99=20=E4=BF=AE=E6=AD=A3=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8F=8A=E6=8E=89=E8=90=BD=E8=AE=B0=E5=BD=95=E7=9A=84?= =?UTF-8?q?=5F=5Fname(battleCode)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8df578cf..0668220d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.97 +// @version 2.90.98 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -492,10 +492,24 @@ 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}`); - } onBattleRound(); + if (g('option').recordEach) { + const token = document.body.innerHTML.match(`var battle_token = \"(.*)\";`)[1]; + let code = getValue('battleCode', true); + if (code?.token != token || !code?.r || !code?.rc) { + const time = code?.token === token ? code?.time ?? time(1) : time(1); + const type = g('battle')?.roundType?.toUpperCase(); + const roundAll = g('battle')?.roundAll; + code = { + token: token, + time: time, + roundType: type, + roundAll: roundAll, + name: `${time}: ${type}-${roundAll}`, + }; + setValue('battleCode', code); + } + } updateEncounter(false); return true; } @@ -1589,7 +1603,7 @@ } } else { if (getValue('drop')) { - drop.__name = getValue('battleCode'); + drop.__name = getValue('battleCode', true).name; dropOld.push(drop); } dropOld.reverse(); @@ -1641,7 +1655,7 @@ } } else { if (getValue('stats')) { - stats.__name = getValue('battleCode'); + stats.__name = getValue('battleCode', true).name; statsOld.push(stats); } statsOld.reverse(); @@ -4899,7 +4913,7 @@ const battle = g('battle'); if (g('option').recordEach && battle.roundNow === battle.roundAll) { const old = getValue('dropOld', true) || []; - drop.__name = getValue('battleCode'); + drop.__name = getValue('battleCode', true).name; drop['#endTime'] = time(3); old.push(drop); setValue('dropOld', old); @@ -5133,7 +5147,7 @@ const battle = g('battle'); if (g('option').recordEach && battle.roundNow === battle.roundAll) { const old = getValue('statsOld', true) || []; - stats.__name = getValue('battleCode'); + stats.__name = getValue('battleCode', true).name; stats.self._endTime = time(3); old.push(stats); setValue('statsOld', old); From 4dd09c1610952ad4a41e426b6083edcc61c6397c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Dec 2025 18:13:34 +0800 Subject: [PATCH 173/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0668220d..2288af10 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -497,15 +497,15 @@ const token = document.body.innerHTML.match(`var battle_token = \"(.*)\";`)[1]; let code = getValue('battleCode', true); if (code?.token != token || !code?.r || !code?.rc) { - const time = code?.token === token ? code?.time ?? time(1) : time(1); + const now = code?.token === token ? code?.time ?? time(1) : time(1); const type = g('battle')?.roundType?.toUpperCase(); const roundAll = g('battle')?.roundAll; code = { token: token, - time: time, + time: now, roundType: type, roundAll: roundAll, - name: `${time}: ${type}-${roundAll}`, + name: `${now}: ${type}-${roundAll}`, }; setValue('battleCode', code); } From 0ea95d2ccb353650caf611436a371f8c86c247c0 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 6 Dec 2025 18:17:05 +0800 Subject: [PATCH 174/216] =?UTF-8?q?2.90.100=20=E4=BF=AE=E6=AD=A3=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8F=8A=E6=8E=89=E8=90=BD=E6=A3=80=E6=B5=8B=E7=9A=84?= =?UTF-8?q?UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2288af10..4263e707 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.98 +// @version 2.90.100 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1603,7 +1603,7 @@ } } else { if (getValue('drop')) { - drop.__name = getValue('battleCode', true).name; + drop.__name = getValue('battleCode', true)?.name; dropOld.push(drop); } dropOld.reverse(); @@ -1655,7 +1655,7 @@ } } else { if (getValue('stats')) { - stats.__name = getValue('battleCode', true).name; + stats.__name = getValue('battleCode', true)?.name; statsOld.push(stats); } statsOld.reverse(); From 64345b06deae1eda8bfa09197cc7594e00ec929e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 7 Dec 2025 00:14:45 +0800 Subject: [PATCH 175/216] =?UTF-8?q?2.90.101=20=E8=B0=83=E6=95=B4=E4=B8=BA?= =?UTF-8?q?=E6=AF=8F=E6=AC=A1=E8=AF=BB=E5=8F=96option=E5=89=8D=E9=83=BD?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 4263e707..e9ba6e98 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.100 +// @version 2.90.101 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -337,7 +337,7 @@ eventpane.style.cssText += 'color:gray;' // 链接置灰提醒 } } else { // 战斗外,自动跳转 - loadOption(); + checkOption(); $ajax.openNoFetch(`${g('option').altBattleFirst ? href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt') : href}/${url}`); } return false; @@ -346,7 +346,7 @@ function checkIsWindowTop() { const currentUrl = window.self.location.href; if (!isFrame) { - loadOption(); + checkOption(); if (!g('option').riddlePopup || gE('#riddlecounter')) { // 未开启使用弹窗或仍处于答题 return true; } @@ -383,7 +383,7 @@ return false; } if (currentUrl.match(/\?s=Battle&ss=(ar|rb)/)) { - loadOption(); + checkOption(); setArenaDisplay(); } return false; @@ -640,12 +640,13 @@ } for (let key in aliasDict) { const itemArray = key.split('_'); + const alias = aliasDict[key]; if (itemArray.length === 1) { - option[key] ??= option[aliasDict[key]]; - option[aliasDict[key]] = undefined; + option[key] ??= option[alias]; + option[alias] = undefined; } else { option[itemArray[0]] ??= {}; - option[itemArray[0]][itemArray[1]] ??= option[aliasDict[key]]; + option[itemArray[0]][itemArray[1]] ??= option[alias]; } } // 迁移旧版本最后的慈悲条件为可配置条件 From f9db921b63869ca2f166c97fdeaedee2a9a3fb2d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 7 Dec 2025 05:34:23 +0800 Subject: [PATCH 176/216] =?UTF-8?q?2.90.102=20=E4=BF=AE=E6=AD=A3=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=88=9D=E5=A7=8B=E5=8C=96=E8=AE=BE=E7=BD=AE=E6=8C=89?= =?UTF-8?q?=E9=92=AE=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 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e9ba6e98..826ddcca 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.101 +// @version 2.90.102 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1026,6 +1026,7 @@ } function optionButton(lang) { // 配置按钮 + if (gE('.hvAAButton')) return; const optionButton = gE('body').appendChild(cE('div')); optionButton.className = 'hvAAButton'; optionButton.onclick = function () { From 307da8a1301be57f2cea696d49bcae4f06bce35b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 7 Dec 2025 18:14:08 +0800 Subject: [PATCH 177/216] =?UTF-8?q?2.90.103=20=E4=BC=98=E5=8C=96ajax?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E3=80=81iframe=E3=80=81=E4=B8=8D=E5=90=8Cscr?= =?UTF-8?q?ipt=E4=B9=8B=E9=97=B4=E7=9A=84=E5=8D=8F=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 826ddcca..0e6d8cf8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.102 +// @version 2.90.103 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -59,7 +59,7 @@ 'Forbidden', ]; const monsterStateKeys = { obj: `div.btm1`, lv: `div.btm2`, name: `div.btm3`, bars: `div.btm4>div.btm5`, buffs: `div.btm6` } - const [$async, $debug, $ajax] = [initAsync(), initDebug(), initAjax()]; + const [$async, $debug, $ajax] = [initAsync(), initDebug(), window.top.$ajax ??= unsafeWindow.$ajax ??= initAjax()]; for (let check of [checkIsHV, checkIsWindowTop, checkOption]) { if (!check()) return; } @@ -115,6 +115,7 @@ function initAjax() { const $ajax = { + debug: false, interval: 300, // DO NOT DECREASE THIS NUMBER, OR IT MAY TRIGGER THE SERVER'S LIMITER AND YOU WILL GET BANNED max: 4, tid: null, @@ -172,6 +173,7 @@ if ($ajax.tid) { if (!$ajax.conn) { clearTimeout($ajax.tid); + $ajax.tid = null; $ajax.timer(); $ajax.send(); } @@ -182,18 +184,22 @@ } } }, + getLast: function () { + const v = localStorage.getItem((isIsekai ? 'hvuti' : 'hvut') + '_last_post'); + return v === null ? undefined : JSON.parse(v); + }, + setLast: function (last) { + localStorage.setItem((isIsekai ? 'hvuti' : 'hvut') + '_last_post', JSON.stringify(last)); + }, timer: function () { - const _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'); + const last = $ajax.getLast(); if (last && now - last >= $ajax.interval) { $ajax.next(); return; } - setValue('last_post', now); + $ajax.setLast(now); $ajax.tid = null; $ajax.next(); }; @@ -203,6 +209,21 @@ GM_xmlhttpRequest($ajax.queue[$ajax.index]); $ajax.index++; $ajax.conn++; + if (!$ajax.debug) return; + const infos = $ajax.queue.map(r=>{ + const info = {}; + info.url = r.url; + if (r.data) info.data = r.data; + if (r.method) info.method = r.method; + if (r.context && JSON.stringify(r.context) !== JSON.stringify({})) info.context = r.context; + if (r.headers && JSON.stringify(r.headers) !== JSON.stringify({})) info.headers = r.headers; + return info; + }); + let remain; + if ($ajax.index < infos.length) { + remain = infos.slice($ajax.index); + } + console.log('$ajax.send:', $ajax.index,'/', infos.length, infos[$ajax.index-1], remain ? 'remain:' : '', remain ?? ''); }, onload: function (r) { $ajax.conn--; From d18536066ea4523fd808df5c743684fa9858ce8f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 7 Dec 2025 20:21:47 +0800 Subject: [PATCH 178/216] =?UTF-8?q?2.90.104=20=E4=BC=98=E5=8C=96=E5=8F=8A?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3ability=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 136 ++++++++++++------ 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0e6d8cf8..f7517559 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.103 +// @version 2.90.104 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2759,47 +2759,93 @@ $async.logSwitch(arguments); const html = await $ajax.fetch('?s=Character&ss=ab'); const doc = $doc(html); - let ability = {}; - const loadSucceed = true; - 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']; - switch (type) { - case 'deprecating1': - case 'deprecating2': - case 'elemental': - case 'forbidden': - case 'divine': - break; - default: - return; - } - 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); - loadSucceed = false; - } - })); - if (!loadSucceed) { - ability = getValue('ability'); - } - for (let ab in ability) { - if (typeof ability[ab] !== 'object') { - break; - } - ability[ab] = ability[ab].level; // old version data + const abd = { + // 'HP Tank': { id: 1101, unlock: [0, 25, 50, 75, 100, 120, 150, 200, 250, 300], level: 0 }, + // 'MP Tank': { id: 1102, unlock: [0, 30, 60, 90, 120, 160, 210, 260, 310, 350], level: 0 }, + // 'SP Tank': { id: 1103, unlock: [0, 40, 80, 120, 170, 220, 270, 330, 390, 450], level: 0 }, + // 'Better Health Pots': { id: 1104, unlock: [0, 100, 200, 300, 400], level: 0 }, + // 'Better Mana Pots': { id: 1105, unlock: [0, 80, 140, 220, 380], level: 0 }, + // 'Better Spirit Pots': { id: 1106, unlock: [0, 90, 160, 240, 400], level: 0 }, + // '1H Damage': { id: 2101, unlock: [0, 100, 200], level: 0 }, + // '1H Accuracy': { id: 2102, unlock: [50, 150], level: 0 }, + // '1H Block': { id: 2103, unlock: [250], level: 0 }, + // '2H Damage': { id: 2201, unlock: [0, 100, 200], level: 0 }, + // '2H Accuracy': { id: 2202, unlock: [50, 150], level: 0 }, + // '2H Parry': { id: 2203, unlock: [250], level: 0 }, + // 'DW Damage': { id: 2301, unlock: [0, 100, 200], level: 0 }, + // 'DW Accuracy': { id: 2302, unlock: [50, 150], level: 0 }, + // 'DW Crit': { id: 2303, unlock: [250], level: 0 }, + // 'Staff Spell Damage': { id: 2501, unlock: [0, 100, 200], level: 0 }, + // 'Staff Accuracy': { id: 2502, unlock: hvVersion < 91 ? [50, 150, 300] : [50, 150], level: 0 }, + // 'Staff Damage': { id: 2503, unlock: [0], level: 0 }, + // 'Cloth Spellacc': { id: 3101, unlock: hvVersion < 91 ? [0, 120, 240] : [120], level: 0 }, + // 'Cloth Spellcrit': { id: 3102, unlock: [0, 40, 90, 130, 190], level: 0 }, + // 'Cloth Castspeed': { id: 3103, unlock: [150, 250], level: 0 }, + // 'Cloth MP': { id: 3104, unlock: [0, 60, 110, 170, 230, 290, 350], level: 0 }, + // 'Light Acc': { id: 3201, unlock: [0], level: 0 }, + // 'Light Crit': { id: 3202, unlock: [0, 40, 90, 130, 190], level: 0 }, + // 'Light Speed': { id: 3203, unlock: [150, 250], level: 0 }, + // 'Light HP/MP': { id: 3204, unlock: [0, 60, 110, 170, 230, 290, 350], level: 0 }, + // 'Heavy Crush': { id: 3301, unlock: [0, 75, 150], level: 0 }, + // 'Heavy Prcg': { id: 3302, unlock: [0, 75, 150], level: 0 }, + // 'Heavy Slsh': { id: 3303, unlock: [0, 75, 150], level: 0 }, + // 'Heavy HP': { id: 3304, unlock: [0, 60, 110, 170, 230, 290, 350], level: 0 }, + // 'Better Weaken': { id: 4201, unlock: [70, 100, 130, 190, 250], level: 0 }, + 'Faster Weaken': { id: 4202, unlock: [80, 165, 250], level: 0 }, + // 'Better Imperil': { id: 4203, unlock: [130, 175, 230, 285, 330], level: 0 }, + 'Faster Imperil': { id: 4204, unlock: [140, 225, 310], level: 0 }, + // 'Better Blind': { id: 4205, unlock: [110, 130, 160, 190, 220], level: 0 }, + 'Faster Blind': { id: 4206, unlock: [120, 215, 275], level: 0 }, + 'Mind Control': { id: 4207, unlock: [80, 130, 170], level: 0 }, + 'Better Silence': { id: 4211, unlock: [120, 170, 215], level: 0 }, + 'Better MagNet': hvVersion < 91 ? { id: 4212, unlock: [250, 295, 340, 370, 400], level: 0 } : undefined, + 'Better Immobilize': hvVersion < 91 ? undefined : { id: 4212, unlock: [250, 295, 340, 370, 400], level: 0 }, + 'Better Slow': { id: 4213, unlock: [30, 50, 75, 105, 135], level: 0 }, + // 'Better Drain': { id: 4216, unlock: [20, 50, 90], level: 0 }, + // 'Faster Drain': { id: 4217, unlock: [30, 70, 110, 150, 200], level: 0 }, + // 'Ether Theft': { id: 4218, unlock: [150], level: 0 }, + // 'Spirit Theft': { id: 4219, unlock: [150], level: 0 }, + // 'Better Haste': { id: 4102, unlock: [60, 75, 90, 110, 130], level: 0 }, + // 'Better Shadow Veil': { id: 4103, unlock: [90, 105, 120, 135, 155], level: 0 }, + // 'Better Absorb': { id: 4104, unlock: [40, 60, 80], level: 0 }, + // 'Stronger Spirit': { id: 4105, unlock: [200, 220, 240, 265, 285], level: 0 }, + // 'Better Heartseeker': { id: 4106, unlock: [140, 185, 225, 265, 305, 345, 385], level: 0 }, + // 'Better Arcane Focus': { id: 4107, unlock: [175, 205, 245, 285, 325, 365, 405], level: 0 }, + // 'Better Regen': { id: 4108, unlock: [50, 70, 95, 145, 195, 245, 295, 375, 445, 500], level: 0 }, + // 'Better Cure': { id: 4109, unlock: [0, 35, 65], level: 0 }, + // 'Better Spark': { id: 4110, unlock: [100, 125, 150], level: 0 }, + // 'Better Protection': { id: 4101, unlock: [40, 55, 75, 95, 120], level: 0 }, + // 'Flame Spike Shield': { id: 4111, unlock: [10, 65, 140, 220, 300], level: 0 }, + // 'Frost Spike Shield': { id: 4112, unlock: [10, 65, 140, 220, 300], level: 0 }, + // 'Shock Spike Shield': { id: 4113, unlock: [10, 65, 140, 220, 300], level: 0 }, + // 'Storm Spike Shield': { id: 4114, unlock: [10, 65, 140, 220, 300], level: 0 }, + 'Conflagration': { id: 4301, unlock: [50, 100, 150, 200, 250, 300, 400], level: 0 }, + 'Cryomancy': { id: 4302, unlock: [50, 100, 150, 200, 250, 300, 400], level: 0 }, + 'Havoc': { id: 4303, unlock: [50, 100, 150, 200, 250, 300, 400], level: 0 }, + 'Tempest': { id: 4304, unlock: [50, 100, 150, 200, 250, 300, 400], level: 0 }, + // 'Sorcery': { id: 4305, unlock: [70, 140, 210, 280, 350], level: 0 }, + // 'Elementalism': { id: 4306, unlock: [85, 170, 255, 340, 425], level: 0 }, + // 'Archmage': { id: 4307, unlock: [90, 180, 270, 360, 450], level: 0 }, + 'Better Corruption': { id: 4401, unlock: [75, 150], level: 0 }, + 'Better Disintegrate': { id: 4402, unlock: [175, 250], level: 0 }, + 'Better Ragnarok': { id: 4403, unlock: [250, 325, 400], level: 0 }, + // 'Ripened Soul': { id: 4404, unlock: [150, 300, 450], level: 0 }, + // 'Dark Imperil': { id: 4405, unlock: [175, 225, 275, 325, 375], level: 0 }, + 'Better Smite': { id: 4501, unlock: [75, 150], level: 0 }, + 'Better Banish': { id: 4502, unlock: [175, 250], level: 0 }, + 'Better Paradise': { id: 4503, unlock: [250, 325, 400], level: 0 }, + // 'Soul Fire': { id: 4504, unlock: [150, 300, 450], level: 0 }, + // 'Holy Imperil': { id: 4505, unlock: [175, 225, 275, 325, 375], level: 0 }, } + + let ability = {}; + gE('#ability_top div[onmouseover*="overability"]', 'all', doc).forEach((div) => { + const exec = div.getAttribute('onmouseover').match(/overability\(\d+, '([^']+)','.+?','(?:(Not Acquired|At Maximum)|Requires Level (\d+).+?)','(Not Acquired|At Maximum|Requires Level (\d+).+?)'/); + const name = exec[1]; + const ab = abd[name]; + if (!ab) return; + ability[ab.id] = exec[2] ? 0 : ab.unlock.indexOf(1*exec[3]) + 1; + }); setValue('ability', ability); $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -4582,7 +4628,7 @@ name: 'Slow', id: '221', img: 'slow', - range: { 4211: [0, 0, 0, 1, 1] }, + range: { 4213: [0, 0, 0, 1, 1] }, }, Im: { name: 'Imperil', @@ -4594,7 +4640,7 @@ name: 'MagNet', id: '233', img: 'magnet', - range: { 4211: [0, 0, 0, 0, 1] }, + range: { 4212: [0, 0, 0, 0, 1] }, }, Si: { name: 'Silence', @@ -4632,7 +4678,7 @@ if (!ranges) { continue; } - if (ability) { + if (ability && ability[ab]) { range = ranges[ability[ab]]; } break; @@ -4764,7 +4810,7 @@ continue; } const ability = getValue('ability', true); - if (ability) { + if (ability && ability[ab]) { range = ranges[ability[ab]]; } break; From 1660d40fad3437d18ae361984a74d3dd9cbfabe8 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 8 Dec 2025 16:40:15 +0800 Subject: [PATCH 179/216] =?UTF-8?q?2.90.105=20=E4=BC=98=E5=8C=96ajax?= =?UTF-8?q?=EF=BC=9B=E4=BF=AE=E6=AD=A3=E5=8F=8A=E8=B0=83=E6=95=B4=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E5=92=8C=E7=9B=AE=E6=A0=87=E9=80=89=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 250 ++++++++++-------- 1 file changed, 133 insertions(+), 117 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f7517559..22216fae 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.104 +// @version 2.90.105 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -121,12 +121,14 @@ tid: null, error: null, conn: 0, - index: 0, queue: [], - fetch: function (url, data, method, context = {}, headers = {}) { + insert: function (url, data, method, context = {}, headers = {}) { + return $ajax.fetch(url, data, method, context, headers, true); + }, + fetch: function (url, data, method, context = {}, headers = {}, isInsert = false) { return new Promise((resolve, reject) => { - $ajax.add(method, url, data, resolve, reject, context, headers); + $ajax.add(method, url, data, resolve, reject, context, headers, isInsert); }); }, open: function (url, data, method, context = {}, headers = {}) { @@ -142,12 +144,7 @@ } return list; }, - add: function (method, url, data, onload, onerror, context = {}, headers = {}) { - const isDuplicate = this.queue.some(req => req.method === method && req.url === url && JSON.stringify(req.data) === JSON.stringify(data)); - if (isDuplicate) { - console.log('Skip duplicated fetch:', url, method, data); - return; - } + add: function (method, url, data, onload, onerror, context = {}, headers = {}, isInsert = false) { method = !data ? 'GET' : method ?? 'POST'; if (method === 'POST') { headers['Content-Type'] ??= 'application/x-www-form-urlencoded'; @@ -163,11 +160,15 @@ } context.onload = onload; context.onerror = onerror; - $ajax.queue.push({ method, url, data, headers, context, onload: $ajax.onload, onerror: $ajax.onerror }); + if (isInsert) { + $ajax.queue.unshift({ method, url, data, headers, context, onload: $ajax.onload, onerror: $ajax.onerror }); + } else { + $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) { + if (!$ajax.queue.length || $ajax.error) { return; } if ($ajax.tid) { @@ -205,25 +206,22 @@ }; $ajax.tid = setTimeout(ontimer, $ajax.interval); }, + simplify: function (r) { + const info = {}; + info.url = r.url; + if (r.data) info.data = r.data; + if (r.method) info.method = r.method; + if (r.context && JSON.stringify(r.context) !== JSON.stringify({})) info.context = r.context; + if (r.headers && JSON.stringify(r.headers) !== JSON.stringify({})) info.headers = r.headers; + return info; + }, send: function () { - GM_xmlhttpRequest($ajax.queue[$ajax.index]); - $ajax.index++; + const current = $ajax.queue.shift(); + GM_xmlhttpRequest(current); $ajax.conn++; if (!$ajax.debug) return; - const infos = $ajax.queue.map(r=>{ - const info = {}; - info.url = r.url; - if (r.data) info.data = r.data; - if (r.method) info.method = r.method; - if (r.context && JSON.stringify(r.context) !== JSON.stringify({})) info.context = r.context; - if (r.headers && JSON.stringify(r.headers) !== JSON.stringify({})) info.headers = r.headers; - return info; - }); - let remain; - if ($ajax.index < infos.length) { - remain = infos.slice($ajax.index); - } - console.log('$ajax.send:', $ajax.index,'/', infos.length, infos[$ajax.index-1], remain ? 'remain:' : '', remain ?? ''); + const remain = $ajax.queue.map($ajax.simplify); + console.log('$ajax.send:', $ajax.simplify(current), remain ? 'remain:' : '', remain ?? ''); }, onload: function (r) { $ajax.conn--; @@ -504,6 +502,7 @@ setPauseUI(box2); reloader(); g('attackStatus', g('option').attackStatus); + // 1二天 2单手 3双手 4双持 5法杖 for (let fightingStyle = 1; fightingStyle < 6; fightingStyle++) { if (gE(`2${fightingStyle}01`)) { g('fightingStyle', fightingStyle.toString()); @@ -2757,7 +2756,7 @@ async function asyncSetAbilityData() { try { await waitPause(); $async.logSwitch(arguments); - const html = await $ajax.fetch('?s=Character&ss=ab'); + const html = await $ajax.insert('?s=Character&ss=ab'); const doc = $doc(html); const abd = { // 'HP Tank': { id: 1101, unlock: [0, 25, 50, 75, 100, 120, 150, 200, 250, 300], level: 0 }, @@ -2865,7 +2864,7 @@ if (perk[currentID]) { return; } - const html = await $ajax.fetch('https://e-hentai.org/hathperks.php'); + const html = await $ajax.insert('https://e-hentai.org/hathperks.php'); if (!html) { return; } @@ -2887,7 +2886,7 @@ } await waitPause(); $async.logSwitch(arguments); - const html = await $ajax.fetch('?s=Character&ss=it'); + const html = await $ajax.insert('?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; @@ -2940,20 +2939,20 @@ } if (hvVersion < 91) { const href = `?s=Forge&ss=re`; - const doc = $doc(await $ajax.fetch(href)); - const json = JSON.parse((await $ajax.fetch(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); + const doc = $doc(await $ajax.insert(href)); + const json = JSON.parse((await $ajax.insert(gE('#mainpane>script[src]', doc).src)).match(/{.*}/)[0]); 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 > threshold) { return; } - const after = $doc(await $ajax.fetch(href, `select_item=${id}`)); + const after = $doc(await $ajax.insert(href, `select_item=${id}`)); return gE('.messagebox_error', )?.innerText ? undefined : json[id].t; } catch (e) { console.error(e) } })); } else { const href = `?s=Bazaar&ss=am&screen=repair&filter=equipped`; - const doc = $doc(await $ajax.fetch(href)); + const doc = $doc(await $ajax.insert(href)); const token = gE('#equipform>input[name="postoken"]', doc).value; eqps = await Promise.all(Array.from(gE('#equiplist>table>tbody>tr:not(.eqselall):not(.eqtplabel)', 'all', doc)).map(async eqp => { try { const id = gE('input', eqp).value; @@ -2961,7 +2960,7 @@ if (condition > threshold) { return; } - const after = $doc(await $ajax.fetch(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); + const after = $doc(await $ajax.insert(href, `&eqids[]=${id}&postoken=${token}&replace_charms=on`)); return gE(`#e${id}`, after) ? gE('.lc', eqp).childNodes[2].textContent : undefined; } catch (e) { console.error(e) } })); } @@ -2984,11 +2983,11 @@ let count; if (hvVersion < 91) { const href = `?s=Character&ss=in`; - const doc = $doc(await $ajax.fetch(href)); + const doc = $doc(await $ajax.insert(href)); count = gE('#eqinv_bot>div>div>div', doc).innerText.match(/: (\d+) \/ \d+/)[1]; } else { const href = `?s=Bazaar&ss=am`; - const doc = $doc(await $ajax.fetch(href)); + const doc = $doc(await $ajax.insert(href)); count = gE('#equipblurb>table>tbody>tr>td:nth-child(2)', doc).innerText; } $async.logSwitch(arguments); @@ -3020,7 +3019,7 @@ } async function getCurrentStamina() { try { - return gE('#stamina_readout .fc4.far>div', $doc(await $ajax.fetch(window.location.href))).textContent.match(/\d+/)[0] * 1; + return gE('#stamina_readout .fc4.far>div', $doc(await $ajax.insert(window.location.href))).textContent.match(/\d+/)[0] * 1; } catch(e) { console.error(e); }} async function checkStamina(low, cost) { @@ -3048,7 +3047,7 @@ const isPerk = (stamina.perk??{})[getCurrentUser()]; const recover = recoverItems[id] ? isPerk ? 20 : 10 : 5; if (current + recover >= 100) continue; // check if overflow by (20 or 10) -> (5) - const recovered = gE('#stamina_readout .fc4.far>div', $doc(await $ajax.fetch(window.location.href, 'recover=stamina'))).textContent.match(/\d+/)[0] * 1; + const recovered = gE('#stamina_readout .fc4.far>div', $doc(await $ajax.insert(window.location.href, 'recover=stamina'))).textContent.match(/\d+/)[0] * 1; goto(); break; } @@ -3112,7 +3111,7 @@ } catch (e) { console.error(e) } } async function onEncounter() { try { - while (!(await $ajax.fetch(href))) { // perhaps network connect not available + while (!(await $ajax.insert(href))) { // perhaps network connect not available await pauseAsync(_1m); } $async.logSwitchStrict('updateEncounter', true); @@ -3154,7 +3153,7 @@ arena.token = {}; await Promise.all(['gr', 'ar', 'rb'].map(async site => { try { - const doc = $doc(await $ajax.fetch(`?s=Battle&ss=${site}`)); + const doc = $doc(await $ajax.insert(`?s=Battle&ss=${site}`)); getStartBattleButtons(doc).forEach(btn => { arena.token[btn.id] = btn.token ?? null; }); } catch (e) { console.error(e) } })); @@ -3260,13 +3259,13 @@ if (hvVersion < 91) { token = `&inittoken=${token}`; } else { - token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.fetch(query))).value}`; + token = `&postoken=${gE('#initform>input[name="postoken"]', $doc(await $ajax.insert(query))).value}`; } await waitPause(); writeArenaStart(); - await $ajax.fetch(query, `initid=${id === 'gr' ? 1 : id}${token}`); + await $ajax.insert(query, `initid=${id === 'gr' ? 1 : id}${token}`); console.log('Arena Fetch Done.', 'altBattleFirst:', option.altBattleFirst); - if (option.altBattleFirst && await $ajax.fetch(href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt'))) { + if (option.altBattleFirst && await $ajax.insert(href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt'))) { console.log('Arena goto alt'); gotoAlt(true); } else { @@ -3535,11 +3534,14 @@ * 按照技能范围,获取包含原目标且范围内最终权重(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 + * @param {(target) => number} excludeWeightRatio target with id * @returns */ - function getRangeCenter(target, range = undefined, isWeaponAttack = false, excludeCondition = undefined, forceUseIndex = undefined) { - if (!range) { + function getRangeCenter(target, range, isWeaponAttack, excludeWeightRatio, forceUseIndex) { + let msTemp = JSON.parse(JSON.stringify(g('battle').monsterStatus)); + msTemp.sort(objArrSort('order')); + // 0. 范围大于等于全体时,直接释放全体 + if (!range || range <= msTemp.length) { return { id: getMonsterID(target), rank: Number.MAX_SAFE_INTEGER }; } const option = g('option'); @@ -3547,32 +3549,46 @@ 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 = option.unreachableWeight; let minRank = Number.MAX_SAFE_INTEGER; - for (let i = order - range; i <= order + range; i++) { - if (i < 0 || i >= msTemp.length || msTemp[i].isDead) { - continue; // 无法选中 - } + // 1. 以选中目标为中心,优先向上 + // 2. 超过顶部则向下找 + // 3. 死亡、超过底下的将被溢出抛弃 + const up = Math.floor(range / 2); + const down = range - up - 1; + const top = Math.max(order - down, 0); + const bottom = Math.min(order + up, msTemp.length-1); + for (let i = top; i <= bottom; i++) { + let center = i; 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; + for (let inRange = center - up; inRange <= (center + down); inRange++) { + let cew = inRange === center ? centralExtraWeight : 0; // cew <= 0, 增加未命中权重,降低命中权重 + let mon = msTemp[inRange]; + if (inRange < 0 || inRange >= msTemp.length || mon.isDead) { // 超出范围 或 死亡目标 + rank += unreachableWeight; continue; } - // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 - rank += cew; - // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 - rank += forceUseIndex ? -1 : mon.finWeight; - } - if (rank < minRank) { - newOrder = i; - minRank = rank; + if (excludeWeightRatio) { + // 特殊排除(ratio === 1则直接排除,00) { + continue; + } + } + rank += cew; // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 + rank += forceUseIndex ? -1 : mon.finWeight; // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 + } + if (rank >= minRank) continue; + while (center >= 0) { + if (!msTemp[center].isDead) { + newOrder = center; + minRank = rank; + break; + } + // 中心目标死亡 且 top能达到第1个(order:0)目标,尝试往前寻找目标,通过上方溢出向下扩展来覆盖目标 + if (top !== 0) break; + center--; } } return { id: getMonsterID(newOrder), rank: minRank }; @@ -3692,7 +3708,7 @@ goto(); return; } - const html = await $ajax.fetch(window.location.href); + const html = await $ajax.insert(window.location.href); gE('#pane_completion').removeChild(gE('#btcp')); clearBattleUnresponsive(); const doc = $doc(html) @@ -4516,7 +4532,7 @@ } const skillOrder = splitOrders(option.skillOrderValue, ['OFC', 'FRD', 'T3', 'T2', 'T1']); - const fightStyle = g('fightingStyle'); + const fightStyle = g('fightingStyle'); // 1二天 2单手 3双手 4双持 5法杖 const skillLib = { OFC: '1111', FRD: '1101', @@ -4533,9 +4549,12 @@ '2403': 3 } const rangeSkills = { - 2101: 2, - 2403: 2, - 1111: 4, + 2101: 5, + 2302: 5, + 2303: 5, + 2403: 5, + // 1101: 20, 全体 + // 1111: 20, } const optionSkills = option.skill; if (!optionSkills) { @@ -4562,8 +4581,7 @@ continue; } gE(id).click(); - const range = id in rangeSkills ? rangeSkills[id] : 0; - clickMonster(getRangeCenter(target, range).id); + clickMonster(getRangeCenter(target, rangeSkills[id] ?? 1).id); return true; } return false; @@ -4589,7 +4607,6 @@ } const toAllCount = skillPack.length; - const exclusiveBuffs = option.debuffAllExclusive ? Object.keys(option.debuffAllExclusive) : undefined; if (option.debuffSkill) { // 是否有启用的buff(不算两个特殊的) skillPack = skillPack.concat(splitOrders(option.debuffSkillOrderValue, ['Sle', 'Bl', 'We', 'Si', 'Slo', 'Dr', 'Im', 'MN', 'Co'])); } @@ -4601,7 +4618,7 @@ continue; } } - let succeed = useDebuffSkill(buff, isToAll, isToAll && exclusiveBuffs?.includes(buff) ? exclusiveBuffs : undefined); + let succeed = useDebuffSkill(buff, isToAll); // 前 toAllCount 个都是先给全体上的 if (succeed) { return true; @@ -4610,43 +4627,43 @@ return false; } - function useDebuffSkill(buff, isAll = false, exclusiveBuffs = undefined) { + function useDebuffSkill(buff, isAll = false) { const skillLib = { Sle: { name: 'Sleep', id: '222', img: 'sleep', - range: { 4207: [0, 0, 1] }, + range: { 4207: [1, 1, 2, 3] }, }, Bl: { name: 'Blind', id: '231', img: 'blind', - range: { 4206: [0, 0, 1] }, + range: { 4206: [1, 1, 2, 3] }, }, Slo: { name: 'Slow', id: '221', img: 'slow', - range: { 4213: [0, 0, 0, 1, 1] }, + range: { 4213: [1, 1, 2, 2, 2, 3] }, }, Im: { name: 'Imperil', id: '213', img: 'imperil', - range: { 4204: [0, 0, 0, 1] }, + range: { 4204: [1, 1, 2, 3] }, }, MN: { name: 'MagNet', id: '233', img: 'magnet', - range: { 4212: [0, 0, 0, 0, 1] }, + range: { 4212: [1, 1, 1, 2, 2, 3] }, }, Si: { name: 'Silence', id: '232', img: 'silence', - range: { 4211: [0, 0, 0, 1] }, + range: { 4211: [1, 1, 2, 3] }, }, Dr: { name: 'Drain', @@ -4657,20 +4674,20 @@ name: 'Weaken', id: '212', img: 'weaken', - range: { 4202: [0, 0, 0, 1] }, + range: { 4202: [1, 1, 2, 3] }, }, Co: { name: 'Confuse', id: '223', img: 'confuse', - range: { 4207: [0, 0, 1] }, + range: { 4207: [1, 1, 2, 3] }, }, }; if (!isOn(skillLib[buff].id)) { // 技能不可用 return false; } // 获取范围 - let range = 0; + let range = 1; let ab; const ability = getValue('ability', true); for (ab in skillLib[buff].range) { @@ -4678,15 +4695,16 @@ if (!ranges) { continue; } - if (ability && ability[ab]) { - range = ranges[ability[ab]]; - } + range = ranges[ability ? ability[ab] ?? 0 : 0]; break; } - // 获取目标 const option = g('option'); - + let exclusiveBuffs; + if (isAll && option.debuffAllExclusive) { + exclusiveBuffs = Object.keys(option.debuffAllExclusive); + exclusiveBuffs = exclusiveBuffs?.includes(buff) ? exclusiveBuffs : undefined + } let isDebuffed = (target, b) => { if (b || !exclusiveBuffs) { const current = getBuffTurnFromImg(getMonsterBuff(getMonsterID(target), skillLib[b ?? buff].img)); @@ -4694,7 +4712,7 @@ return threshold >= 0 && current > threshold; } for (const exclusive of exclusiveBuffs) { - if (isDebuffed(target, exclusive)) return true; + if (isDebuffed(target, exclusive)) return 0.9; } }; let debuffByIndex = isAll && option[`debuffSkill${buff}AllByIndex`]; @@ -4753,41 +4771,41 @@ 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] + 111: [3, 4, 4, 5, 5, 5, 5, 5], + 112: [4, 4, 6, 6, 6, 6, 7, 7], + 113: [7, 7, 7, 7, 8, 9, 9, 10] }, 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] + 121: [3, 4, 4, 5, 5, 5, 5, 5], + 122: [4, 4, 6, 6, 6, 6, 7, 7], + 123: [7, 7, 7, 7, 8, 9, 9, 10] }, 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] + 131: [3, 4, 4, 5, 5, 5, 5, 5], + 132: [4, 4, 6, 6, 6, 6, 7, 7], + 133: [7, 7, 7, 7, 8, 9, 9, 10] }, 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] + 141: [3, 4, 4, 5, 5, 5, 5, 5], + 142: [4, 4, 6, 6, 6, 6, 7, 7], + 143: [7, 7, 7, 7, 8, 9, 9, 10] }, //暗 - 4401: { 161: [0, 1, 2] }, - 4402: { 162: [0, 2, 3] }, - 4403: { 163: [0, 3, 4, 4] }, + 4401: { 161: [3, 4, 5] }, + 4402: { 162: [5, 6, 7] }, + 4403: { 163: [7, 8, 9, 10] }, //圣 - 4501: { 151: [0, 1, 2] }, - 4502: { 152: [0, 2, 3] }, - 4503: { 153: [0, 3, 4, 4] }, + 4501: { 151: [3, 4, 5] }, + 4502: { 152: [5, 6, 7] }, + 4503: { 153: [7, 8, 9, 10] }, } - let range = 0; + let range = 1; // Spell > Offensive Magic const attackStatus = g('attackStatus'); let target = g('battle').monsterStatus[0]; if (attackStatus === 0) { if (g('fightingStyle') === '1') { // 二天一流 - range = 1; + range = 3; } } else { if (g('option').etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) && checkCondition(g('option').etherTapCondition)) { @@ -4810,9 +4828,7 @@ continue; } const ability = getValue('ability', true); - if (ability && ability[ab]) { - range = ranges[ability[ab]]; - } + range = ranges[ability ? ability[ab] ?? 0 : 0]; break; } } From b8297eae260b3a66e3040a039d0986b28597d374 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 8 Dec 2025 17:06:16 +0800 Subject: [PATCH 180/216] 2.90.106 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 22216fae..49662b7d 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.105 +// @version 2.90.106 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3556,12 +3556,15 @@ // 3. 死亡、超过底下的将被溢出抛弃 const up = Math.floor(range / 2); const down = range - up - 1; - const top = Math.max(order - down, 0); + const top = order <= range ? 0 : Math.max(order - down, 0); const bottom = Math.min(order + up, msTemp.length-1); for (let i = top; i <= bottom; i++) { let center = i; + if (msTemp[center].isDead) continue; let rank = 0; - for (let inRange = center - up; inRange <= (center + down); inRange++) { + let overflow = Math.max(up-center,0); + const [min, max] = [center - up + overflow, center + down + overflow]; + for (let inRange = min; inRange <= max; inRange++) { let cew = inRange === center ? centralExtraWeight : 0; // cew <= 0, 增加未命中权重,降低命中权重 let mon = msTemp[inRange]; if (inRange < 0 || inRange >= msTemp.length || mon.isDead) { // 超出范围 或 死亡目标 @@ -3579,16 +3582,10 @@ rank += cew; // 中心目标会受到副手及冲击攻击时,相当于有效生命值降低 rank += forceUseIndex ? -1 : mon.finWeight; // 强制使用顺序而非权重时,全部使用统一的权重而非怪物状态 } - if (rank >= minRank) continue; - while (center >= 0) { - if (!msTemp[center].isDead) { - newOrder = center; - minRank = rank; - break; - } - // 中心目标死亡 且 top能达到第1个(order:0)目标,尝试往前寻找目标,通过上方溢出向下扩展来覆盖目标 - if (top !== 0) break; - center--; + if (rank < minRank) { + newOrder = center; + minRank = rank; + break; } } return { id: getMonsterID(newOrder), rank: minRank }; From 81253215033c37d30150da1531e5a7f62c9aff33 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Wed, 10 Dec 2025 12:03:38 +0800 Subject: [PATCH 181/216] =?UTF-8?q?2.90.107=20=E4=BF=AE=E6=AD=A3=E5=BA=93?= =?UTF-8?q?=E5=AD=98=E6=A3=80=E6=9F=A5=E4=B8=AD=E8=8D=AF=E6=B0=B4=E5=92=8C?= =?UTF-8?q?=E9=95=BF=E6=95=88=E8=8D=AFid=E5=AF=B9=E8=B0=83=E4=BA=86?= =?UTF-8?q?=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 | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 49662b7d..e810152f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.106 +// @version 2.90.107 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -221,7 +221,7 @@ $ajax.conn++; if (!$ajax.debug) return; const remain = $ajax.queue.map($ajax.simplify); - console.log('$ajax.send:', $ajax.simplify(current), remain ? 'remain:' : '', remain ?? ''); + console.log('$ajax.send:', $ajax.simplify(current), remain?.length ? 'remain:' : '', remain?.length ? remain : ''); }, onload: function (r) { $ajax.conn--; @@ -1184,14 +1184,14 @@ '
      ; 遭遇战前检查遭遇戰前檢查Check before encounter
      ', '
      [C!]检查物品库存檢查物品庫存Check is item needs supply;遭遇战前检查遭遇戰前檢查Check before encounter', '
      ', - '
      体力药水體力藥水Health Potion
      ', - '
      体力长效药體力長效藥Health Draught
      ', + '
      体力长效药體力長效藥Health Draught
      ', + '
      体力药水體力藥水Health Potion
      ', '
      体力秘药體力秘藥Health Elixir
      ', - '
      魔力药水魔力藥水Mana Potion
      ', - '
      魔力长效药魔力長效藥Mana Draught
      ', + '
      魔力长效药魔力長效藥Mana Draught
      ', + '
      魔力药水魔力藥水Mana Potion
      ', '
      魔力秘药魔力秘藥Mana Elixir
      ', - '
      灵力药水靈力藥水Spirit Potion
      ', - '
      灵力长效药靈力長效藥Spirit Draught
      ', + '
      灵力长效药靈力長效藥Spirit Draught
      ', + '
      灵力药水靈力藥水Spirit Potion
      ', '
      灵力秘药靈力秘藥Spirit Elixir
      ', '
      花瓶花瓶Flower Vase
      ', '
      泡泡糖泡泡糖Bubble-Gum
      ', @@ -1214,14 +1214,14 @@ '
      ', '
      [C!!]压榨届使用额外的库存检查壓榨屆使用額外的庫存檢查Extra supply check for Grind Fest', '
      ', - '
      体力药水體力藥水Health Potion
      ', - '
      体力长效药體力長效藥Health Draught
      ', + '
      体力药水體力藥水Health Potion
      ', + '
      体力长效药體力長效藥Health Draught
      ', '
      体力秘药體力秘藥Health Elixir
      ', - '
      魔力药水魔力藥水Mana Potion
      ', - '
      魔力长效药魔力長效藥Mana Draught
      ', + '
      魔力药水魔力藥水Mana Potion
      ', + '
      魔力长效药魔力長效藥Mana Draught
      ', '
      魔力秘药魔力秘藥Mana Elixir
      ', - '
      灵力药水靈力藥水Spirit Potion
      ', - '
      灵力长效药靈力長效藥Spirit Draught
      ', + '
      灵力药水靈力藥水Spirit Potion
      ', + '
      灵力长效药靈力長效藥Spirit Draught
      ', '
      灵力秘药靈力秘藥Spirit Elixir
      ', '
      花瓶花瓶Flower Vase
      ', '
      泡泡糖泡泡糖Bubble-Gum
      ', @@ -3277,6 +3277,7 @@ // 战斗中// function onBattleRound() { // 主程序 + if (!gE('#battle_main')) return; let battle = getValue('battle', true); if (!battle || !battle.roundAll) { // 修复因多个页面/世界同时读写造成缓存数据异常的情况 battle = JSON.parse(JSON.stringify(g('battle'))); From b8aa569f5a6d5954e729dfd620b0a6c7655998bf Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:36:34 +0800 Subject: [PATCH 182/216] =?UTF-8?q?2.90.108=20=E7=A7=BB=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E6=9C=89=E6=95=88=E7=9A=84=E7=B2=BE=E5=8A=9B=E6=8D=9F?= =?UTF-8?q?=E5=A4=B1=E6=97=B6=E7=9A=84=E8=84=9A=E6=9C=AC=E8=A1=8C=E4=B8=BA?= =?UTF-8?q?=EF=BC=9B=E5=A2=9E=E5=8A=A0=E7=B2=BE=E5=8A=9B=E6=B6=88=E8=80=97?= =?UTF-8?q?=E5=80=8D=E7=8E=87=E7=9A=84=E4=BC=B0=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e810152f..0394136e 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.107 +// @version 2.90.108 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -32,7 +32,7 @@ (function () { try { 'use strict'; - const standalone = ['option', 'arena', 'drop', 'stats', 'staminaLostLog', 'battleCode', 'disabled', 'stamina', 'staminaTime', 'lastHref', 'battle', 'monsterDB', 'monsterMID', 'ability']; + const standalone = ['option', 'arena', 'drop', 'stats', 'staminaLostLog', 'battleCode', 'disabled', 'stamina', 'lastHref', 'battle', 'monsterDB', 'monsterMID', 'ability']; const sharable = ['option']; const excludeStandalone = { 'option': ['optionStandalone', 'version', 'lang'] }; const href = window.location.href; @@ -1144,11 +1144,11 @@ '
      ', '
      继续新回合延时繼續新回合延時New round wait time: (秒)(秒)(s)
      ', '
      战斗结束退出延时戰鬥結束退出延時Exit battle wait time: (秒)(秒)(s)
      ', - '
      当损失精力當損失精力If it lost Stamina: ', - ' ;', - ' ; ', - ' ', - '
      ', + // '
      当损失精力當損失精力If it lost Stamina: ', + // ' ;', + // ' ; ', + // ' ', + // '
      ', '
      战斗页面停留戰鬥頁面停留If not active for : ', '
      ; ', '
      ', @@ -2852,8 +2852,9 @@ async function asyncSetStamina() { try { await waitPause(); $async.logSwitch(arguments); - const stamina = getValue('stamina') ?? {}; - [stamina.current, stamina.perk]= await Promise.all([ + const stamina = getValue('stamina', true) ?? { ratio: 1 }; + let [last, lastTime] = [stamina.current, stamina.time]; + [stamina.current, stamina.perk] = await Promise.all([ getCurrentStamina(), (async () => { try { if (isIsekai || !g('option').restoreStamina) { @@ -2876,6 +2877,14 @@ return perk; } catch(e) {console.error(e) }})() ]); + stamina.time = time(0); + if (stamina.lastCost) { + last += Math.floor(stamina.time / _1h) - Math.floor(lastTime / _1h); + const delta = last - stamina.current; + stamina.ratio = delta / stamina.lastCost; + console.log('last stamina ratio:', stamina.ratio); + stamina.lastCost = undefined; + } setValue('stamina', stamina); $async.logSwitch(arguments); } catch (e) { console.error(e) } } @@ -3023,7 +3032,7 @@ } catch(e) { console.error(e); }} async function checkStamina(low, cost) { - const stamina = getValue('stamina'); + const stamina = getValue('stamina', true); const option = g('option'); let now = time(0); let hours = Math.floor(now / _1h); @@ -3226,9 +3235,11 @@ 105: 1, 106: 1, 107: 1, 108: 1, 109: 1, 110: 1, 111: 1, 112: 1, gr: 0 } - let stamina = await getCurrentStamina(); + let stamina = getValue('stamina', true); + stamina.current = await getCurrentStamina(); + stamina.time = time(0); for (let id in staminaCost) { - staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina >= 60 ? 0.03 : 0.02) + staminaCost[id] *= (isIsekai ? 2 : 1) * (stamina.current >= 60 ? 0.03 : 0.02) } let query; @@ -3250,7 +3261,7 @@ return; } const cost = staminaCost[id]; - if (!await checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { + if (!await checkBattleReady(idleArena, { staminaCost: cost * (stamina.ratio ?? 1), checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { console.log('Check Battle Ready Failed', 'id:', id); $async.logSwitch(arguments); return; @@ -3265,6 +3276,8 @@ writeArenaStart(); await $ajax.insert(query, `initid=${id === 'gr' ? 1 : id}${token}`); console.log('Arena Fetch Done.', 'altBattleFirst:', option.altBattleFirst); + stamina.lastCost = cost; + setValue('stamina', stamina); if (option.altBattleFirst && await $ajax.insert(href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt'))) { console.log('Arena goto alt'); gotoAlt(true); From 64b32d11a4be72d9ec2f19d6e8a294e15d9512c5 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:37:44 +0800 Subject: [PATCH 183/216] Update stamina.lastCost handling for 'gr' case --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0394136e..1f45138f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3276,7 +3276,7 @@ writeArenaStart(); await $ajax.insert(query, `initid=${id === 'gr' ? 1 : id}${token}`); console.log('Arena Fetch Done.', 'altBattleFirst:', option.altBattleFirst); - stamina.lastCost = cost; + stamina.lastCost = id === 'gr' ? undefined : cost; setValue('stamina', stamina); if (option.altBattleFirst && await $ajax.insert(href.replace('hentaiverse.org', 'alt.hentaiverse.org').replace('alt.alt', 'alt'))) { console.log('Arena goto alt'); From 31e67344fb75629543219ba9b8d97c3ceb8f5dab Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:38:59 +0800 Subject: [PATCH 184/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1f45138f..44d6042a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -2881,11 +2881,11 @@ if (stamina.lastCost) { last += Math.floor(stamina.time / _1h) - Math.floor(lastTime / _1h); const delta = last - stamina.current; - stamina.ratio = delta / stamina.lastCost; - console.log('last stamina ratio:', stamina.ratio); + stamina.ratio = Math.max(1, delta / stamina.lastCost); stamina.lastCost = undefined; } setValue('stamina', stamina); + console.log('stamina', stamina); $async.logSwitch(arguments); } catch (e) { console.error(e) } } From aa3079ae0df240f50bc3455a9304524f507486b2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:45:21 +0800 Subject: [PATCH 185/216] =?UTF-8?q?=E6=9A=82=E6=97=B6=E4=B8=8D=E5=90=AF?= =?UTF-8?q?=E7=94=A8=E7=B2=BE=E5=8A=9B=E6=B6=88=E8=80=97=E5=80=8D=E7=8E=87?= =?UTF-8?q?=E6=9D=A5=E8=AE=A1=E7=AE=97cost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 44d6042a..1d4a7a48 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3261,7 +3261,7 @@ return; } const cost = staminaCost[id]; - if (!await checkBattleReady(idleArena, { staminaCost: cost * (stamina.ratio ?? 1), checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { + if (!await checkBattleReady(idleArena, { staminaCost: cost, checkEncounter: option.encounter, staminaLow: id === 'gr' ? option.staminaGrindFest : undefined })) { console.log('Check Battle Ready Failed', 'id:', id); $async.logSwitch(arguments); return; From cb39070d2a6edf68bef03993149899cf7ac222c4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:48:07 +0800 Subject: [PATCH 186/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1d4a7a48..3ca38d8b 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.108 +// @version 2.90.109 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues From 9c43923eb6a1b283ed56b5ada26303fc62ff4a27 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:51:37 +0800 Subject: [PATCH 187/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 3ca38d8b..a14aad1f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1802,16 +1802,16 @@ } }, 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', {}); - } - }; + // 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', {}); + // } + // }; gE('.idleArenaReset', optionBox).onclick = function () { if (_alert(1, '是否重置', '是否重置', 'Whether to reset')) { delValue('arena'); @@ -2862,6 +2862,7 @@ } let currentID = getCurrentUser(); const perk = stamina.perk ?? {}; + console.log(); if (perk[currentID]) { return; } @@ -3861,19 +3862,19 @@ setEncounter(encounter); } } - 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; - } - } - } + // 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 roundPrev = battle.roundNow; From 853c864ed029c37035e00e2de3f8a72897742c96 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 16:53:45 +0800 Subject: [PATCH 188/216] 2.90.110 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index a14aad1f..2d341d5f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.109 +// @version 2.90.110 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2857,18 +2857,17 @@ [stamina.current, stamina.perk] = await Promise.all([ getCurrentStamina(), (async () => { try { + const perk = stamina.perk ?? {}; if (isIsekai || !g('option').restoreStamina) { - return; + return perk; } let currentID = getCurrentUser(); - const perk = stamina.perk ?? {}; - console.log(); if (perk[currentID]) { - return; + return perk; } const html = await $ajax.insert('https://e-hentai.org/hathperks.php'); if (!html) { - return; + return perk; } const doc = $doc(html); const perks = gE('.stuffbox>table>tbody>tr', 'all', doc); From ef8e65fd52c9dd4419cc5373e0f228d57b05d0db Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 11 Dec 2025 20:04:45 +0800 Subject: [PATCH 189/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2d341d5f..ff396092 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -3706,12 +3706,13 @@ await waitPause(); if (g('monsterAlive') > 0) { // Defeat setExitBattleTimeout('Defeat'); + clearBattleUnresponsive(); } else if (g('battle').roundNow === g('battle').roundAll) { // Victory setExitBattleTimeout('Victory'); + clearBattleUnresponsive(); } else { // Next Round setTimeoutOrExecute(onNewRound, option.NewRoundWaitTime * _1s); } - clearBattleUnresponsive(); async function onNewRound() { try { await waitPause(); From 9aa3778ea7e1ba9f741ca5fd5fd8c82e3ae7c317 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 03:26:55 +0800 Subject: [PATCH 190/216] =?UTF-8?q?2.90.111=20=E5=A2=9E=E5=8A=A0=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=AD=94=E9=A2=98=E8=87=AA=E5=8A=A8=E6=8F=90?= =?UTF-8?q?=E4=BA=A4+=E9=9A=8F=E6=9C=BA=E7=AD=94=E6=A1=88=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 61 ++++++++++++++++--- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ff396092..e5082ec0 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.110 +// @version 2.90.111 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -362,6 +362,45 @@ return false; } + // 答题// + async function riddleAlert() { try { + setAlarm('Riddle'); + const option = g('option'); + const answerTime = option.riddleAnswerTime ?? 0; + let time; + const timeDiv = gE('#riddlecounter>div>div', 'all'); + while (time === undefined || time > answerTime) { + if (timeDiv.length === 0) { + await pauseAsync(_1s); + continue; + } + time = undefined; + for (let t of timeDiv) { + time = (t.style.backgroundPosition.match(/(\d+)px$/)[1] / 12).toString() + (time ?? ''); + } + time *= 1; + document.title = time; + await pauseAsync(_1s); + } + for (let ans of gE('#riddler1>*', 'all').children) { + if (!ans.children[0].children[0].checked) continue; + console.log('riddle submit'); + gE('#riddlesubmit').click(); + return; + } + if (!option.riddleAnswerChoose) return; + // if no answer selected + const answers = ['aj', 'fs', 'pp', 'ra', 'rd', 'ts']; + answers.sort(Math.random); + const answer = `riddlesubmit=Submit+Answer` + answers.slice(0, option.riddleAnswerChoose ?? 0).map(ans=>`&riddleanswer[]=${ans}`).join(''); + console.log('random submit', answer); + const battle = gE('#battle_main', $doc(await $ajax.fetch(window.location.href, answer))); + if (!battle) { + console.error('ERROR: Failed fetch submit.'); + } + goto(); + } catch(e) { console.error(e) }} + function checkIsWindowTop() { const currentUrl = window.self.location.href; if (!isFrame) { @@ -462,7 +501,7 @@ return false; } if (!g('option').riddlePopup || window.opener) { - setAlarm('Riddle'); + riddleAlert(); return true; } window.open(window.location.href, 'riddleWindow', 'resizable,scrollbars,width=1241,height=707'); @@ -959,11 +998,13 @@ } 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 (!gE('.hvAA-LangStyle')) { + 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;}`; + } } const globalStyle = gE('head').appendChild(cE('style')); const cssContent = [ @@ -1094,7 +1135,9 @@ '
      异世界相关異世界相關Isekai: ', ' ; ', '
      在任意页面停留在任意頁面停留While idle in any page for 秒后,自动切换恒定世界和异世界秒後,自動切換恆定世界和異世界s, auto switch between Isekai and Persistent
      ', - '
      小马答题小馬答題RIDDLE: ; ', + '
      ', + ' 小马答题小馬答題RIDDLE: ; ', + '
      时间時間If ETR秒,如果输入框为空则随机选中秒,如果輸入框為空則隨機選中s and no answer has been chosen yet, random 个答案并提交(请注意提交错误的答案可能比不提交或只提交一个正确选项的惩罚更重)个答案並提交(請注意提交錯誤的答案可能比不提交或只提交一個正確選項的懲罰更重)answers will be generated and submitted.(Notice that submit wrong answers might causing more punishment than submit nothing or single correct one)
      ', '
      ', '
      脚本行为腳本行為Script Activity', '
      ', @@ -2975,7 +3018,7 @@ } eqps = eqps.filter(e=>e); if (eqps.length) { - console.log('eqps need repair: ', eqps.join('\n')); + console.log('eqps need repair:\n', eqps.join('\n ')); document.title = `[R!]` + document.title; } $async.logSwitch(arguments); From 20a0450a3fba5850edde1c3a99b5ca638f48150a Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 03:29:24 +0800 Subject: [PATCH 191/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index e5082ec0..ba9c9b0f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -392,7 +392,7 @@ // if no answer selected const answers = ['aj', 'fs', 'pp', 'ra', 'rd', 'ts']; answers.sort(Math.random); - const answer = `riddlesubmit=Submit+Answer` + answers.slice(0, option.riddleAnswerChoose ?? 0).map(ans=>`&riddleanswer[]=${ans}`).join(''); + const answer = `riddlesubmit=Submit+Answer` + answers.slice(0, Math.max(0, Math.min(6, option.riddleAnswerChoose ?? 0))).map(ans=>`&riddleanswer[]=${ans}`).join(''); console.log('random submit', answer); const battle = gE('#battle_main', $doc(await $ajax.fetch(window.location.href, answer))); if (!battle) { From 70e00f92f1ab1e0a43863af417414488a22751cd Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 03:38:07 +0800 Subject: [PATCH 192/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index ba9c9b0f..1a1192c7 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1137,7 +1137,7 @@ '
      在任意页面停留在任意頁面停留While idle in any page for 秒后,自动切换恒定世界和异世界秒後,自動切換恆定世界和異世界s, auto switch between Isekai and Persistent
      ', '
      ', ' 小马答题小馬答題RIDDLE: ; ', - '
      时间時間If ETR秒,如果输入框为空则随机选中秒,如果輸入框為空則隨機選中s and no answer has been chosen yet, random 个答案并提交(请注意提交错误的答案可能比不提交或只提交一个正确选项的惩罚更重)个答案並提交(請注意提交錯誤的答案可能比不提交或只提交一個正確選項的懲罰更重)answers will be generated and submitted.(Notice that submit wrong answers might causing more punishment than submit nothing or single correct one)
      ', + '
      时间時間If ETR秒,提交当前选中答案 或 为空时随机选中秒,提交當前選中答案 或 為空時隨機選中s submit chosen answers or random 个答案并提交(请注意提交错误的答案可能比不提交或只提交一个正确选项的惩罚更重)个答案並提交(請注意提交錯誤的答案可能比不提交或只提交一個正確選項的懲罰更重)answers if none is chosen.(Notice that submit wrong answers might causing more punishment than submit nothing or single correct one)
      ', '
      ', '
      脚本行为腳本行為Script Activity', '
      ', From db8a7add9ab5ae15f9f3f833f2e1434b438677ee Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 03:56:39 +0800 Subject: [PATCH 193/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1a1192c7..8b0c8925 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1137,7 +1137,7 @@ '
      在任意页面停留在任意頁面停留While idle in any page for 秒后,自动切换恒定世界和异世界秒後,自動切換恆定世界和異世界s, auto switch between Isekai and Persistent
      ', '
      ', ' 小马答题小馬答題RIDDLE: ; ', - '
      时间時間If ETR秒,提交当前选中答案 或 为空时随机选中秒,提交當前選中答案 或 為空時隨機選中s submit chosen answers or random 个答案并提交(请注意提交错误的答案可能比不提交或只提交一个正确选项的惩罚更重)个答案並提交(請注意提交錯誤的答案可能比不提交或只提交一個正確選項的懲罰更重)answers if none is chosen.(Notice that submit wrong answers might causing more punishment than submit nothing or single correct one)
      ', + ' ', '
      ', '
      脚本行为腳本行為Script Activity', '
      ', From 667b96cd2641402a50231469a5e46096beb1bcaf Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 03:57:36 +0800 Subject: [PATCH 194/216] Update UI elements and labels in hvAutoAttack script --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8b0c8925..1190a732 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -1137,7 +1137,7 @@ '
      在任意页面停留在任意頁面停留While idle in any page for 秒后,自动切换恒定世界和异世界秒後,自動切換恆定世界和異世界s, auto switch between Isekai and Persistent
      ', '
      ', ' 小马答题小馬答題RIDDLE: ; ', - ' ', + ' ', '
      ', '
      脚本行为腳本行為Script Activity', '
      ', From d9d6edb8ef6bc7d81f5a7c54c41cb062d0d07be2 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 16 Dec 2025 17:48:44 +0800 Subject: [PATCH 195/216] =?UTF-8?q?2.90.112=20=E8=AF=BB=E5=8F=96=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E6=97=B6=E8=87=AA=E5=8A=A8=E6=B8=85=E9=99=A4=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 1190a732..039e0043 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.111 +// @version 2.90.112 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2568,7 +2568,7 @@ if (!Array.isArray(parms[i])) { continue; } - k = parms[i][j].split(','); + k = parms[i][j].replace(' ', '').split(','); const kk = k.toString(); k[0] = returnValue(k[0]); k[2] = returnValue(k[2]); @@ -2921,6 +2921,7 @@ } catch(e) {console.error(e) }})() ]); stamina.time = time(0); + const lastCost = stamina.lastCost; if (stamina.lastCost) { last += Math.floor(stamina.time / _1h) - Math.floor(lastTime / _1h); const delta = last - stamina.current; @@ -2928,7 +2929,7 @@ stamina.lastCost = undefined; } setValue('stamina', stamina); - console.log('stamina', stamina); + console.log('stamina', stamina, last, stamina.current, lastCost, stamina.ratio); $async.logSwitch(arguments); } catch (e) { console.error(e) } } From eabcf6112be522a5b56b07afd6f52b4895fb9658 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 19 Dec 2025 18:33:01 +0800 Subject: [PATCH 196/216] Update README_en.md --- HentaiVerse/hvAutoAttack/README_en.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/README_en.md b/HentaiVerse/hvAutoAttack/README_en.md index ccd03f27..38de9021 100644 --- a/HentaiVerse/hvAutoAttack/README_en.md +++ b/HentaiVerse/hvAutoAttack/README_en.md @@ -163,6 +163,14 @@ The following is a schematic diagram of the circuit diagram | Infusion of Storms / windinfusion | Infusion of Divinity / holyinfusion | Infusion of Darkness / darkinfusion | | Scroll of Swiftness / haste_scroll | - | - | | Flower Vase / flowers | Bubble-Gum / gum | - | +| Sleep / sleep | Blind / blind | Slow / slow | +| Imperil / imperil | MagNet / magnet | Silence / silence | +| Drain / drainhp | Weaken / weaken | Confuse / confuse | +| Coalesced Mana / coalescemana | Stunned / stun / wpn_stun | Penetrated Armor / ap / wpn_ap | +| Bleeding Wound / bleed / wpn_bleed | Absorbing Ward / absorb | Fury of the Sisters / trio_furyofthesisters | +| Lamentations of the Future / trio_skuld | Screams of the Past / trio_urd | Wailings of the Present / trio_verdandi | Searing Skin / firedot | Freezing Limbs / coldslow | +| Turbulent Air / windmiss | Deep Burns / elecweak | Breached Defense / holybreach | +| Blunted Attack / darknerf | Burning Soul / soulfire | Ripened Soul / ripesoul | *** @@ -197,3 +205,4 @@ In this example, the script will attack enemy 1 next. 1. see [README_Chinese#更新历史](https://github.com/dodying/UserJs/blob/master/HentaiVerse/hvAutoAttack/README.md#更新历史) + From 987f651289dfc984fb9966fbd2ffda127334344d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Fri, 19 Dec 2025 18:33:04 +0800 Subject: [PATCH 197/216] Update README.md --- HentaiVerse/hvAutoAttack/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index 54e3d59a..ac98b9c8 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -169,6 +169,14 @@ | Infusion of Storms / windinfusion | Infusion of Divinity / holyinfusion | Infusion of Darkness / darkinfusion | | Scroll of Swiftness / haste_scroll | - | - | | Flower Vase / flowers | Bubble-Gum / gum | - | +| Sleep / sleep | Blind / blind | Slow / slow | +| Imperil / imperil | MagNet / magnet | Silence / silence | +| Drain / drainhp | Weaken / weaken | Confuse / confuse | +| Coalesced Mana / coalescemana | Stunned / stun / wpn_stun | Penetrated Armor / ap / wpn_ap | +| Bleeding Wound / bleed / wpn_bleed | Absorbing Ward / absorb | Fury of the Sisters / trio_furyofthesisters | +| Lamentations of the Future / trio_skuld | Screams of the Past / trio_urd | Wailings of the Present / trio_verdandi | Searing Skin / firedot | Freezing Limbs / coldslow | +| Turbulent Air / windmiss | Deep Burns / elecweak | Breached Defense / holybreach | +| Blunted Attack / darknerf | Burning Soul / soulfire | Ripened Soul / ripesoul | *** @@ -393,3 +401,4 @@ + From 5c31a8f69cf5db53adda7db4b3632ab6d36f8e8d Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 09:15:54 +0800 Subject: [PATCH 198/216] =?UTF-8?q?2.90.113=20=E6=9D=A1=E4=BB=B6=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8=E8=BD=AC=E4=B8=BA?= =?UTF-8?q?=E9=80=86=E6=B3=A2=E5=85=B0=E5=BC=8F=E5=B9=B6=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=EF=BC=88=E5=8E=9F=E6=A0=BC=E5=BC=8F=E4=BB=8D=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 301 +++++++++++++++--- 1 file changed, 262 insertions(+), 39 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 039e0043..9711e9fe 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.112 +// @version 2.90.113 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -59,7 +59,7 @@ 'Forbidden', ]; const monsterStateKeys = { obj: `div.btm1`, lv: `div.btm2`, name: `div.btm3`, bars: `div.btm4>div.btm5`, buffs: `div.btm6` } - const [$async, $debug, $ajax] = [initAsync(), initDebug(), window.top.$ajax ??= unsafeWindow.$ajax ??= initAjax()]; + const [$RPN, $async, $debug, $ajax] = [initRPN(), initAsync(), initDebug(), window.top.$ajax ??= unsafeWindow.$ajax ??= initAjax()]; for (let check of [checkIsHV, checkIsWindowTop, checkOption]) { if (!check()) return; } @@ -70,6 +70,191 @@ setTimeout(goto, 5 * _1m); // ----------Process Steps---------- + function initRPN() { + const $RPN = { + operators: { + '>=': { precedence : 0, func: (a, b) => a >= b ? 1 : 0 }, + '<=': { precedence : 0, func: (a, b) => a <= b ? 1 : 0 }, + '==': { precedence : 0, func: (a, b) => a == b ? 1 : 0 }, + '!=': { precedence : 0, func: (a, b) => a != b ? 1 : 0 }, + '&&': { precedence : -1, func: (a, b) => a && b ? 1 : 0 }, + '||': { precedence : -1, func: (a, b) => a || b ? 1 : 0 }, + '**': { precedence:3, func: (a,b) => Math.pow(a, b)}, + '!': { precedence : -1, func: (a) => a ? 0 : 1 }, + '+': { precedence : 1, func: (a, b) => a + b }, + '-': { precedence : 1, func: (a, b) => a - b }, + '*': { precedence : 2, func: (a, b) => a * b }, + '/': { precedence : 2, func: (a, b) => a / b }, + '%': { precedence : 2, func: (a, b) => a % b }, + '>': { precedence : 0, func: (a, b) => a > b ? 1 : 0 }, + '<': { precedence : 0, func: (a, b) => a < b ? 1 : 0 }, + }, + + multiCharOperators: ['>=', '<=', '==', '!=', '&&', '||', '**'], + + isOperator(token) { + return token in $RPN.operators || $RPN.multiCharOperators.includes(token); + }, + + isMultiCharOperator(token) { + return $RPN.multiCharOperators.includes(token); + }, + + hasHigherPrecedence(op1, op2) { + return $RPN.operators[op1].precedence >= $RPN.operators[op2].precedence; + }, + + tokenize(expression) { + const tokens = []; + let i = 0; + + while (i < expression.length) { + const ch = expression[i]; + + if (ch === ' ') { + i++; + continue; + } + + if (ch === '(' || ch === ')') { + tokens.push(ch); + i++; + continue; + } + + let isMultiChar = false; + for (const op of $RPN.multiCharOperators) { + if (expression.startsWith(op, i)) { + tokens.push(op); + i += op.length; + isMultiChar = true; + break; + } + } + if (isMultiChar) continue; + + if ($RPN.isOperator(ch)) { + tokens.push(ch); + i++; + continue; + } + + if (/[0-9]/.test(ch)) { + let num = ''; + while (i < expression.length && /[0-9.]/.test(expression[i])) { + num += expression[i]; + i++; + } + tokens.push(parseFloat(num)); + continue; + } + + if (/[a-zA-Z_]/.test(ch)) { + let varName = ''; + while (i < expression.length && /[a-zA-Z0-9_]/.test(expression[i])) { + varName += expression[i]; + i++; + } + tokens.push(varName); + continue; + } + + throw new Error(`Unknown character: ${ch}`); + } + + return tokens; + }, + + infixToPostfix(infixTokens) { + const output = []; + const stack = []; + + for (const token of infixTokens) { + if (typeof token === 'number' || /[a-zA-Z_]/.test(token[0])) { + output.push(token); + } + else if (token === '(') { + stack.push(token); + } + else if (token === ')') { + while (stack.length && stack[stack.length - 1] !== '(') { + output.push(stack.pop()); + } + stack.pop(); + } + else if ($RPN.isOperator(token)) { + while ( + stack.length && + stack[stack.length - 1] !== '(' && + $RPN.hasHigherPrecedence(stack[stack.length - 1], token) + ) { + output.push(stack.pop()); + } + stack.push(token); + } + } + + while (stack.length) { + output.push(stack.pop()); + } + + return output; + }, + + evaluatePostfix(postfixTokens, resolver) { + const stack = []; + + for (const token of postfixTokens) { + if (typeof token === 'number') { + stack.push(token); + } + else if (typeof token === 'string' && /[a-zA-Z_]/.test(token[0])) { + const value = resolver ? resolver(token) : token; + stack.push(value); + } + else { + let a, b; + if (stack.length < 2) { + if (token === '-') { + b = stack.pop(); + a = 0; + } else if (token === '!') { + a = stack.pop(); + b = undefined; + } else { + throw new Error('Wrong Expression.'); + } + } else { + b = stack.pop(); + a = stack.pop(); + } + + let result; + if (token in $RPN.operators) { + result = $RPN.operators[token].func(a, b); + } else { + throw new Error(`Unknow operator: ${token}`); + } + stack.push(result); + } + } + + if (stack.length !== 1) { + throw new Error('Wrong Expression.'); + } + + return stack[0]; + }, + + evaluate(expression, variableHandler = null) { + const tokens = $RPN.tokenize(expression); + const postfix = $RPN.infixToPostfix(tokens); + return $RPN.evaluatePostfix(postfix, variableHandler); + } + }; + return $RPN; + } + function initDebug() { const $debug = { Stack: class extends Error { @@ -2274,6 +2459,13 @@ '', '', '', + '', + '', + '', + '', + '', + '', + '', '', '', '', @@ -2294,7 +2486,7 @@ `${String.fromCharCode(0x21F1.toString(10))}`, '', ``, - '', + '', ``, '', ].join(' '); @@ -2348,7 +2540,7 @@ input.type = 'text'; input.className = 'customizeInput'; input.name = `${target.getAttribute('name')}_${groupChoose - 1}`; - input.value = `${selects[1].value},${selects[2].value},${selects[3].value}`; + input.value = `${selects[1].value} ${selects[2].value} ${selects[3].value}`; }; function attr(target) { @@ -2518,8 +2710,6 @@ 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; @@ -2530,11 +2720,32 @@ } result = result[key] } - return isNaN(result * 1) ? result : (result * 1); + return isNaN(result * 1) ? result ?? str : (result * 1); } return str * 1; }; const func = { + ar() { + return g('battle').roundType === 'ar'; + }, + gr() { + return g('battle').roundType === 'gr'; + }, + tw() { + return g('battle').roundType === 'tw'; + }, + rb() { + return g('battle').roundType === 'rb'; + }, + iw() { + return g('battle').roundType === 'iw'; + }, + ba() { + return g('battle').roundType === 'ba'; + }, + isRoundType(t) { + return g('battle').roundType === t; + }, isCd(id) { // is cool down done return isOn(id) ? 1 : 0; }, @@ -2568,38 +2779,50 @@ if (!Array.isArray(parms[i])) { continue; } - k = parms[i][j].replace(' ', '').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 = k[0] > k[2]; - break; - case '2': - result = k[0] < k[2]; - break; - case '3': - result = k[0] >= k[2]; - break; - case '4': - result = k[0] <= k[2]; - break; - case '5': - result = k[0] === k[2]; - break; - case '6': - result = k[0] !== k[2]; - break; - } + k = parms[i][j].replace(/,\s*(.*)\s*,/, (match, p1) => { + switch (p1) { + case '>': + case '1': + return '>'; + case '<': + case '2': + return '<'; + case '≥': + case '>=': + case '3': + return '>='; + case '≤': + case '<=': + case '4': + return '<='; + case '=': + case '==': + case '===': + case '5': + return '=='; + case '≠': + case '~=': + case '<>': + case '!=': + case '6': + return '!='; + } + }).replace(/(?<])=(?!=)|≥|≤|≠|~=|<>/g, (match) => { + switch (match) { + case '≥': + return '>='; + case '≤': + return '<='; + case '=': + case '===': + return '=='; + case '≠': + case '~=': + case '<>': + return '!='; + } + }).replace(/'|"/g, ''); + result = $RPN.evaluate(k, returnValue); if (!result) { parmResult = false; break; From b7baa876f522f4210c6c73de7f9c4cd2d27f6f8b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 09:39:46 +0800 Subject: [PATCH 199/216] Revise README_en.md for clarity and updates(2.90.113+) Updated README with new sections and improved formatting. --- HentaiVerse/hvAutoAttack/README_en.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README_en.md b/HentaiVerse/hvAutoAttack/README_en.md index 38de9021..f07f1f94 100644 --- a/HentaiVerse/hvAutoAttack/README_en.md +++ b/HentaiVerse/hvAutoAttack/README_en.md @@ -49,6 +49,8 @@ Scripts get information through text, and if you have not yet modified the font, Each area with a red dotted border can be set to a customize condition. +Customizable Formula is support now, such as `hp > mp` or `2 * ( hp + mp ) > sp`, supported operators: `+` `-` `*` `/` `%` `&&` `||` `!` `>` `<` `>=`(`≥`) `<=`(`≤`) `==`(`=`,`===`) `!=`(`≠`,`~=`,`<>`), logical operators returns 0 or 1 (as false or true) + * If these areas are left blank (a condition is not set), then it's equivalent to true. When the mouse moves in these areas, a box is displayed in the upper right corner. (When the mouse out, the box disappears) @@ -59,9 +61,11 @@ Four drop down lists and one button are visible in the box * Drop-down List 2/4: comparison value A / comparison value B -* Drop-down List 3: only support comparison operator (`1`: >, `2`: <, `3`: ≥, `4`: ≤, `5`: =, `6`: ≠) +* Drop-down List 3: operator + +* Button ADD: Generates an input box with a value of `A Operator B` -* Button ADD: Generates an input box with a value of `A,Comparison-Operator,B` +* Legacy version condition such as `A,Comparison-Operator,B` is still supported, Comparison-Operator: (`1`: >, `2`: <, `3`: ≥, `4`: ≤, `5`: =, `6`: ≠) #### Comparison Value @@ -69,29 +73,30 @@ Four drop down lists and one button are visible in the box 2. `oc`: Overcharge, 0-250 3. `monsterAll`/`monsterAlive`/`bossAll`/`bossAlive`: amount of all monster/boss (alive) 4. `roundNow`/`roundAll`/`roundLeft` -5. `roundType`: Battle Type (`ar`: The Arena, `rb`: Ring of Blood, `gr`: GrindFest, `iw`: Item World, `ba`: Random Encounter) +5. `isRoundType`、`ar`、`ba`、`iw`、`tw`、`gr`、`rb`: is current round type as the target type, such as: both `_isRoundType_ar` and `_ar` returns `is currently in The Arena` +6. `roundType`: Battle Type (`ar`: The Arena, `rb`: Ring of Blood, `gr`: GrindFest, `iw`: Item World, `ba`: Random Encounter, `tw`: The Tower) - (**Note**: Because comparison between strings, please add quotation, such as `"ar"`/`'ar'`) + (**Note**: Because comparison between strings, please add quotation while using legacy version condition `A,Comparison-Operator,B` , such as `"ar"`/`'ar'`) -6. `attackStatus`: Attack Mode (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -7. `fightingStyle`: Fighting Style (`1`: Niten, `2`: 1H, `3`: 2H, `4`: DW, `5`: Staff) -8. `isCd`: whether the skill/item is cooldowning, format: `_isCd_id` +7. `attackStatus`: Attack Mode (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) +8. `fightingStyle`: Fighting Style (`1`: Niten, `2`: 1H, `3`: 2H, `4`: DW, `5`: Staff) +9. `isCd`: whether the skill/item is cooldowning, format: `_isCd_id` **example 1**: the id of Protection is 411 , `_isCd_411,5,0` means Protection can't be casted or `_isCd_411,5,1` means Protection can be casted **example 2**: the id of ManaElixir is 11295, `_isCd_11295,5,0` means ManaElixir can't be used or `_isCd_11295,5,1` means ManaElixir can be used -9. `buffTurn`: time the buff last in person, format`_buffTurn_img` +10. `buffTurn`: time the buff last in person, format`_buffTurn_img` **example**: the image of Protection is protection, `_buffTurn_protection,5,0` means you don't have the buff of Protection or `_buffTurn_protection,3,10` means the buff of Protection on you last at least 10 turns -10. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: +11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: 1. The highest priority monster by rank in default situations. 2. Weapon skills (OFC, T1~T3, etc.), Offensive Spell skills (Tire2, Tire3): by each condition > for each ranked target > find the target fit all sub-condition in the condition and cast to it. Such as the pic below: condition for Merciful Blow: only cast to targets which with hp below 25% and a bleed buff. ![example](https://github.com/user-attachments/assets/da181eac-e634-41ad-97a7-ff59a7b28b6d) -11. blank: the value you want to put in +12. blank: the value you want to put in #### Example @@ -206,3 +211,4 @@ In this example, the script will attack enemy 1 next. + From ed3577cd178b17d7786a4a708dd015248c36a823 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 09:39:57 +0800 Subject: [PATCH 200/216] Revise README.md for clarity and updates(2.90.113+) --- HentaiVerse/hvAutoAttack/README.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index ac98b9c8..e3e15650 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -50,9 +50,10 @@ *** ### 自定义判断条件 - 每一个拥有红色虚线边框的区域,都可以设置自定义判断条件。 +现已支持自定义的条件公式,例如`hp > mp` 或 `2 * ( hp + mp ) > sp`,支持运算符: `+` `-` `*` `/` `%` `**` `&&` `||` `!` `>` `<` `>=`(`≥`) `<=`(`≤`) `==`(`=`,`===`) `!=`(`≠`,`~=`,`<>`),逻辑运算符返回`0`或`1` (表示false或true) + * 注意:如果这些区域留空(一个条件也没设置),那么就相当于真。 当鼠标在这些区域内移动时,右上角会显示一个盒子(当鼠标不在这些区域内,盒子消失) @@ -63,9 +64,11 @@ * 下拉列表2/4: 比较值A/比较值B -* 下拉列表3: 只支持比较运算符(`1`:大于, `2`:小于, `3`: 大于等于, `4`: 小于等于, `5`:等于, `6`:不等于) +* 下拉列表3: 运算符 -* ADD按钮: 生成一个值为`比较值A,比较值,比较值B`的输入框 +* ADD按钮: 生成一个值为 `比较值A 运算符 比较值B` 的输入框 + +* 仍兼容旧版本 `比较值A,比较运算符,比较值B` 的条件,其中比较运算符:(`1`:大于, `2`:小于, `3`: 大于等于, `4`: 小于等于, `5`:等于, `6`:不等于) #### 比较值 @@ -73,29 +76,30 @@ 2. `oc`: Overcharge, 250==>250% 3. `monsterAll`/`monsterAlive`/`bossAll`/`bossAlive`: 怪兽/Boss的总数目/存活数目 4. `roundNow`/`roundAll`/`roundLeft`: 当前回合数/总回合数/剩余回合数 -5. `roundType`: 战役模式 (`ar`: The Arena, `rb`: Ring of Blood, `gr`: GrindFest, `iw`: Item World, `ba`: Random Encounter) +5. `isRoundType`、`ar`、`ba`、`iw`、`tw`、`gr`、`rb`: 当前是否是某战役模式,例如`_isRoundType_ar`或`_ar`均返回 `当前是否是The Arena` +6. `roundType`: 战役模式 (`ar`: The Arena, `rb`: Ring of Blood, `gr`: GrindFest, `iw`: Item World, `ba`: Random Encounter, `tw`: The Tower) - **注意**: 由于是字符串之间的比较,所以请加上引号,如"ar"/'ar' + **注意**: 由于是字符串之间的比较,所以用旧版本格式`比较值A,比较运算符,比较值B`时请加上引号,如"ar"/'ar' -6. `attackStatus`: 攻击模式 (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -7. `fightingStyle`: 战斗风格 (`1`: 二天, `2`: 单手, `3`: 双手, `4`: 双持, `5`: 法杖) -8. `isCd`: 技能/物品是否cd,格式`_isCd_id` +7. `attackStatus`: 攻击模式 (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) +8. `fightingStyle`: 战斗风格 (`1`: 二天, `2`: 单手, `3`: 双手, `4`: 双持, `5`: 法杖) +9. `isCd`: 技能/物品是否cd,格式`_isCd_id` **示例1**: Protection的id为411,则`_isCd_411,5,0`表示不可施放,`_isCd_411,5,1`表示可以施放 **示例2**: ManaElixir的id为11295,则`_isCd_11295,5,0`表示不可使用,`_isCd_11295,5,1`表示可以使用 -9. `buffTurn`: 人物Buff剩余时间,格式`_buffTurn_img` +10. `buffTurn`: 人物Buff剩余时间,格式`_buffTurn_img` **示例**: Protection的img为protection,则`_buffTurn_protection,5,0`表示不存在Protection的buff,`_buffTurn_protection,3,10`表示Protection的buff至少剩余10回合 -10. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 +11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 1. 默认情况的target均为权重优先级最高的目标 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff ![示例](https://github.com/user-attachments/assets/b4d0c57d-fdb1-464b-88d6-107643809339) -11. 空白(blank): 自己输入 (the value you want to put in) +12. 空白(blank): 自己输入 (the value you want to put in) #### 示例 @@ -402,3 +406,4 @@ + From c0b0515959ba8b557cbc11cf13779553576765d8 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 10:02:55 +0800 Subject: [PATCH 201/216] =?UTF-8?q?2.90.114=20=E5=A2=9E=E5=8A=A0=E5=AF=B9f?= =?UTF-8?q?ightStyle=E3=80=81attackStatus=E7=9A=84=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9711e9fe..8a59fd52 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.113 +// @version 2.90.114 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2468,7 +2468,19 @@ '', '', '', + '', + '', + '', + '', + '', + '', + '', '', + '', + '', + '', + '', + '', '', '', '', @@ -2746,6 +2758,42 @@ isRoundType(t) { return g('battle').roundType === t; }, + phys() { + return g('attackStatus') === 0 ? 1 : 0; + }, + fire() { + return g('attackStatus') * 1 === 10 ? 1 : 0; + }, + cold() { + return g('attackStatus') * 1 === 20 ? 1 : 0; + }, + elec() { + return g('attackStatus') * 1 === 30 ? 1 : 0; + }, + wind() { + return g('attackStatus') * 1 === 40 ? 1 : 0; + }, + divi() { + return g('attackStatus') * 1 === 50 ? 1 : 0; + }, + forb() { + return g('attackStatus') * 1 === 60 ? 1 : 0; + }, + nt() { + return g('fightingStyle') * 1 === 10 ? 1 : 0; + }, + onehanded() { + return g('fightingStyle') * 1 === 20 ? 1 : 0; + }, + twohanded() { + return g('fightingStyle') * 1 === 30 ? 1 : 0; + }, + dw() { + return g('fightingStyle') * 1 === 40 ? 1 : 0; + }, + staff() { + return g('fightingStyle') * 1 === 50 ? 1 : 0; + }, isCd(id) { // is cool down done return isOn(id) ? 1 : 0; }, @@ -2821,7 +2869,7 @@ case '<>': return '!='; } - }).replace(/'|"/g, ''); + }).replace(/'|"/g, '').replace('_1h', '_onehanded').replace('_2h', '_twohanded'); result = $RPN.evaluate(k, returnValue); if (!result) { parmResult = false; From 663a948db77657ff08ad0bc8222bb45cfb8d7f3b Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 10:12:02 +0800 Subject: [PATCH 202/216] Update README.md for 2.90.114 --- HentaiVerse/hvAutoAttack/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README.md b/HentaiVerse/hvAutoAttack/README.md index e3e15650..14589390 100644 --- a/HentaiVerse/hvAutoAttack/README.md +++ b/HentaiVerse/hvAutoAttack/README.md @@ -81,19 +81,19 @@ **注意**: 由于是字符串之间的比较,所以用旧版本格式`比较值A,比较运算符,比较值B`时请加上引号,如"ar"/'ar' -7. `attackStatus`: 攻击模式 (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -8. `fightingStyle`: 战斗风格 (`1`: 二天, `2`: 单手, `3`: 双手, `4`: 双持, `5`: 法杖) +7. `attackStatus`: 攻击模式 (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden)。 或使用 `_phys`, `_fire`, `_cold`, `_elec`, `_wind`, `_divi`, `_forb` 表示 `当前 attack mode 是否为 ...`,例如 `_phys` 等价于 `attackStatus == 0` +8. `fightingStyle`: 战斗风格 (`1`: 二天, `2`: 单手, `3`: 双手, `4`: 双持, `5`: 法杖)。 或使用 `_nt`, `_1h`, `_2h`, `_dw`, `_staff` 表示 `当前 fighting style 是否为 ...`,例如 `_nt` 等价于 `fightStyle == 1` 9. `isCd`: 技能/物品是否cd,格式`_isCd_id` - **示例1**: Protection的id为411,则`_isCd_411,5,0`表示不可施放,`_isCd_411,5,1`表示可以施放 + **示例1**: Protection的id为411,则`!_isCd_411`表示不可施放,`_isCd_411`表示可以施放 - **示例2**: ManaElixir的id为11295,则`_isCd_11295,5,0`表示不可使用,`_isCd_11295,5,1`表示可以使用 + **示例2**: ManaElixir的id为11295,则`!_isCd_11295`表示不可使用,`_isCd_11295`表示可以使用 10. `buffTurn`: 人物Buff剩余时间,格式`_buffTurn_img` - **示例**: Protection的img为protection,则`_buffTurn_protection,5,0`表示不存在Protection的buff,`_buffTurn_protection,3,10`表示Protection的buff至少剩余10回合 + **示例**: Protection的img为protection,则`_buffTurn_protection == 0`表示不存在Protection的buff,`_buffTurn_protection >= 10`表示Protection的buff至少剩余10回合 -11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed,6,0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 +11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: 目标怪物的HP%、SP%、MP%、buff剩余时间,`_targetBuffTurn_`后缀参照8.`buffTurn`(如:`_targetBuffTurn_bleed != 0`表示目标bleed的buff剩余回合不等于0)。target的目标怪物遵循以下规则 1. 默认情况的target均为权重优先级最高的目标 2. 武器技能(马炮、T1~T3等)、法术技能(中阶、高阶):按照 逐条条件判断>按权重逐个目标>满足任意一条条件内的所有子条目,则对该目标释放。例如下图最后的慈悲的条件:仅释放hp小于25%、拥有流血buff @@ -407,3 +407,4 @@ + From 17d341699438e5d36897ebeef08633c9b95741c3 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 10:12:07 +0800 Subject: [PATCH 203/216] Update README_en.md for 2.90.114 --- HentaiVerse/hvAutoAttack/README_en.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/README_en.md b/HentaiVerse/hvAutoAttack/README_en.md index f07f1f94..9d17159f 100644 --- a/HentaiVerse/hvAutoAttack/README_en.md +++ b/HentaiVerse/hvAutoAttack/README_en.md @@ -78,19 +78,19 @@ Four drop down lists and one button are visible in the box (**Note**: Because comparison between strings, please add quotation while using legacy version condition `A,Comparison-Operator,B` , such as `"ar"`/`'ar'`) -7. `attackStatus`: Attack Mode (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden) -8. `fightingStyle`: Fighting Style (`1`: Niten, `2`: 1H, `3`: 2H, `4`: DW, `5`: Staff) +7. `attackStatus`: Attack Mode (`0`: Physical, `1`: Fire, `2`: Cold, `3`: Elec, `4`: Wind, `5`: Divine, `6`: Forbidden). Or use `_phys`, `_fire`, `_cold`, `_elec`, `_wind`, `_divi`, `_forb` as `if current attack mode is ...`, such as `_phys` equals `attackStatus == 0` +8. `fightingStyle`: Fighting Style (`1`: Niten, `2`: 1H, `3`: 2H, `4`: DW, `5`: Staff). Or use `_nt`, `_1h`, `_2h`, `_dw`, `_staff` as `if current fighting style is ...`, such as `_nt` equals `fightStyle == 1` 9. `isCd`: whether the skill/item is cooldowning, format: `_isCd_id` - **example 1**: the id of Protection is 411 , `_isCd_411,5,0` means Protection can't be casted or `_isCd_411,5,1` means Protection can be casted + **example 1**: the id of Protection is 411 , `!_isCd_411` means Protection can't be casted or `_isCd_411` means Protection can be casted - **example 2**: the id of ManaElixir is 11295, `_isCd_11295,5,0` means ManaElixir can't be used or `_isCd_11295,5,1` means ManaElixir can be used + **example 2**: the id of ManaElixir is 11295, `!_isCd_11295` means ManaElixir can't be used or `_isCd_11295` means ManaElixir can be used 10. `buffTurn`: time the buff last in person, format`_buffTurn_img` - **example**: the image of Protection is protection, `_buffTurn_protection,5,0` means you don't have the buff of Protection or `_buffTurn_protection,3,10` means the buff of Protection on you last at least 10 turns + **example**: the image of Protection is protection, `_buffTurn_protection == 0` means you don't have the buff of Protection or `_buffTurn_protection >= 10` means the buff of Protection on you last at least 10 turns -11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed,6,0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: +11. `targetHp`、`targetMp`、`targetSp`、`targetBuffTurn`: HP%、SP%、MP%、buffRemainTime of target monster, suffix of `_targetBuffTurn_` is same as 8.`buffTurn`(such as:`_targetBuffTurn_bleed != 0` means remain turns of bleed buff on target monster is not equal to 0. Target that is calculating is chosen by following rules: 1. The highest priority monster by rank in default situations. 2. Weapon skills (OFC, T1~T3, etc.), Offensive Spell skills (Tire2, Tire3): by each condition > for each ranked target > find the target fit all sub-condition in the condition and cast to it. Such as the pic below: condition for Merciful Blow: only cast to targets which with hp below 25% and a bleed buff. @@ -212,3 +212,4 @@ In this example, the script will attack enemy 1 next. + From a5df611318db347bf6a512eb2a3729435b33eee4 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 17:05:19 +0800 Subject: [PATCH 204/216] =?UTF-8?q?2.90.115=20=E4=BF=AE=E6=AD=A3=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 102 +++++++++++------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 8a59fd52..c8e1592f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.114 +// @version 2.90.115 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1346,18 +1346,22 @@ '
      战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed):
      ', '
      ', - '
      ', - '
      ', - '
      ', - '

      ', - '
      ', - '
      ', - '
      ', - '

      ', - '
      ', - '
      ', - '
      ', - '
      ', + '
      ', + '
      ', + '
      ', + + '
      ', + '

      ', + '
      ', + '
      ', + '
      ', + '
      ', + '

      ', + '
      ', + + '
      ', + '
      ', + '
      ', '
      ', '
      使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
      ', '
      ', @@ -2077,12 +2081,12 @@ if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { return; } - const valueArray = e.target.value.split(','); + const value = e.target.value; let name = gE('input[name="battleOrderName"]').value; if (e.target.checked) { - name = name + ((name) ? `,${valueArray[0]}` : valueArray[0]); + name = name + ((name) ? `,${value}` : value); } else { - name = name.replace(new RegExp(`(^|,)${valueArray[0]}(,|$)`), '$2').replace(/^,/, ''); + name = name.replace(new RegExp(`(^|,)${value}(,|$)`), '$2').replace(/^,/, ''); } gE('input[name="battleOrderName"]').value = name; }; @@ -2738,61 +2742,61 @@ }; const func = { ar() { - return g('battle').roundType === 'ar'; + return g('battle').roundType === 'ar' ? 1 : 0; }, gr() { - return g('battle').roundType === 'gr'; + return g('battle').roundType === 'gr' ? 1 : 0; }, tw() { - return g('battle').roundType === 'tw'; + return g('battle').roundType === 'tw' ? 1 : 0; }, rb() { - return g('battle').roundType === 'rb'; + return g('battle').roundType === 'rb' ? 1 : 0; }, iw() { - return g('battle').roundType === 'iw'; + return g('battle').roundType === 'iw' ? 1 : 0; }, ba() { - return g('battle').roundType === 'ba'; + return g('battle').roundType === 'ba' ? 1 : 0; }, isRoundType(t) { - return g('battle').roundType === t; + return g('battle').roundType === t ? 1 : 0; }, phys() { - return g('attackStatus') === 0 ? 1 : 0; + return g('attackStatus') * 1 === 0 ? 1 : 0; }, fire() { - return g('attackStatus') * 1 === 10 ? 1 : 0; + return g('attackStatus') * 1 === 1 ? 1 : 0; }, cold() { - return g('attackStatus') * 1 === 20 ? 1 : 0; + return g('attackStatus') * 1 === 2 ? 1 : 0; }, elec() { - return g('attackStatus') * 1 === 30 ? 1 : 0; + return g('attackStatus') * 1 === 3 ? 1 : 0; }, wind() { - return g('attackStatus') * 1 === 40 ? 1 : 0; + return g('attackStatus') * 1 === 4 ? 1 : 0; }, divi() { - return g('attackStatus') * 1 === 50 ? 1 : 0; + return g('attackStatus') * 1 === 5 ? 1 : 0; }, forb() { - return g('attackStatus') * 1 === 60 ? 1 : 0; + return g('attackStatus') * 1 === 6 ? 1 : 0; }, nt() { - return g('fightingStyle') * 1 === 10 ? 1 : 0; + return g('fightingStyle') * 1 === 1 ? 1 : 0; }, onehanded() { - return g('fightingStyle') * 1 === 20 ? 1 : 0; + return g('fightingStyle') * 1 === 2 ? 1 : 0; }, twohanded() { - return g('fightingStyle') * 1 === 30 ? 1 : 0; + return g('fightingStyle') * 1 === 3 ? 1 : 0; }, dw() { - return g('fightingStyle') * 1 === 40 ? 1 : 0; + return g('fightingStyle') * 1 === 4 ? 1 : 0; }, staff() { - return g('fightingStyle') * 1 === 50 ? 1 : 0; + return g('fightingStyle') * 1 === 5 ? 1 : 0; }, isCd(id) { // is cool down done return isOn(id) ? 1 : 0; @@ -2875,8 +2879,10 @@ parmResult = false; break; } + console.log(k, result); } if (parmResult) { + console.log(parms[i], parmResult); return target; } } @@ -3790,7 +3796,8 @@ } const taskList = { 'Pause': autoPause, - 'Rec': autoRecover, + 'Cure': ()=>autoRecover(true), + 'Rec': ()=>autoRecover(false), 'Def': autoDefend, 'Scroll': useScroll, 'Channel': useChannelSkill, @@ -3798,7 +3805,8 @@ 'Infus': useInfusions, 'Debuff': useDeSkill, 'Focus': autoFocus, - 'SS': autoSS, + 'SS': ()=>autoSS(true), + 'SSDisable': ()=>autoSS(false), 'Skill': autoSkill, 'Atk': attack, }; @@ -3806,6 +3814,7 @@ for (let i = 0; i < names.length; i++) { if (taskList[names[i]]()) { onStepInDone(); + console.log(names[i]); return; } delete taskList[names[i]]; @@ -3813,6 +3822,7 @@ for (let name in taskList) { if (taskList[name]()) { onStepInDone(); + console.log(name); return; } } @@ -4459,17 +4469,22 @@ g('battle', battle); } - function autoRecover() { // 自动回血回魔 + function autoRecover(isCureOnly) { // 自动回血回魔 const option = g('option'); if (!option.item) { return false; } const name = splitOrders(option.itemOrderName, ['FC', 'HE', 'LE', 'HG', 'HP', 'Cure', 'MG', 'MP', 'ME', 'SG', 'SP', 'SE', 'Mystic', 'CC', 'ED']); const order = splitOrders(option.itemOrderValue, [11199, 11501, 10005, 11195, 311, 10006, 11295, 11299, 10007, 11395, 11399, 10008, 11402, 11401]); + const cures = [11199, 11501, 10005, 11195, 311, 10006]; for (let i = 0; i < name.length; i++) { let id = order[i]; + if (isCureOnly && !(id in cures)){ + continue; + } if (option.item[name[i]] && checkCondition(option[`item${name[i]}Condition`]) && isOn(id)) { (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); + console.log('rec', name[i],option[`item${name[i]}Condition`], checkCondition(option[`item${name[i]}Condition`])); return true; } } @@ -4742,6 +4757,7 @@ const threshold = option.buffSkillThreshold ? option.buffSkillThreshold[buff] ?? 0 : 0; if (threshold >= 0 && current > threshold) continue; gE(skillLib[buff].id).click(); + console.log(buff); return true; } const draughtPack = { @@ -4769,6 +4785,7 @@ for (i in draughtPack) { if (!getPlayerBuff(draughtPack[i].img) && option.buffSkill && option.buffSkill[i] && checkCondition(option[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`)) { gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`).click(); + console.log(draughtPack[i]); return true; } } @@ -4822,14 +4839,19 @@ return false; } - function autoSS() { + function autoSS(isDisableOnly) { const textSP = gE('#vrs') ?? gE('#dvrs'); const spValue = textSP.childNodes[0].textContent * 1; if (spValue <= 1) { return false; } const option = g('option'); - if ((option.turnOnSS && checkCondition(option.turnOnSSCondition) && !gE('#ckey_spirit[src*="spirit_a"]')) || (option.turnOffSS && checkCondition(option.turnOffSSCondition) && gE('#ckey_spirit[src*="spirit_a"]'))) { + const enabled = gE('#ckey_spirit[src*="spirit_a"]'); + if ( + (!isDisableOnly && option.turnOnSS && checkCondition(option.turnOnSSCondition) && !enabled) + || + (option.turnOffSS && checkCondition(option.turnOffSSCondition) && enabled) + ) { gE('#ckey_spirit').click(); return true; } From 77427548af24129099562c983e5eb1000f0f199c Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 21 Dec 2025 17:50:16 +0800 Subject: [PATCH 205/216] =?UTF-8?q?2.90.116=20=E4=BF=AE=E6=AD=A3=E6=B2=BB?= =?UTF-8?q?=E7=96=97=E7=9A=84=E9=BB=98=E8=AE=A4=E9=A1=BA=E5=BA=8Fid?= =?UTF-8?q?=E9=94=99=E8=AF=AF=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 | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index c8e1592f..487b536a 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.115 +// @version 2.90.116 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2879,10 +2879,8 @@ parmResult = false; break; } - console.log(k, result); } if (parmResult) { - console.log(parms[i], parmResult); return target; } } @@ -3814,7 +3812,6 @@ for (let i = 0; i < names.length; i++) { if (taskList[names[i]]()) { onStepInDone(); - console.log(names[i]); return; } delete taskList[names[i]]; @@ -3822,7 +3819,6 @@ for (let name in taskList) { if (taskList[name]()) { onStepInDone(); - console.log(name); return; } } @@ -4475,16 +4471,15 @@ return false; } const name = splitOrders(option.itemOrderName, ['FC', 'HE', 'LE', 'HG', 'HP', 'Cure', 'MG', 'MP', 'ME', 'SG', 'SP', 'SE', 'Mystic', 'CC', 'ED']); - const order = splitOrders(option.itemOrderValue, [11199, 11501, 10005, 11195, 311, 10006, 11295, 11299, 10007, 11395, 11399, 10008, 11402, 11401]); - const cures = [11199, 11501, 10005, 11195, 311, 10006]; + const order = splitOrders(option.itemOrderValue, [313, 11199, 11501, 10005, 11195, 311, 10006, 11295, 11299, 10007, 11395, 11399, 10008, 11402, 11401]); + const cures = [313, 11199, 11501, 10005, 11195, 311]; for (let i = 0; i < name.length; i++) { let id = order[i]; - if (isCureOnly && !(id in cures)){ + if (isCureOnly && !cures.includes(id)){ continue; } if (option.item[name[i]] && checkCondition(option[`item${name[i]}Condition`]) && isOn(id)) { (gE(`.bti3>div[onmouseover*="(${id})"]`) ?? gE(id)).click(); - console.log('rec', name[i],option[`item${name[i]}Condition`], checkCondition(option[`item${name[i]}Condition`])); return true; } } @@ -4757,7 +4752,6 @@ const threshold = option.buffSkillThreshold ? option.buffSkillThreshold[buff] ?? 0 : 0; if (threshold >= 0 && current > threshold) continue; gE(skillLib[buff].id).click(); - console.log(buff); return true; } const draughtPack = { @@ -4785,7 +4779,6 @@ for (i in draughtPack) { if (!getPlayerBuff(draughtPack[i].img) && option.buffSkill && option.buffSkill[i] && checkCondition(option[`buffSkill${i}Condition`]) && gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`)) { gE(`.bti3>div[onmouseover*="(${draughtPack[i].id})"]`).click(); - console.log(draughtPack[i]); return true; } } From 658505e27e6fe35b3e8ebc6eebdc2def4825e0fe Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 22 Dec 2025 22:12:10 +0800 Subject: [PATCH 206/216] =?UTF-8?q?2.90.117=20=E4=BF=AE=E6=AD=A3=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=81=B5=E5=8A=A8=E6=9E=B6=E5=8A=BF=E7=9A=84=E6=89=A7?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 487b536a..81002faf 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.116 +// @version 2.90.117 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3803,8 +3803,8 @@ 'Infus': useInfusions, 'Debuff': useDeSkill, 'Focus': autoFocus, - 'SS': ()=>autoSS(true), - 'SSDisable': ()=>autoSS(false), + 'SS': ()=>autoSS(false), + 'SSDisable': ()=>autoSS(true), 'Skill': autoSkill, 'Atk': attack, }; From 28d3a525a599213134df1b1cdfa286b02230064e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Mon, 22 Dec 2025 22:40:21 +0800 Subject: [PATCH 207/216] =?UTF-8?q?2.90.118=20=E5=A2=9E=E5=8A=A0=E4=B8=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=87=AA=E5=AE=9A=E4=B9=89=E6=88=98=E6=96=97?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E7=9A=84=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 81002faf..73baac63 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.117 +// @version 2.90.118 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1344,25 +1344,25 @@ '
      *攻击模式攻擊模式Attack Mode:', '
      ', - '
      战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed):
      ', - '
      ', - '
      ', - '
      ', - '
      ', - - '
      ', - '

      ', - '
      ', - '
      ', - '
      ', - '
      ', - '

      ', - '
      ', - - '
      ', - '
      ', - '
      ', - '
      ', + '
      战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed): ', + '

      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '

      ', + '
      ', + '
      ', + '
      ', + '
      ', + '

      ', + '
      ', + + '
      ', + '
      ', + '
      ', + '
      ', '
      使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
      ', '
      ', '
      ', @@ -3808,7 +3808,8 @@ 'Skill': autoSkill, 'Atk': attack, }; - const names = g('option').battleOrderName?.split(',') ?? []; + const option = g('option'); + const names = option.battleOrderDefaultOnly ? [] : option.battleOrderName?.split(',') ?? []; for (let i = 0; i < names.length; i++) { if (taskList[names[i]]()) { onStepInDone(); From be2d37d4fbe7d245c26b60148a4ae9e094e92bf0 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 00:05:53 +0800 Subject: [PATCH 208/216] =?UTF-8?q?2.90.119=20=E5=A2=9E=E5=8A=A0=E4=BD=8E?= =?UTF-8?q?=E9=98=B6=E9=AD=94=E6=B3=95=E6=8A=80=E8=83=BD=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=EF=BC=8C=E6=94=BB=E5=87=BB=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=BA=E9=9D=9E=E7=89=A9=E7=90=86=E6=97=B6=E5=B0=86=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E6=A0=B9=E6=8D=AE=E8=AF=A5=E6=9D=A1=E4=BB=B6=E6=9D=A5?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E4=BD=8E=E9=98=B6=E9=AD=94=E6=B3=95=E6=8A=80?= =?UTF-8?q?=E8=83=BD=EF=BC=88=E6=89=80=E6=9C=89=E9=AD=94=E6=B3=95=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E5=9D=87=E4=B8=8D=E6=BB=A1=E8=B6=B3=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E6=97=B6=E4=BD=BF=E7=94=A8=E7=89=A9=E7=90=86=E6=94=BB=E5=87=BB?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 79 +++++++++++-------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 73baac63..2d68a1cd 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.118 +// @version 2.90.119 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1364,6 +1364,7 @@ '
      ', '
      ', '
      使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
      ', + '
      ', '
      ', '
      ', '
      : {{etherTapCondition}}
      ', @@ -5142,45 +5143,57 @@ 4502: { 152: [5, 6, 7] }, 4503: { 153: [7, 8, 9, 10] }, } - let range = 1; + let range = g('fightingStyle') === '1' ? 3 : 1; // Spell > Offensive Magic + const option = g('option'); const attackStatus = g('attackStatus'); - let target = g('battle').monsterStatus[0]; - if (attackStatus === 0) { - if (g('fightingStyle') === '1') { // 二天一流 - range = 3; + const monsters = g('battle').monsterStatus; + let target = monsters[0]; + const tryAttack = () => { + if (!target || target.isDead) { + return false; } - } else { - if (g('option').etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`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--}`; - target = checkCondition(condition, g('battle').monsterStatus); - if (target && isOn(id)) { - return id; - } - } - })(); - gE(skill)?.click(); - for (let ab in updateAbility) { - const ranges = updateAbility[ab][skill]; - if (!ranges) { - continue; - } - const ability = getValue('ability', true); - range = ranges[ability ? ability[ab] ?? 0 : 0]; - break; + clickMonster(getRangeCenter(target, range, !attackStatus).id); + return true; + }; + // 1. physical + if (attackStatus === 0) { + return tryAttack(); + } + + // 2. etherTap + if (option.etherTap && getMonsterBuff(getMonsterID(target), 'coalescemana') + && (!gE('#pane_effects>img[onmouseover*="Ether Tap (x2)"]') || getPlayerBuff(`wpn_et"][id*="effect_expire`)) + && checkCondition(option.etherTapCondition)) { + return tryAttack(); + } + // 2.5 try check skill condition + const skill = 1 * (() => { + let lv = 3; + for (let condition of [option.highSkillCondition, option.middleSkillCondition, option.lowSkillCondition]) { + let id = `1${attackStatus}${lv--}`; + target = checkCondition(condition, monsters); + if (target && isOn(id)) { + return id; } } + })(); + // 3. no skill available + if (!skill) { + return tryAttack(); } - if (!target || target.isDead) { - return false; + // 4. cast skill + for (let ab in updateAbility) { + const ranges = updateAbility[ab][skill]; + if (!ranges) { + continue; + } + const ability = getValue('ability', true); + range = ranges[ability ? ability[ab] ?? 0 : 0]; + break; } - clickMonster(getRangeCenter(target, range, !attackStatus).id); - return true; + gE(skill)?.click(); + return tryAttack(); } function getHPFromMonsterDB(mdb, name, lv) { From 163d05e0c22d900b110008b8bd47a593aec362af Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 01:14:25 +0800 Subject: [PATCH 209/216] =?UTF-8?q?2.90.120=20=E6=B7=BB=E5=8A=A0=E6=AC=A1?= =?UTF-8?q?=E8=A6=81=E6=94=BB=E5=87=BB=E6=A8=A1=E5=BC=8F=EF=BC=88=E5=8F=8A?= =?UTF-8?q?=E5=85=B6=E9=A1=BA=E5=BA=8F=E3=80=81=E6=9D=A1=E4=BB=B6=EF=BC=89?= =?UTF-8?q?=E3=80=82=E6=89=A7=E8=A1=8C=E6=94=BB=E5=87=BB=E5=89=8D=EF=BC=8C?= =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=8C=89=E7=85=A7=E9=A1=BA=E5=BA=8F=E5=92=8C?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84=E6=9D=A1=E4=BB=B6=E5=B0=9D=E8=AF=95?= =?UTF-8?q?=E6=89=BE=E5=88=B0=E6=AC=A1=E8=A6=81=E6=A8=A1=E5=BC=8F=E5=B9=B6?= =?UTF-8?q?=E6=94=BB=E5=87=BB=EF=BC=8C=E5=90=A6=E5=88=99=EF=BC=88=E6=B2=A1?= =?UTF-8?q?=E6=89=BE=E5=88=B0=E6=88=96=E6=89=80=E6=9C=89=E9=83=BD=E6=94=BB?= =?UTF-8?q?=E5=87=BB=E5=A4=B1=E8=B4=A5=EF=BC=89=E4=BD=BF=E7=94=A8=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=94=BB=E5=87=BB=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 85 +++++++++++++++---- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 2d68a1cd..995618e2 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.119 +// @version 2.90.120 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1341,11 +1341,11 @@ '
      延迟延遲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:', - '
      ', + '
      *默认攻击模式默認攻擊模式Default Attack Mode:', + '
      ', '
      战斗执行顺序(未配置的按照下面的顺序)戰鬥執行順序(未配置的按照下面的順序)Battal Order(Using order below as default if not configed): ', - '

      ', + '

      ', '
      ', '
      ', '
      ', @@ -1363,7 +1363,27 @@ '
      ', '
      ', '
      ', - '
      使用魔药(与攻击模式相同)使用魔藥(與攻擊模式相同)Use Infusion(same as attack mode){{infusionCondition}}
      ', + '
      使用魔药(与默认攻击模式相同)使用魔藥(與默認攻擊模式相同)Use Infusion(same as default attack mode){{infusionCondition}}
      ', + + '
      次要攻击模式顺序(未配置的按照下面的顺序)次要攻擊模式順序(未配置的按照下面的順序)Attack Mode Order(Using order below as default if not configed):', + '

      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      ', '
      ', '
      ', @@ -2078,6 +2098,24 @@ gE('input[name="idleArenaValue"]').value = value; }; + gE('.attackStatusOrder', 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="attackStatusOrderName"]').value; + let { value } = gE('input[name="attackStatusOrderValue"]'); + 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="attackStatusOrderName"]').value = levels; + gE('input[name="attackStatusOrderValue"]').value = value; + }; + gE('.battleOrder', optionBox).onclick = function (e) { if (e.target.tagName !== 'INPUT' && e.target.type !== 'checkbox') { return; @@ -5105,14 +5143,25 @@ } function attack() { // 自动打怪 - // 如果 - // 1. 开启了自动以太水龙头 - // 2. 目标怪在魔力合流状态中 - // 3. 未获得以太水龙头*2 或 *1 - // 4. 满足条件 - // 使用物理普通攻击,跳过Offensive Magic - // 否则按照属性攻击模式释放Spell > Offensive Magic + let range = g('fightingStyle') === '1' ? 3 : 1; + const option = g('option'); + const monsters = g('battle').monsterStatus; + + let attackStatusOrder = option.attackStatusOrderValue?.split(',').map(x=>x*1) ?? []; + attackStatusOrder = attackStatusOrder.concat([0,1,2,3,4,5,6].filter(x=> !(attackStatusOrder.includes(x)))); + if (option.attackStatusSwitch) { + const conditions = option.attackStatusSwitchCondition ?? {}; + for (const status of attackStatusOrder) { + if (!option.attackStatusSwitch[status]) continue; + if (!checkCondition(conditions[status], monsters)) continue; + if (!onAttack(range, status)) continue; + break; + } + } + onAttack(range, g('attackStatus')); + } + function onAttack(range, attackStatus) { const updateAbility = { 4301: { //火 111: [3, 4, 4, 5, 5, 5, 5, 5], @@ -5143,10 +5192,16 @@ 4502: { 152: [5, 6, 7] }, 4503: { 153: [7, 8, 9, 10] }, } - let range = g('fightingStyle') === '1' ? 3 : 1; - // Spell > Offensive Magic + + // 如果 + // 1. 开启了自动以太水龙头 + // 2. 目标怪在魔力合流状态中 + // 3. 未获得以太水龙头*2 或 *1 + // 4. 满足条件 + // 使用物理普通攻击,跳过Offensive Magic + // 否则按照属性攻击模式释放Spell > Offensive Magic + const option = g('option'); - const attackStatus = g('attackStatus'); const monsters = g('battle').monsterStatus; let target = monsters[0]; const tryAttack = () => { From ae5fe7ac8818cc7ee9fa9e3ef6b918e0c71814cb Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 01:19:01 +0800 Subject: [PATCH 210/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 995618e2..b49ed4e0 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -5155,10 +5155,10 @@ if (!option.attackStatusSwitch[status]) continue; if (!checkCondition(conditions[status], monsters)) continue; if (!onAttack(range, status)) continue; - break; + return true; } } - onAttack(range, g('attackStatus')); + return onAttack(range, g('attackStatus')); } function onAttack(range, attackStatus) { From f8100189321a34ebd6c995fd520c75e3cbc7695e Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 21:35:21 +0800 Subject: [PATCH 211/216] =?UTF-8?q?2.90.121=20=E4=BF=AE=E6=AD=A3=E6=94=BB?= =?UTF-8?q?=E5=87=BB=E6=A8=A1=E5=BC=8F=E9=85=8D=E7=BD=AE=E8=AF=BB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index b49ed4e0..9e6ab5ef 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.120 +// @version 2.90.121 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -1377,13 +1377,13 @@ '
      ', '
      ', - '
      ', - '
      ', - '
      ', - '
      ', - '
      ', - '
      ', - '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', + '
      ', '
      ', '
      ', '
      ', @@ -5150,10 +5150,10 @@ let attackStatusOrder = option.attackStatusOrderValue?.split(',').map(x=>x*1) ?? []; attackStatusOrder = attackStatusOrder.concat([0,1,2,3,4,5,6].filter(x=> !(attackStatusOrder.includes(x)))); if (option.attackStatusSwitch) { - const conditions = option.attackStatusSwitchCondition ?? {}; for (const status of attackStatusOrder) { + const condition = option[`attackStatusSwitchCondition${status}`] ?? {}; if (!option.attackStatusSwitch[status]) continue; - if (!checkCondition(conditions[status], monsters)) continue; + if (!checkCondition(condition, monsters)) continue; if (!onAttack(range, status)) continue; return true; } From 5b88828f1468bdb03ea4dda75305d5ba88f1bede Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 22:43:59 +0800 Subject: [PATCH 212/216] =?UTF-8?q?2.90.122=20skillOTOS=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=8C=96=E5=AD=98=E5=82=A8=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0Spell=E7=9A=84=E6=AC=A1=E6=95=B0=EF=BC=9B=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3RPN=E5=AF=B9'.'=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 9e6ab5ef..0251ce67 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.121 +// @version 2.90.122 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -149,9 +149,9 @@ continue; } - if (/[a-zA-Z_]/.test(ch)) { + if (/[a-zA-Z_.]/.test(ch)) { let varName = ''; - while (i < expression.length && /[a-zA-Z0-9_]/.test(expression[i])) { + while (i < expression.length && /[a-zA-Z0-9_.]/.test(expression[i])) { varName += expression[i]; i++; } @@ -159,7 +159,7 @@ continue; } - throw new Error(`Unknown character: ${ch}`); + throw new Error(`Unknown character: ${ch} from ${expression}`); } return tokens; @@ -208,7 +208,7 @@ if (typeof token === 'number') { stack.push(token); } - else if (typeof token === 'string' && /[a-zA-Z_]/.test(token[0])) { + else if (typeof token === 'string' && /[a-zA-Z_.]/.test(token[0])) { const value = resolver ? resolver(token) : token; stack.push(value); } @@ -2756,7 +2756,6 @@ function checkCondition(parms, targets = undefined) { let i, j, k, target; - targets ??= [g('battle').monsterStatus[0]]; if (typeof parms === 'undefined') { return targets[0]; @@ -2775,6 +2774,7 @@ } result = result[key] } + result ??= 0; return isNaN(result * 1) ? result ?? str : (result * 1); } return str * 1; @@ -4170,6 +4170,16 @@ function newRound(isNew) { // New Round let battle = isNew ? {} : getValue('battle', true); + if (isNew) { + console.log('isNew') + setValue('skillOTOS', { + OFC: 0, + FRD: 0, + T3: 0, + T2: 0, + T1: 0, + }); + } if (!battle) { battle = JSON.parse(JSON.stringify(g('battle') ?? {})); battle.monsterStatus?.sort(objArrSort('order')); @@ -4297,14 +4307,6 @@ } battle.roundLeft = battle.roundAll - battle.roundNow; setValue('battle', battle); - - g('skillOTOS', { - OFC: 0, - FRD: 0, - T3: 0, - T2: 0, - T1: 0, - }); } function killBug() { // 在 HentaiVerse 发生导致 turn 损失的 bug 时发出警告并移除问题元素: https://ehwiki.org/wiki/HentaiVerse_Bugs_%26_Errors#Combat @@ -4954,10 +4956,12 @@ if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { continue; } - if (option.skillOTOS && option.skillOTOS[skill] && g('skillOTOS')[skill] >= 1) { + const skillOTOS = getValue('skillOTOS', true); + if (option.skillOTOS && option.skillOTOS[skill] && skillOTOS[skill] >= 1) { continue; } - g('skillOTOS')[skill]++; + skillOTOS[skill]++; + setValue('skillOTOS', skillOTOS); let target = checkCondition(option[`skill${skill}Condition`], g('battle').monsterStatus); if (!target) { continue; @@ -5146,7 +5150,6 @@ let range = g('fightingStyle') === '1' ? 3 : 1; const option = g('option'); const monsters = g('battle').monsterStatus; - let attackStatusOrder = option.attackStatusOrderValue?.split(',').map(x=>x*1) ?? []; attackStatusOrder = attackStatusOrder.concat([0,1,2,3,4,5,6].filter(x=> !(attackStatusOrder.includes(x)))); if (option.attackStatusSwitch) { @@ -5248,7 +5251,14 @@ break; } gE(skill)?.click(); - return tryAttack(); + if (tryAttack()) { + const skillOTOS = getValue('skillOTOS', true); + skillOTOS[skill] ??= 0; + skillOTOS[skill]++; + setValue('skillOTOS', skillOTOS); + return true; + } + return false; } function getHPFromMonsterDB(mdb, name, lv) { From b9392790744a2edbfa107070a2ab6941cedca94f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Thu, 25 Dec 2025 23:33:19 +0800 Subject: [PATCH 213/216] =?UTF-8?q?2.90.123=20=E5=A2=9E=E5=8A=A0=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E8=AF=BB=E5=8F=96=E4=B8=AD=E5=AF=B9=E5=90=AB=E4=B8=8B?= =?UTF-8?q?=E5=88=92=E7=BA=BF'=5F'=E7=9A=84=E9=94=AE=E5=80=BC=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 0251ce67..bf5410f6 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.122 +// @version 2.90.123 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -2761,7 +2761,7 @@ return targets[0]; } const returnValue = function (str) { - if (str.match(/^_/)) { + if (str.match(/^_/) && !str.match(/\./)) { const arr = str.split('_'); return func[arr[1]](...[...arr].splice(2)); } if (isNaN(str * 1)) { From 181c81124267a58f93dacafd52b80733664bf9e9 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 27 Dec 2025 14:18:38 +0800 Subject: [PATCH 214/216] =?UTF-8?q?2.90.124=20=E4=BF=AE=E6=AD=A3rpn?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=8F=8AskillOTOS=E9=9D=9E=E7=A9=BA=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index bf5410f6..f35909a8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.123 +// @version 2.90.124 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -149,9 +149,9 @@ continue; } - if (/[a-zA-Z_.]/.test(ch)) { + if (/[a-zA-Z_.'"]/.test(ch)) { let varName = ''; - while (i < expression.length && /[a-zA-Z0-9_.]/.test(expression[i])) { + while (i < expression.length && /[a-zA-Z0-9_.'"]/.test(expression[i])) { varName += expression[i]; i++; } @@ -170,7 +170,7 @@ const stack = []; for (const token of infixTokens) { - if (typeof token === 'number' || /[a-zA-Z_]/.test(token[0])) { + if (typeof token === 'number' || /[a-zA-Z_'"]/.test(token[0])) { output.push(token); } else if (token === '(') { @@ -203,13 +203,13 @@ evaluatePostfix(postfixTokens, resolver) { const stack = []; - for (const token of postfixTokens) { if (typeof token === 'number') { stack.push(token); } - else if (typeof token === 'string' && /[a-zA-Z_.]/.test(token[0])) { - const value = resolver ? resolver(token) : token; + else if (typeof token === 'string' && /[a-zA-Z_.'"]/.test(token[0])) { + let value = resolver ? resolver(token) : token; + if (typeof value === 'string' && value[0] !== "'" && value[0] != '"') value = `'${value}'`; stack.push(value); } else { @@ -2766,15 +2766,16 @@ return func[arr[1]](...[...arr].splice(2)); } if (isNaN(str * 1)) { const paramList = str.split('.'); - let result; + let result, isInData; for (let key of paramList) { if (!result) { result = (g('battle') ?? getValue('battle', true))[key] ?? g(key) ?? getValue(key) ?? g('option')?.[key]; + isInData = result; continue; } result = result[key] } - result ??= 0; + result ??= isInData ? 0 : result; return isNaN(result * 1) ? result ?? str : (result * 1); } return str * 1; @@ -2912,7 +2913,7 @@ case '<>': return '!='; } - }).replace(/'|"/g, '').replace('_1h', '_onehanded').replace('_2h', '_twohanded'); + }).replace('_1h', '_onehanded').replace('_2h', '_twohanded'); result = $RPN.evaluate(k, returnValue); if (!result) { parmResult = false; @@ -4171,14 +4172,7 @@ function newRound(isNew) { // New Round let battle = isNew ? {} : getValue('battle', true); if (isNew) { - console.log('isNew') - setValue('skillOTOS', { - OFC: 0, - FRD: 0, - T3: 0, - T2: 0, - T1: 0, - }); + setValue('skillOTOS', {}); } if (!battle) { battle = JSON.parse(JSON.stringify(g('battle') ?? {})); @@ -4956,7 +4950,8 @@ if (g('oc') < (id in skillOC ? skillOC[id] : 2)) { continue; } - const skillOTOS = getValue('skillOTOS', true); + const skillOTOS = getValue('skillOTOS', true) ?? {}; + skillOTOS[skill] ??= 0; if (option.skillOTOS && option.skillOTOS[skill] && skillOTOS[skill] >= 1) { continue; } @@ -5252,7 +5247,7 @@ } gE(skill)?.click(); if (tryAttack()) { - const skillOTOS = getValue('skillOTOS', true); + const skillOTOS = getValue('skillOTOS', true) ?? {}; skillOTOS[skill] ??= 0; skillOTOS[skill]++; setValue('skillOTOS', skillOTOS); From 12f3532ef11f4df33e15f173d54cc47f5ed7163f Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sat, 27 Dec 2025 14:37:20 +0800 Subject: [PATCH 215/216] Update hvAutoAttack.user.js --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index f35909a8..6e4f933f 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -75,8 +75,8 @@ operators: { '>=': { precedence : 0, func: (a, b) => a >= b ? 1 : 0 }, '<=': { precedence : 0, func: (a, b) => a <= b ? 1 : 0 }, - '==': { precedence : 0, func: (a, b) => a == b ? 1 : 0 }, - '!=': { precedence : 0, func: (a, b) => a != b ? 1 : 0 }, + '==': { precedence : 0, func: (a, b) => a === b ? 1 : 0 }, + '!=': { precedence : 0, func: (a, b) => a !== b ? 1 : 0 }, '&&': { precedence : -1, func: (a, b) => a && b ? 1 : 0 }, '||': { precedence : -1, func: (a, b) => a || b ? 1 : 0 }, '**': { precedence:3, func: (a,b) => Math.pow(a, b)}, From 18a496e805b18a58103c13cbb10a8948ca17cc09 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Sun, 28 Dec 2025 16:20:40 +0800 Subject: [PATCH 216/216] 2.90.125 --- HentaiVerse/hvAutoAttack/hvAutoAttack.user.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js index 6e4f933f..c37c94b8 100644 --- a/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js +++ b/HentaiVerse/hvAutoAttack/hvAutoAttack.user.js @@ -6,7 +6,7 @@ // @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.124 +// @version 2.90.125 // @author dodying // @namespace https://github.com/dodying/ // @supportURL https://github.com/dodying/UserJs/issues @@ -3240,8 +3240,10 @@ if (stamina.lastCost) { last += Math.floor(stamina.time / _1h) - Math.floor(lastTime / _1h); const delta = last - stamina.current; - stamina.ratio = Math.max(1, delta / stamina.lastCost); - stamina.lastCost = undefined; + if (delta !== 0) { + stamina.ratio = Math.max(1, delta / stamina.lastCost); + stamina.lastCost = undefined; + } } setValue('stamina', stamina); console.log('stamina', stamina, last, stamina.current, lastCost, stamina.ratio); @@ -4298,6 +4300,7 @@ if (roundPrev !== battle.roundNow) { battle.turn = 0; + setValue('skillOTOS', {}); } battle.roundLeft = battle.roundAll - battle.roundNow; setValue('battle', battle);