// ==UserScript== // @name CBG Helper // @namespace https://yys.zhebu.work/ // @version 0.0.5 // @description A helper tool for Onmyoji player to look for good account. // @author CJ // @match https://yys.cbg.163.com/* // @grant none // @run-at document-start // @downloadURL none // ==/UserScript== (function() { 'use strict'; var acct_info = {}; var FRAC_N = 5 var url_match = "api/get_equip_detail"; var _open = XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, URL) { var _onreadystatechange = this.onreadystatechange, _this = this; _this.onreadystatechange = function () { // catch only completed 'api/search/universal' requests if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf(url_match)) { try { ////////////////////////////////////// // THIS IS ACTIONS FOR YOUR REQUEST // // EXAMPLE: // ////////////////////////////////////// var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]} data = floatify(data) // rewrite responseText Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)}); Object.defineProperty(_this, 'response', {value: JSON.stringify(data)}); /////////////// END ////////////////// } catch (e) {} console.log('Caught! :)', method, URL/*, _this.responseText*/); } // call original callback if (_onreadystatechange) _onreadystatechange.apply(this, arguments); }; // detect any onreadystatechange changing Object.defineProperty(this, "onreadystatechange", { get: function () { return _onreadystatechange; }, set: function (value) { _onreadystatechange = value; } }); return _open.apply(_this, arguments); }; function addDownloadBtn() { if(document.getElementById('cbghelper_download')) { return; } var b = document.createElement('a'); b.innerText = "(💾保存为JSON)"; b.onclick = function () { console.log("To save data!"); saveToJsonHelper(); } b.id = "cbghelper_download" b.style.cursor = "pointer"; var yuhun_list = document.getElementsByClassName('yuhun-list')[0]; yuhun_list.parentNode.childNodes[1].append(b) } var checkExist = setInterval(function () { if (!document.getElementById('cbghelper_download')) { var ready = setInterval(function () { if (document.getElementsByClassName('yuhun-list').length) { console.log("Exists!"); clearInterval(ready); addDownloadBtn() } }, 100) } }, 100); const floatify = function (data) { let equip = data['equip']; let acct_detail = JSON.parse(equip['equip_desc']); let mitama_list = acct_detail['inventory']; let hero_list = acct_detail['heroes']; try { var message = { name: equip.seller_name, roleid: equip.seller_roleid, ordersn: equip.game_ordersn, mitama_list }; 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; 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) { attrs[propName].add_val = getPropValue(equips, mitama_list, propName).toFixed(FRAC_N); } if (propName === '暴击' && parseFloat(attrs[propName].add_val) > 0) { let suit_cp = ["针女","三味","网切","伤魂鸟","破势","镇墓兽","青女房"]; 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 += 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 saveToJsonHelper() { saveToJson(acct_info.latest.mitama_list); } })();