您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
修复 CBG Helper 无法使用的问题,原项目为 https://greasyfork.org/zh-CN/scripts/406264-cbg-helper, 有问题找 灵亦rEd (https://space.bilibili.com/103021226)
// ==UserScript== // @name CBG Helper 修复版 // @namespace https://yys.zhebu.work/ // @version 0.1.9 // @description 修复 CBG Helper 无法使用的问题,原项目为 https://greasyfork.org/zh-CN/scripts/406264-cbg-helper, 有问题找 灵亦rEd (https://space.bilibili.com/103021226) // @author Jie Chu (原作者) & 灵亦rEd(修复和后续更新) // @match https://yys.cbg.163.com/* // @grant none // @run-at document-start // @require https://update.greasyfork.org/scripts/465643/1421695/ajaxHookerLatest.js // ==/UserScript== ;(function () { 'use strict' let panel_class_name = 'content-overview' let acct_info = { ready: false } window.ling3 = acct_info let FRAC_N = 5 let url_get_equip_detail = '/cgi/api/get_equip_detail' let url_get_equip_desc = '/cgi/api/get_equip_desc' // added by LingErEd let suit_imp = ['散件', '招财猫', '火灵', '蚌精', '共潜', '遗念火'] // 重要套装,可自行添加 let suit_by_props = { 暴击伤害: ['无刀取'], 暴击: [ '针女', '三味', '网切', '伤魂鸟', '破势', '镇墓兽', '青女房', '海月火玉' ], 攻击加成: [ '蝠翼', '轮入道', '狰', '鸣屋', '心眼', '阴摩罗', '狂骨', '兵主部', '贝吹坊' ], 防御加成: [ '珍珠', '魅妖', '雪幽魂', '招财猫', '反枕', '日女巳时', '木魅', '出世螺', '奉海图' ], 生命加成: [ '地藏像', '涅槃之火', '被服', '镜姬', '钟灵', '薙魂', '树妖', '涂佛', '恶楼' ], 效果抵抗: ['骰子鬼', '返魂香', '魍魉之匣', '幽谷响', '共潜'], 效果命中: ['蚌精', '火灵', '飞缘魔', '遗念火'], 首领御魂: [ '土蜘蛛', '胧车', '荒骷髅', '地震鲶', '蜃气楼', '鬼灵歌伎', '夜荒魂' ] } // eslint-disable-next-line no-undef ajaxHooker.hook(request => { let originalResponse = request.response if (request.url.startsWith(url_get_equip_detail)) { console.log('ajaxHooker url_get_equip_detail') request.response = res => { if (res.status == 200) { // console.log(res.responseText); const data = JSON.parse(res.responseText) window.ling2 = data floatify(data, 'url_get_equip_detail') } if (originalResponse) try { originalResponse.apply(this, [res]) } catch (error) {} } } if (request.url.startsWith(url_get_equip_desc)) { console.log('ajaxHooker url_get_equip_desc') request.response = res => { if (res.status == 200) { // const data = JSON.parse(res.responseText) window.ling1 = JSON.parse(res.json.equip_desc) floatify( { equip: res.json }, 'url_get_equip_desc' ) } if (originalResponse) try { originalResponse.apply(this, [res]) } catch (error) {} } } }) function nowrapText (textLabel) { return `<span class="cbghelper_nowrap">${textLabel}</span>` } function addExtendedHighlight () { if ( document.getElementById('cbghelper_exthighlight') || !acct_info.hasOwnProperty('summary') ) { return } let { fastest, heads, feet, hero_info } = acct_info.summary let itms = [] let build_item = function (label, id) { let li = document.createElement('li') li.innerText = label return li } //collection of heros let total = hero_info['ssr']['all'] + hero_info['sp']['all'] let got_total = hero_info['ssr']['got'] + hero_info['sp']['got'] if (total === got_total) { itms.push(build_item('SSR/SP全收集')) } else if (hero_info['ssr']['all'] === hero_info['ssr']['got']) { itms.push(build_item('SSR全收集')) } if (hero_info['x']['all'] === hero_info['x']['got']) { itms.push(build_item('联动全收集')) } // edited by 灵亦rEd (https://space.bilibili.com/103021226) // 几头几尾和散件一速以及招财一速现在默认有显示了 //number of heads and feet // if (heads.length > 0 || feet.length > 0) { // let x = heads.length > 0 ? heads.length : '无'; // let y = feet.length > 0 ? feet.length : '无'; // let label = `${x}头${y}脚`; // itms.push(build_item(label)) // } // //fastest speed // let fastest_spd_label = `最快一速${[1, 2, 3, 4, 5, 6].reduce((total, p) => total + fastest[p]['散件'], 0).toFixed(2)}`; // let fastest_spd = build_item(fastest_spd_label) // fastest_spd.id = 'cbghelper_exthighlight'; // itms.push(fastest_spd); // //fastest zhaocai speed // let zc_spd_val = [1, 2, 3, 4, 5, 6].reduce((total, p) => total + fastest[p]['招财猫'], 0); // let spd_inc = [1, 2, 3, 4, 5, 6].map(p => fastest[p]['散件'] - fastest[p]['招财猫'], 0); // spd_inc.sort((a, b) => b - a); // zc_spd_val += spd_inc[0] + spd_inc[1]; // let zc_spd_label = `招财一速${zc_spd_val.toFixed(2)}`; // itms.push(build_item(zc_spd_label)); // added by 灵亦rEd (https://space.bilibili.com/103021226) // 显示黑蛋 let blackEggCount = acct_info?.acctHighlight?.damo_count_dict?.[2]?.[411] || 0 // el let blackEggCountLabel = `御行达摩${blackEggCount}个` let blackEggCountEl = build_item(blackEggCountLabel) blackEggCountEl.id = 'cbghelper_exthighlight' itms.push(blackEggCountEl) // 显示魂玉 let hunyu = acct_info?.acctHighlight?.hunyu || 0 // el let hunyuLabel = `魂玉${hunyu}个` itms.push(build_item(hunyuLabel)) // 太鼓 let taigu = acct_info?.acctHighlight?.lbscards?.[200036]?.num || 0 // el let taiguL = `太鼓${taigu}个` itms.push(build_item(taiguL)) // 庭院皮肤 let yardSkin = acct_info?.acctHighlight?.skin?.yard?.length || 0 itms.push(build_item(`庭院皮肤${yardSkin}个`)) // 召唤屋皮肤 let gambleSkin = acct_info?.acctHighlight?.skin?.gamble?.length || 0 itms.push(build_item(`召唤屋皮肤${gambleSkin}个`)) // 幕间皮肤 let shishenluSkin = acct_info?.acctHighlight?.skin?.shishenlu?.length || 0 itms.push(build_item(`幕间皮肤${shishenluSkin}个`)) // 战斗 let battleSkin = acct_info?.acctHighlight?.skin?.battle?.length || 0 itms.push(build_item(`战斗皮肤${battleSkin}个`)) // 在 skin 项目中找到符合名字的 items // 用于找到臻藏皮肤的个数 function findItemsWithKeywordInSkin (dataArray, keyword) { if (!Array.isArray(dataArray)) { return [] } return dataArray.filter(item => { // 确保子数组存在第二个元素,并且是字符串类型 return ( item[1] && typeof item[1] === 'string' && item[1].includes(keyword) ) }) } try { // 臻藏皮肤的个数 let ssSkins = acct_info?.acctHighlight?.skin?.ss let zcSkins = findItemsWithKeywordInSkin(ssSkins, '臻藏') itms.push(build_item(`臻藏皮肤${zcSkins.length}个`)) } catch (error) { console.log('臻藏皮肤获取失败') } try { // 藏金台阁 let battleSkins = acct_info?.acctHighlight?.skin?.battle let zangjin = findItemsWithKeywordInSkin(battleSkins, '藏金台阁') if (zangjin && zangjin.length) itms.push(build_item(`藏金台阁`)) } catch (error) { console.log('藏金台阁皮肤获取失败') } // 八岐大蛇鳞片 let dashe = acct_info?.acctHighlight?.currency_900216 || 0 // el let dasheLabel = `八岐大蛇鳞片${dashe}个` itms.push(build_item(dasheLabel)) // 大蛇的逆鳞 let jindashe = acct_info?.acctHighlight?.currency_900217 || 0 // el let jindasheL = `大蛇的逆鳞${jindashe}个` itms.push(build_item(jindasheL)) let highlight = document.getElementsByClassName('highlight')[0] let newHighlight = document.createElement('ul') // newHighlight 添加 class name highlight newHighlight.className = 'highlight new-highlight' for (let li of itms) { newHighlight.appendChild(li) } // 将 newHighlight 插入到 highlight 后面 highlight.parentNode.insertBefore(newHighlight, highlight.nextSibling) } function summaryPage () { let wrapper = document.createElement('div') wrapper.classList.add('module') if (!acct_info.hasOwnProperty('summary')) { wrapper.appendChild( document.createTextNode('数据加载出错,请尝试刷新页面') ) return wrapper } let decimal = 2 let { fastest, heads, feet, fullspd_cnt } = acct_info.summary let fullspd_suit = Object.fromEntries(suit_imp.map(name => [name, 0])) fastest = JSON.parse(JSON.stringify(fastest)) // make a deep copy let suit_stats = {} for (let p of [1, 2, 3, 4, 5, 6]) { for (let name in fullspd_cnt[p]) { if (fullspd_suit[name] === 0) { continue } if (name in suit_stats) { suit_stats[name].push(p) } else { suit_stats[name] = [p] } } } for (let name in suit_stats) { if (suit_stats[name].length >= 4) { if (name in fullspd_suit) { continue } else { fullspd_suit[name] = 0 } } } let fast_suit_speed = function (name) { let suit_fastest = Object.fromEntries( [1, 2, 3, 4, 5, 6].map(p => [ p, name in fastest[p] ? fastest[p][name] : 0 ]) ) let suit_spd_val = [1, 2, 3, 4, 5, 6].reduce( (total, p) => total + suit_fastest[p], 0 ) let spd_inc = [1, 2, 3, 4, 5, 6].map( p => fastest[p]['散件'] - suit_fastest[p] ) spd_inc.sort((a, b) => b - a) suit_spd_val += spd_inc[0] + spd_inc[1] return suit_spd_val } Object.keys(fullspd_suit).forEach(name => { fullspd_suit[name] = fast_suit_speed(name) }) let sortByValue = function (a, b) { return b.value - a.value } let headStr = heads.length > 0 ? heads .sort(sortByValue) .map(itm => `<span class="data-value">${itm.name}: ${itm.value.toFixed( decimal )}</span>`.trim() ) .join(', ') : '无' let feetStr = feet.length > 0 ? feet .sort(sortByValue) .map(itm => `<span class="data-value">${itm.name}: ${itm.value.toFixed( decimal )}</span>`.trim() ) .join(', ') : '无' let td_val = function (pos, name) { let fullspd = fullspd_cnt[pos][name] > 0 let spd = name in fastest[pos] ? fastest[pos][name].toFixed(decimal) : 0 let res = `<span${fullspd ? '' : ' class=disabled'}>${spd}</span> ` if (fullspd) { res += nowrapText(`(${fullspd_cnt[pos][name]})`) } return res } Object.keys(fastest[2]).forEach( k => (fastest[2][k] = fastest[2][k] - 57 > 0 ? fastest[2][k] - 57 : 0) ) let speed_summary = function (name) { return `<tr> <td>${name}</td> ${[1, 2, 3, 4, 5, 6, 7].map( i => `<td>${td_val(i, name)}</td>` )} </tr>` } let fastest_tbl = `<table width="100%"> <tr> <th>位置</th> ${[1, 2, 3, 4, 5, 6].map( i => `<th>${i}</th>` )} <th>4${nowrapText('(命中)')}</th> </tr> ${Object.keys(fullspd_suit) .map(name => speed_summary(name)) .join(' ')} </table>` let suit_table = `<table width="100%"> <tr> <th>御魂名称</th> <th>套装一速</th></tr> ${Object.keys(fullspd_suit) .map( name => `<tr> <th>${name}</th> <td>${fullspd_suit[name].toFixed( 5 )}</td></tr>\n` ) .join('')} </table>` let title = document.createElement('div') title.classList.add('title') title.innerText = '御魂亮点' let spd = document.createElement('section') spd.innerHTML = `<div><span class="data-name">头:</span> ${headStr} </div> <div><span class="data-name">脚:</span> ${feetStr} </div>` let title2 = document.createElement('div') title2.innerText = '套装一速(非独立)' title2.classList.add('title') let suit = document.createElement('section') suit.innerHTML = suit_table let title3 = document.createElement('div') title3.innerText = '各位置一速(满速个数)' title3.classList.add('title') let fastest_sec = document.createElement('section') fastest_sec.innerHTML = fastest_tbl if (fastest_sec.firstChild.nodeType === Node.TEXT_NODE) { fastest_sec.firstChild.textContent = '' } wrapper.appendChild(title) wrapper.appendChild(spd) wrapper.appendChild(title2) wrapper.appendChild(suit) wrapper.appendChild(title3) wrapper.appendChild(fastest_sec) return wrapper } function addHighlightView () { if (document.getElementById('cbghelper_highlight')) { return } let div = document.createElement('div') div.id = 'cbghelper_highlight' div.class = 'module' div.appendChild(summaryPage()) let wrapper = document.getElementsByClassName(panel_class_name)[0] wrapper.appendChild(div) } function addDownloadBtn () { if (document.getElementById('cbghelper_download')) { return } let b = document.createElement('a') b.innerText = '(💾保存为JSON)' b.onclick = function () { console.log('To save data!') saveToJsonHelper() } b.id = 'cbghelper_download' b.style.cursor = 'pointer' let yuhun_list = document.getElementsByClassName('content-top-left')[0] yuhun_list.getElementsByTagName('h3')[1].appendChild(b) } function addDownloadBtnWrapper () { if (document.getElementsByClassName('yuhun-list').length) { addDownloadBtn() } } function addExtHighlightWrapper () { if (document.getElementsByClassName('highlight').length) { addExtendedHighlight() } } function addHighlightViewWrapper () { if ( document.getElementsByClassName(panel_class_name).length && acct_info.ready ) { addHighlightView() } } function init () { let checkfn_list = { cbghelper_download: addDownloadBtnWrapper, cbghelper_exthighlight: addExtHighlightWrapper, cbghelper_highlight: addHighlightViewWrapper } let handlers = {} let checkExist = setInterval(function () { if (!document.URL.startsWith('https://yys.cbg.163.com/cgi/mweb/equip')) { return } for (let eid of Object.keys(checkfn_list)) { if (document.getElementById(eid) && eid in handlers) { clearInterval(handlers[eid]) delete handlers[eid] } else if (document.getElementById(eid) || eid in handlers) { continue } else { handlers[eid] = setInterval(checkfn_list[eid], 200) } } }, 100) } init() const floatify = function (data, type) { console.log('floatify', data) let equip = data['equip'] // 如果没有 equip_desc 则返回 if (!equip.hasOwnProperty('equip_desc')) { console.log('No equip_desc, from', type) return data } let acct_detail = JSON.parse(equip['equip_desc']) let mitama_list = acct_detail['inventory'] let hero_list = acct_detail['heroes'] let hero_info = acct_detail['hero_history'] try { var message = { name: equip.seller_name, roleid: equip.seller_roleid, ordersn: equip.game_ordersn, mitama_list } var event = new CustomEvent('SaveLastAccount', { detail: message }) window.dispatchEvent(event) acct_info.latest = message } catch (error) {} Object.entries(mitama_list).forEach(([key, value]) => { mitama_list[key] = floatify_mitama(value) }) Object.entries(hero_list).forEach(([key, value]) => { hero_list[key] = floatify_hero(value, mitama_list) }) acct_detail['inventory'] = mitama_list equip['equip_desc'] = JSON.stringify(acct_detail) data['equip'] = equip acctHighlight(mitama_list, hero_info, acct_detail) return data } function getPropValue (mitama_set, mitama_list, propName) { let res = 0 for (let mitama_id of mitama_set) { var { attrs, single_attr = [] } = mitama_list[mitama_id] for (let [p, v] of attrs) { if (p === propName) { res += parseFloat(v) } } if (single_attr.length > 0 && single_attr[0] === propName) { res += parseFloat(single_attr[1]) } } return res } function floatify_hero (hero_data, mitama_list) { var { attrs, equips } = hero_data Object.keys(attrs).forEach(propName => { if (propName === '速度' && parseFloat(attrs[propName].add_val) > 0) { if (hero_data.heroId === 255 && hero_data.awake === 1) { //觉醒阎魔+10速度 attrs[propName].add_val = 10.0 } else { attrs[propName].add_val = 0.0 } attrs[propName].add_val += getPropValue(equips, mitama_list, propName) attrs[propName].add_val = attrs[propName].add_val.toFixed(FRAC_N) } if (propName === '暴击' && parseFloat(attrs[propName].add_val) > 0) { let suit_cp = suit_by_props['暴击'] attrs[propName].add_val = getPropValue(equips, mitama_list, propName) let suit_names = equips.map(x => mitama_list[x].name) let suit_count = {} for (let n of suit_names) { if (n in suit_count) { suit_count[n] += 1 } else { suit_count[n] = 1 } } Object.keys(suit_count).forEach(n => { if (suit_count[n] >= 2 && suit_cp.includes(n)) { attrs[propName].add_val += suit_count[n] === 6 ? 30 : 15 } }) attrs[propName].add_val = attrs[propName].add_val.toFixed(2) + '%' } }) return hero_data } function floatify_mitama (mitama) { var { rattr, attrs } = mitama mitama['attrs'] = [attrs[0], ...calAttrs(rattr)] return mitama } function calAttrs (rattrs, format = true) { var enAttrNames = [ 'attackAdditionRate', 'attackAdditionVal', 'critPowerAdditionVal', 'critRateAdditionVal', 'debuffEnhance', 'debuffResist', 'defenseAdditionRate', 'defenseAdditionVal', 'maxHpAdditionRate', 'maxHpAdditionVal', 'speedAdditionVal' ] var cnAttrNames = [ '攻击加成', '攻击', '暴击伤害', '暴击', '效果命中', '效果抵抗', '防御加成', '防御', '生命加成', '生命', '速度' ] var basePropValue = { 攻击加成: 3, 攻击: 27, 暴击伤害: 4, 暴击: 3, 效果抵抗: 4, 效果命中: 4, 防御加成: 3, 防御: 5, 生命加成: 3, 生命: 114, 速度: 3 } var percentProp = { 攻击加成: true, 攻击: false, 暴击伤害: true, 暴击: true, 效果抵抗: true, 效果命中: true, 防御加成: true, 防御: false, 生命加成: true, 生命: false, 速度: false } var e2cNameMap = Object.assign( {}, ...enAttrNames.map((n, index) => ({ [n]: cnAttrNames[index] })) ) var res = Object() for (let rattr of rattrs) { var [prop, v] = rattr prop = e2cNameMap[prop] if (prop in res) { res[prop] += v } else { res[prop] = v } } return Object.keys(res) .sort() .map(p => { var v = res[p] * basePropValue[p] if (format) { v = v.toFixed(FRAC_N) if (percentProp[p]) { v += '%' } } return [p, v] }) } function soulToJson (soulItem) { const { attrs, level, qua, rattr, uuid, name, pos, single_attr = [] } = soulItem var born = parseInt(uuid.substring(0, 8), 16) let soulDict = { 固有属性: single_attr.length ? single_attr[0] : null, 生成时间: born, 御魂等级: level, 御魂星级: qua, 御魂ID: uuid, 御魂类型: name, 位置: pos } let PROPNAMES = [ '攻击', '攻击加成', '防御', '防御加成', '暴击', '暴击伤害', '生命', '生命加成', '效果命中', '效果抵抗', '速度' ] PROPNAMES.map(function (e, i) { soulDict[e] = 0 }) let percent = [ '攻击加成', '防御加成', '暴击', '暴击伤害', '生命加成', '效果命中', '效果抵抗' ] for (let [p, v] of [attrs[0], ...calAttrs(rattr, false)]) { v = parseFloat(v) if (percent.includes(p)) { v = v / 100 } soulDict[p] += v } if (single_attr.length) { const [p, v] = single_attr soulDict[p] += parseFloat(v) / 100 } return soulDict } function saveToJson (soulLists) { var fileContent = 'data:text/json;charset=utf-8,' let soulListJson = Object.values(soulLists).map(soulToJson) soulListJson.unshift('yuhun_ocr2.0') fileContent += JSON.stringify(soulListJson) var encodedUri = encodeURI(fileContent) var link = document.createElement('a') link.setAttribute('href', encodedUri) link.setAttribute('download', 'yuhun.json') link.innerHTML = 'Click Here to download your data' document.body.appendChild(link) // Required for FF link.click() link.parentNode.removeChild(link) } function acctHighlight (mitama_list, hero_info, acctHighlight) { let fastest = {} let fullspd_cnt = {} let heads = [] let feet = [] let all_pos = [1, 2, 3, 4, 5, 6] for (let p of [1, 2, 3, 4, 5, 6, 7]) { //7 for 命中@4 fastest[p] = {} fullspd_cnt[p] = {} for (let name of suit_imp) { fastest[p][name] = 0 fullspd_cnt[p][name] = 0 } } Object.entries(mitama_list).forEach(([key, m]) => { let { attrs, pos, name, qua, rattr } = m let spd = 0, spdpt = 0 for (let [p, v] of attrs) { if (p === '速度') { spd += parseFloat(v) } } for (let rattr_entry of rattr) { var [prop, v] = rattr_entry if (prop === 'speedAdditionVal') { spdpt += 1 } } if (spdpt < 1 || (pos === 2 && spd < 57)) { return } if (spdpt === 6 && (pos !== 2 || spd > 70)) { fullspd_cnt[pos]['散件'] += 1 if (name in fullspd_cnt[pos]) { fullspd_cnt[pos][name] += 1 } else { fullspd_cnt[pos][name] = 1 } if (pos === 2) { heads.push({ pos, name, value: spd - 57 }) } else if (pos === 4 && attrs[0][0] === '效果命中') { fullspd_cnt[7]['散件'] += 1 if (name in fullspd_cnt[pos]) { fullspd_cnt[7][name] += 1 } else { fullspd_cnt[7][name] = 1 } feet.push({ pos, name, value: spd }) } } if (name in fastest[pos]) { fastest[pos][name] = fastest[pos][name] > spd ? fastest[pos][name] : spd } else { fastest[pos][name] = spd } fastest[pos]['散件'] = fastest[pos]['散件'] > spd ? fastest[pos]['散件'] : spd if (pos === 4 && attrs[0][0] === '效果命中') { pos = 7 if (name in fastest[pos]) { fastest[pos][name] = fastest[pos][name] > spd ? fastest[pos][name] : spd } else { fastest[pos][name] = spd } fastest[pos]['散件'] = fastest[pos]['散件'] > spd ? fastest[pos]['散件'] : spd } }) acct_info.summary = { heads, feet, fastest, fullspd_cnt, hero_info } acct_info.ready = true acct_info.acctHighlight = acctHighlight } function saveToJsonHelper () { // var event = new CustomEvent("LoadLastAccount", {}); // window.dispatchEvent(event); // console.log("Account data requested!"); saveToJson(acct_info.latest.mitama_list) } // function needed that is not included from chrome extension var cssRules = ` .cbghelper_nowrap { white-space: nowrap; } .new-highlight { margin-top: 0 !important; } ` function injectCSS () { var style = document.createElement('style') style.innerHTML = cssRules document.getElementsByTagName('head')[0].appendChild(style) } injectCSS() })()