// ==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
// ==/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);
}
})();