更新鹮穿之喙的数据

This commit is contained in:
Kokomi 2023-06-02 05:10:22 +08:00
parent c06233e86a
commit d74098b6df
23 changed files with 77 additions and 4056 deletions

View File

@ -24,7 +24,7 @@ app.reg({
desc: '【#统计】 #深渊出场率 #深渊12层出场率'
},
abyssTeam: {
rule: /#深渊(组队|配队)/,
rule: /^#深渊(组队|配队)/,
fn: AbyssTeam,
describe: '【#角色】 #深渊组队'
},

View File

@ -30,6 +30,7 @@ export const idsMap = {
303155515: '离簇不归',
310247243: '神乐之真意',
313300315: '原木刀',
316078811: '鹮穿之喙',
334242634: '申鹤',
339931171: '乘胜追击',
342097547: '辰砂之纺锤',
@ -67,6 +68,7 @@ export const idsMap = {
646032090: '鹿野院平藏',
646100491: '千岩诀·同心',
650049651: '风花之颂',
650438131: '秘智之眸的青睐',
655825874: '云堇',
656120259: '神射手之誓',
680510411: '白影剑',
@ -144,6 +146,7 @@ export const idsMap = {
1437658243: '螭骨剑',
1438974835: '逆飞的流星',
1455107995: '四风原典',
1456643042: '绮良良',
1468367538: '迪奥娜',
1470442731: '风信之锋',
1479961579: '铁影阔剑',

View File

@ -8,8 +8,8 @@ export const usefulAttr = {
布洛妮娅: { hp: 0, atk: 75, def: 0, speed: 100, cpct: 75, cdmg: 100, stance: 0, heal: 0, recharge: 100, effPct: 0, effDef: 0, dmg: 100 },
杰帕德: { hp: 50, atk: 0, def: 100, speed: 100, cpct: 0, cdmg: 0, stance: 0, heal: 0, recharge: 100, effPct: 50, effDef: 50, dmg: 0 },
姬子: { hp: 0, atk: 75, def: 0, speed: 75, cpct: 100, cdmg: 100, stance: 50, heal: 0, recharge: 50, effPct: 0, effDef: 0, dmg: 100 },
瓦尔特: { hp: 0, atk: 75, def: 0, speed: 100, cpct: 100, cdmg: 100, stance: 0, heal: 0, recharge: 50, effPct: 0, effDef: 0, dmg: 100 },
彦卿: { hp: 0, atk: 75, def: 0, speed: 75, cpct: 100, cdmg: 100, stance: 0, heal: 0, recharge: 75, effPct: 100, effDef: 0, dmg: 100 },
瓦尔特: { hp: 0, atk: 75, def: 0, speed: 75, cpct: 100, cdmg: 100, stance: 0, heal: 0, recharge: 50, effPct: 100, effDef: 0, dmg: 100 },
彦卿: { hp: 0, atk: 75, def: 0, speed: 75, cpct: 100, cdmg: 100, stance: 0, heal: 0, recharge: 75, effPct: 0, effDef: 0, dmg: 100 },
白露: { hp: 100, atk: 0, def: 50, speed: 75, cpct: 0, cdmg: 0, stance: 0, heal: 100, recharge: 100, effPct: 0, effDef: 50, dmg: 0 },
克拉拉: { hp: 0, atk: 75, def: 0, speed: 75, cpct: 100, cdmg: 100, stance: 0, heal: 0, recharge: 50, effPct: 0, effDef: 0, dmg: 100 },
三月七: { hp: 50, atk: 0, def: 100, speed: 100, cpct: 0, cdmg: 0, stance: 0, heal: 0, recharge: 100, effPct: 50, effDef: 50, dmg: 0 },

View File

@ -218,6 +218,13 @@ export default function (step, staticStep) {
dmg: ({ refine }) => step(12)[refine],
a2Plus: ({ attr, calc, refine }) => calc(attr.mastery) * step(160)[refine] / 100
}
},
鹮穿之喙: {
title: '重击命中敌人2层提高元素精通[mastery]点',
data: {
mastery: step(80)
}
}
}

View File

@ -163,5 +163,10 @@
"id": 15511,
"name": "猎人之径",
"star": 5
},
"鹮穿之喙": {
"id": 15419,
"name": "鹮穿之喙",
"star": 4
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,59 @@
{
"id": 15419,
"name": "鹮穿之喙",
"affixTitle": "秘智之眸的青睐",
"star": 4,
"desc": "以故事中的描述铸就的黄金之弓。若将它作为寻常武具使用,也可视为让纸上故事的一角在纸外的世界得到显现了吧。",
"attr": {
"atk": {
"1": 43.73,
"20": 118.57,
"40": 225.99,
"50": 293.36,
"60": 360.9,
"70": 428.69,
"80": 496.72,
"90": 564.78,
"20+": 144.47,
"40+": 251.99,
"50+": 319.26,
"60+": 386.8,
"70+": 454.69,
"80+": 522.62
},
"bonusKey": "atkPct",
"bonusData": {
"1": 6,
"20": 10.6,
"40": 15.45,
"50": 17.87,
"60": 20.3,
"70": 22.72,
"80": 25.14,
"90": 27.56,
"20+": 10.6,
"40+": 15.45,
"50+": 17.87,
"60+": 20.3,
"70+": 22.72,
"80+": 25.14
}
},
"materials": {
"weapon": "谧林涓露的金符",
"monster": "漫游者的盛放之花",
"normal": "织金红绸"
},
"affixData": {
"text": "重击命中敌人后的6秒内角色元素精通提升$[0]点。该效果至多叠加2层每0.5秒至多触发一次。",
"datas": {
"0": [
"40",
"50",
"60",
"70",
"80"
]
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,111 +0,0 @@
import fs from 'fs'
import lodash from 'lodash'
import fetch from 'node-fetch'
import ImgDownloader from './sprider/ImgDown.js'
import CharData from './sprider/CharDataAmber.js'
import { Data } from '#miao'
const _path = process.cwd()
const _root = _path + '/plugins/miao-plugin/'
const _mRoot = _root + 'resources/meta/material/'
let mData = {}
if (fs.existsSync(_mRoot + 'data.json')) {
mData = JSON.parse(fs.readFileSync(_mRoot + 'data.json', 'utf8'))
}
const tElems = ['anemo', 'geo', 'electro', 'dendro']
let getCharData = async function (id, key, name = '', _id = id) {
let url = `https://api.ambr.top/v2/chs/avatar/100000${id}`
console.log('req: ' + url)
let req = await fetch(url)
let reqData = await req.json()
reqData = reqData.data
console.log(reqData.id)
let data = CharData.getBasic(reqData)
name = name || data.name
let imgs = new ImgDownloader(name)
let attr = CharData.getDetailAttr(reqData)
data.baseAttr = {}
data.growAttr = {}
let talentId
let talentKey
let detail = CharData.getDetail(reqData)
let { talent, cons } = detail
data.talentKey = talentKey || lodash.invert(lodash.mapValues(talent, (t) => t.id))
data.talentId = talentId
data.talentCons = CharData.getConsTalent(talent, cons)
return {
data,
details: [detail],
imgs
}
}
function checkName (name) {
let charPath = `resources/meta/character/${name}/`
Data.createDir(charPath, 'miao')
if (name === '旅行者') {
for (let idx in tElems) {
Data.createDir(`${charPath}${tElems[idx]}/icons`, 'miao')
}
} else {
Data.createDir(`${charPath}/icons`, 'miao')
}
Data.createDir(`${charPath}/imgs`, 'miao')
let data = Data.readJSON(`${charPath}/data.json`, 'miao')
return data.ver * 1 > 1
}
async function saveCharData (id) {
let { data, details, imgs } = await getCharData(id)
let name = data.name
if (!name) {
console.log(`角色名不存在${id}:${name}`)
return
}
Data.createDir(`resources/meta/character/${name}/`, 'miao')
let charPath = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/`
fs.writeFileSync(`${charPath}data.json`, JSON.stringify(data, '', 2))
if (details.length === 1) {
fs.writeFileSync(`${charPath}detail.json`, JSON.stringify(details[0], '', 2))
} else if (data.id === 20000000) {
for (let idx in details) {
let detail = details[idx]
fs.writeFileSync(`${charPath}/${detail.elem}/detail.json`, JSON.stringify(detail, '', 2))
}
}
console.log(data.name + '数据下载完成')
if (![10000005, 10000007].includes(data.id)) {
await imgs.download()
console.log(data.name + '图像全部下载完成')
}
}
async function down (name = '', force = false) {
if (name === '') {
name = lodash.keys(charData).join(',')
}
let names = name.split(',')
for (let id in charData) {
let ds = charData[id]
if (!names.includes(id) && !names.includes(ds.key) && !names.includes(ds.name)) {
continue
}
await saveCharData(id)
}
fs.writeFileSync(`${_mRoot}data.json`, JSON.stringify(mData, '', 2))
}
const charData = {
61: '绮良良'
}
await down('61', true)

View File

@ -1,141 +0,0 @@
import fs from 'fs'
import cheerio from 'cheerio'
import fetch from 'node-fetch'
import { Data } from '#miao'
import lodash from 'lodash'
import request from 'request'
import HttpsProxyAgent from 'https-proxy-agent'
let agent = new HttpsProxyAgent('http://localhost:4780')
const artiIdx = {
Flower: 1,
Plume: 2,
Sands: 3,
Goblet: 4,
Circlet: 5
}
async function getSets (id) {
const url = `https://genshin.honeyhunterworld.com/i_${id}/?lang=CHS`
let req = await fetch(url, { agent })
let txt = await req.text()
let sTxt = /sortable_data.push\((\[\[.*?\]\])[\n\s]*\)/.exec(txt)
let ret = {}
if (sTxt && sTxt[1]) {
// eslint-disable-next-line no-eval
let arrs = eval(sTxt[1])
lodash.forEach(arrs, (ds) => {
let $ = cheerio.load(ds.join(''))
let a = $('a:eq(1)')
let idRet = /i_(.+)\//.exec(a.attr('href'))
let nRet = /^(\w+)\s/.exec($('a:last').text())
if (nRet && idRet) {
ret[artiIdx[nRet[1]]] = {
id: idRet[1],
name: a.text()
}
}
})
}
return ret
}
async function down (sets = '') {
const url = 'https://genshin.honeyhunterworld.com/fam_art_set/?lang=CHS'
let req = await fetch(url, { agent })
let txt = await req.text()
if (sets) {
sets = sets.split(',')
}
let ret = Data.readJSON('resources/meta/artifact/data.json', 'miao')
let sTxt = /sortable_data.push\((\[\[.*?\]\])\)/.exec(txt)
if (sTxt && sTxt[1]) {
// eslint-disable-next-line no-eval
let txt = sTxt[1]
txt = txt.replace(/<script>.+<\/script>/g, '')
let tmp
try {
tmp = eval(txt)
} catch (e) {
}
lodash.forEach(tmp, (ds) => {
let na = cheerio.load(ds[0])('a:last')
let idRet = /i_(\w+)\//.exec(na.attr('href'))
if (idRet && idRet[1]) {
let effect = {}
let $ = cheerio.load(`<div>${ds[2]}</div>`)
$('span').each(function () {
let setRet = /(\d)-Piece:\s*(.*)。?$/.exec($(this).text())
if (setRet && setRet[1]) {
effect[setRet[1]] = setRet[2]
}
})
if (idRet[1]) {
let id = idRet[1]
ret[id] = ret[id] || {
id,
name: na.find('img').attr('alt'),
sets: {},
effect
}
}
}
})
}
let imgs = []
for (let idx in ret) {
let ds = ret[idx]
if (sets) {
if (!sets.includes(ds.name)) {
continue
}
}
ds.sets = await getSets(ds.id)
console.log(`arti ${ds.id}:${ds.name} Done`)
Data.createDir(`resources/meta/artifact/imgs/${ds.name}`, 'miao')
lodash.forEach(ds.sets, (s, idx) => {
imgs.push({
url: `img/i_${s.id}.webp`,
file: `${ds.name}/${idx}.webp`
})
})
}
Data.createDir('resources/meta/artifact', 'miao')
Data.writeJSON('resources/meta/artifact/data.json', ret, 'miao')
const _path = process.cwd()
const _root = _path + '/plugins/miao-plugin/'
const _aRoot = _root + 'resources/meta/artifact/imgs/'
await Data.asyncPool(5, imgs, async function (ds) {
if (fs.existsSync(`${_aRoot}/${ds.file}`)) {
// console.log(`已存在,跳过 ${ds.file}`)
return true
}
try {
let stream = fs.createWriteStream(`${_aRoot}/${ds.file}.tmp`)
await request('https://genshin.honeyhunterworld.com/' + ds.url).pipe(stream)
return new Promise((resolve) => {
stream.on('finish', () => {
fs.rename(`${_aRoot}/${ds.file}.tmp`, `${_aRoot}/${ds.file}`, () => {
console.log(`图像下载成功: ${ds.file}`)
resolve()
})
})
})
} catch (e) {
console.log(`图像下载失败: ${ds.file}`)
console.log(e)
return false
}
})
}
await down('水仙之梦,花海甘露之光')

View File

@ -1,295 +0,0 @@
import cheerio from 'cheerio'
import lodash from 'lodash'
import fetch from 'node-fetch'
import ImgDownloader from './sprider/ImgDown.js'
import CharData from './sprider/CharData.js'
import { Data } from '#miao'
import HttpsProxyAgent from 'https-proxy-agent'
let agent = new HttpsProxyAgent('http://localhost:4780')
let mData = Data.readJSON('/resources/meta/material/data.json', 'miao')
let tId = Data.readJSON('/tools/meta/talent.json', 'miao')
const tElems = ['anemo', 'geo', 'electro', 'dendro']
let getCharData = async function (id, key, name = '', _id = id) {
let idNum = (id < 10 ? '0' : '') + (id < 100 ? '0' : '') + id
let url = `https://genshin.honeyhunterworld.com/${key}_${idNum}/?lang=CHS`
console.log('req: ' + url)
let req = await fetch(url, {
method: 'GET',
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.20',
referer: 'https://genshin.honeyhunterworld.com/fam_chars/?lang=CHS',
'sec-ch-ua': '"Microsoft Edge";v = "105", " Not;A Brand";v = "99", "Chromium";v = "105"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': 'Windows',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': 1
},
agent
})
let txt = await req.text()
const $ = cheerio.load(txt)
let sTxt = /sortable_data.push\((.*)\)/.exec(txt)
if (sTxt && sTxt[1]) {
// eslint-disable-next-line no-eval
let tmp
try {
tmp = eval(sTxt[1])
} catch (e) {
tmp = {}
}
for (let idx in tmp) {
let t = tmp[idx].join('')
if (/Namecard/.test(t)) {
let r = /\/i_([n\d]+)\/\?/.exec(t)
if (r && r[1]) {
$._nid = r[1]
}
}
}
}
let data = CharData.getBasic($, id, name, _id)
name = name || data.name
let imgs = new ImgDownloader(name)
$.imgs = imgs
let attr = CharData.getDetailAttr($)
let ld = attr.details['90']
data.baseAttr = {
hp: ld[0] * 1,
atk: ld[1] * 1,
def: ld[2] * 1
}
data.growAttr = {
key: attr.keys[3],
value: ld[3]
}
let details = []
let metas = []
let talentElem = {}
let talentId
let talentKey
if (data.elem === 'multi') {
talentKey = {}
talentId = {}
for (let idx in tElems) {
let detail = CharData.getDetail({ $, id, name, setIdx: idx * 1 + 1, elem: tElems[idx] })
detail.attr = attr
detail.elem = tElems[idx]
details.push(detail)
const te = {
anemo: 4,
geo: 6,
electro: 7,
dendro: 8
}
let cid = `1000000${id}-${id}0${te[tElems[idx]]}`
lodash.forEach(tId[cid].talentId || {}, (v, k) => {
talentId[k] = v
})
lodash.forEach(detail.talent, (ds, k) => {
talentKey[ds.id] = k
if (k === 'e' || k === 'q') {
talentElem[ds.id] = tElems[idx]
}
})
}
} else {
let detail = CharData.getDetail({ $, id, name })
details.push(detail)
talentId = tId[(10000000 + id * 1)]?.talentId || {}
}
let detail = details[0]
let { talent, cons } = detail
talentKey = talentKey || lodash.invert(lodash.mapValues(talent, (t) => t.id))
data.talentId = {}
let talentKeyId = {}
lodash.forEach(talentId, (tid, id) => {
data.talentId[id] = talentKey[tid]
talentKeyId[tid] = id
})
if (data.elem === 'multi') {
data.talentElem = {}
lodash.forEach(talentElem, (elem, tid) => {
data.talentElem[talentKeyId[tid]] = elem
})
}
data.talentCons = CharData.getConsTalent(talent, cons)
data.materials = CharData.getMaterials($, mData)
CharData.getImgs($)
return {
data,
details,
metas,
imgs
}
}
function checkName (name) {
let charPath = `resources/meta/character/${name}/`
Data.createDir(charPath, 'miao')
if (name === '旅行者') {
for (let idx in tElems) {
Data.createDir(`${charPath}${tElems[idx]}/icons`, 'miao')
}
} else {
Data.createDir(`${charPath}/icons`, 'miao')
}
Data.createDir(`${charPath}/imgs`, 'miao')
let data = Data.readJSON(`${charPath}/data.json`, 'miao')
return data.ver * 1 > 1
}
async function saveCharData (id, key, name = '', force = false, _id = id) {
if (!id || !key) {
return
}
if (name && checkName(name) && !force) {
return
}
let { data, details, imgs } = await getCharData(id, key, name, _id)
name = name || data.name
if (!name) {
console.log(`角色名不存在${id}:${key}`)
return
}
if (checkName(name) && !force) {
return
}
if (eta[name]) {
data.eta = new Date(`${eta[name]} 10:00:00`) * 1
}
let charPath = `/resources/meta/character/${name}/`
Data.writeJSON({ path: charPath, name: 'data.json', data, rn: true, root: 'miao' })
if (details.length === 1) {
Data.writeJSON({ path: charPath, name: 'detail.json', data: details[0], rn: true, root: 'miao' })
} else if (data.id === 20000000) {
for (let idx in details) {
let detail = details[idx]
Data.writeJSON({ path: `${charPath}/${detail.elem}`, name: 'detail.json', data: detail, rn: true, root: 'miao' })
}
}
console.log(data.name + '数据下载完成')
if (![10000005, 10000007].includes(data.id)) {
await imgs.download()
console.log(data.name + '图像全部下载完成')
}
}
async function down (name = '', force = false) {
if (name === '') {
name = lodash.keys(charData).join(',')
}
let names = name.split(',')
for (let id in charData) {
let ds = charData[id]
if (typeof (ds) === 'string') {
ds = ds.split(',')
ds = { key: ds[0], name: ds[1] }
}
if (!names.includes(id) && !names.includes(ds.key) && !names.includes(ds.name)) {
continue
}
await saveCharData(ds.id || id, ds.key, ds.name, force, id)
}
Data.writeJSON({ name: '/resources/meta/material/data.json', data: mData, rn: true, root: 'miao' })
}
const charData = {
2: 'ayaka,神里绫华',
3: 'qin,琴',
4: { key: 'playergirl', name: '旅行者', id: 7 },
5: 'playerboy,空',
6: 'lisa,丽莎',
7: 'playergirl,荧',
14: 'barbara,芭芭拉',
15: 'kaeya,凯亚',
16: 'diluc,迪卢克',
20: 'razor,雷泽',
21: 'ambor,安柏',
22: 'venti,温迪',
23: 'xiangling,香菱',
24: 'beidou,北斗',
25: 'xingqiu,行秋',
26: 'xiao,魈',
27: 'ningguang,凝光',
29: 'klee,可莉',
30: 'zhongli,钟离',
31: 'fischl,菲谢尔',
32: 'bennett,班尼特',
33: 'tartaglia,达达利亚',
34: 'noel,诺艾尔',
35: 'qiqi,七七',
36: 'chongyun,重云',
37: 'ganyu,甘雨',
38: 'albedo,阿贝多',
39: 'diona,迪奥娜',
41: 'mona,莫娜',
42: 'keqing,刻晴',
43: 'sucrose,砂糖',
44: 'xinyan,辛焱',
45: 'rosaria,罗莎莉亚',
46: 'hutao,胡桃',
47: 'kazuha,枫原万叶',
48: 'feiyan,烟绯',
49: 'yoimiya,宵宫',
50: 'tohma,托马',
51: 'eula,优菈',
52: 'shougun,雷电将军',
53: 'sayu,早柚',
54: 'kokomi,珊瑚宫心海',
55: 'gorou,五郎',
56: 'sara,九条裟罗',
57: 'itto,荒泷一斗',
58: 'yae,八重神子',
59: 'heizo,鹿野院平藏',
60: 'yelan,夜兰',
61: 'momoka,绮良良',
62: 'aloy,埃洛伊',
63: 'shenhe,申鹤',
64: 'yunjin,云堇',
65: 'shinobu,久岐忍',
66: 'ayato,神里绫人',
67: 'collei,柯莱',
68: 'dori,多莉',
69: 'tighnari,提纳里',
70: 'nilou,妮露',
71: 'cyno,赛诺',
72: 'candace,坎蒂丝',
73: 'nahida,纳西妲',
74: 'layla,莱依拉',
75: 'wanderer,流浪者',
76: 'faruzan,珐露珊',
77: 'yaoyao,瑶瑶',
78: 'alhatham,艾尔海森',
79: 'dehya,迪希雅',
80: 'mika,米卡',
81: 'kaveh,卡维',
82: 'baizhuer,白术'
}
let eta = {
妮露: '2022-10-14',
纳西妲: '2022-11-02',
莱依拉: '2022-11-02',
流浪者: '2022-12-07',
珐露珊: '2022-12-07',
瑶瑶: '2023-01-18',
艾尔海森: '2023-01-18',
迪希雅: '2023-03-01',
米卡: '2023-03-21',
卡维: '2023-05-02',
白术: '2023-05-02',
绮良良: '2023-05-24'
}
await down('卡维,白术,绮良良', true)

View File

@ -1,20 +0,0 @@
// eslint-disable-next-line no-unused-vars
import { Data } from '#miao'
import { ProfileDmg } from '#miao.models'
import { ProfileWeapon } from '../apps/profile/ProfileWeapon.js'
export async function calcDmg (inputData, enemyLv = 86) {
let dmg = new ProfileDmg(inputData)
let ret = await dmg.calcData({ enemyLv })
if (ret === false) {
return {}
} else {
ret = Data.getData(ret, 'ret,msg,enemyName')
ret.enemyLevel = enemyLv
}
return ret
}
export async function calcWeapon (inputData, enemyLv = 86) {
return await ProfileWeapon.calc(inputData)
}

View File

@ -1,834 +0,0 @@
{
"10000002": {
"name": "神里绫华",
"talentId": {
"10018": 232,
"10019": 239,
"10024": 231
},
"talentKey": {
"10018": "e",
"10019": "q",
"10024": "a"
}
},
"10000003": {
"name": "琴",
"talentId": {
"10031": 331,
"10033": 332,
"10034": 339
},
"talentKey": {
"10031": "a",
"10033": "e",
"10034": "q"
}
},
"10000006": {
"name": "丽莎",
"talentId": {
"10060": 431,
"10061": 432,
"10062": 439
},
"talentKey": {
"10060": "a",
"10061": "e",
"10062": "q"
}
},
"10000014": {
"name": "芭芭拉",
"talentId": {
"10070": 1431,
"10071": 1432,
"10072": 1439
},
"talentKey": {
"10070": "a",
"10071": "e",
"10072": "q"
}
},
"10000015": {
"name": "凯亚",
"talentId": {
"10073": 1531,
"10074": 1532,
"10075": 1539
},
"talentKey": {
"10073": "a",
"10074": "e",
"10075": "q"
}
},
"10000016": {
"name": "迪卢克",
"talentId": {
"10160": 1631,
"10161": 1632,
"10165": 1639
},
"talentKey": {
"10160": "a",
"10161": "e",
"10165": "q"
}
},
"10000020": {
"name": "雷泽",
"talentId": {
"10201": 2031,
"10202": 2032,
"10203": 2039
},
"talentKey": {
"10201": "a",
"10202": "e",
"10203": "q"
}
},
"10000021": {
"name": "安柏",
"talentId": {
"10017": 2139,
"10032": 2132,
"10041": 2131
},
"talentKey": {
"10017": "q",
"10032": "e",
"10041": "a"
}
},
"10000022": {
"name": "温迪",
"talentId": {
"10221": 2231,
"10224": 2232,
"10225": 2239
},
"talentKey": {
"10221": "a",
"10224": "e",
"10225": "q"
}
},
"10000023": {
"name": "香菱",
"talentId": {
"10231": 2331,
"10232": 2332,
"10235": 2339
},
"talentKey": {
"10231": "a",
"10232": "e",
"10235": "q"
}
},
"10000024": {
"name": "北斗",
"talentId": {
"10241": 2431,
"10242": 2432,
"10245": 2439
},
"talentKey": {
"10241": "a",
"10242": "e",
"10245": "q"
}
},
"10000025": {
"name": "行秋",
"talentId": {
"10381": 2531,
"10382": 2532,
"10385": 2539
},
"talentKey": {
"10381": "a",
"10382": "e",
"10385": "q"
}
},
"10000026": {
"name": "魈",
"talentId": {
"10261": 2631,
"10262": 2632,
"10265": 2639
},
"talentKey": {
"10261": "a",
"10262": "e",
"10265": "q"
}
},
"10000027": {
"name": "凝光",
"talentId": {
"10271": 2731,
"10272": 2732,
"10274": 2739
},
"talentKey": {
"10271": "a",
"10272": "e",
"10274": "q"
}
},
"10000029": {
"name": "可莉",
"talentId": {
"10291": 2931,
"10292": 2932,
"10295": 2939
},
"talentKey": {
"10291": "a",
"10292": "e",
"10295": "q"
}
},
"10000030": {
"name": "钟离",
"talentId": {
"10301": 3031,
"10302": 3032,
"10303": 3039
},
"talentKey": {
"10301": "a",
"10302": "e",
"10303": "q"
}
},
"10000031": {
"name": "菲谢尔",
"talentId": {
"10311": 3131,
"10312": 3132,
"10313": 3139
},
"talentKey": {
"10311": "a",
"10312": "e",
"10313": "q"
}
},
"10000032": {
"name": "班尼特",
"talentId": {
"10321": 3231,
"10322": 3232,
"10323": 3239
},
"talentKey": {
"10321": "a",
"10322": "e",
"10323": "q"
}
},
"10000033": {
"name": "达达利亚",
"talentId": {
"10331": 3331,
"10332": 3332,
"10333": 3339
},
"talentKey": {
"10331": "a",
"10332": "e",
"10333": "q"
}
},
"10000034": {
"name": "诺艾尔",
"talentId": {
"10341": 3431,
"10342": 3432,
"10343": 3439
},
"talentKey": {
"10341": "a",
"10342": "e",
"10343": "q"
}
},
"10000035": {
"name": "七七",
"talentId": {
"10351": 3531,
"10352": 3532,
"10353": 3539
},
"talentKey": {
"10351": "a",
"10352": "e",
"10353": "q"
}
},
"10000036": {
"name": "重云",
"talentId": {
"10401": 3631,
"10402": 3632,
"10403": 3639
},
"talentKey": {
"10401": "a",
"10402": "e",
"10403": "q"
}
},
"10000037": {
"name": "甘雨",
"talentId": {
"10371": 3731,
"10372": 3732,
"10373": 3739
},
"talentKey": {
"10371": "a",
"10372": "e",
"10373": "q"
}
},
"10000038": {
"name": "阿贝多",
"talentId": {
"10386": 3831,
"10387": 3832,
"10388": 3839
},
"talentKey": {
"10386": "a",
"10387": "e",
"10388": "q"
}
},
"10000039": {
"name": "迪奥娜",
"talentId": {
"10391": 3931,
"10392": 3932,
"10395": 3939
},
"talentKey": {
"10391": "a",
"10392": "e",
"10395": "q"
}
},
"10000041": {
"name": "莫娜",
"talentId": {
"10411": 4131,
"10412": 4132,
"10415": 4139
},
"talentKey": {
"10411": "a",
"10412": "e",
"10415": "q"
}
},
"10000042": {
"name": "刻晴",
"talentId": {
"10421": 4231,
"10422": 4232,
"10425": 4239
},
"talentKey": {
"10421": "a",
"10422": "e",
"10425": "q"
}
},
"10000043": {
"name": "砂糖",
"talentId": {
"10431": 4331,
"10432": 4332,
"10435": 4339
},
"talentKey": {
"10431": "a",
"10432": "e",
"10435": "q"
}
},
"10000044": {
"name": "辛焱",
"talentId": {
"10441": 4431,
"10442": 4432,
"10443": 4439
},
"talentKey": {
"10441": "a",
"10442": "e",
"10443": "q"
}
},
"10000045": {
"name": "罗莎莉亚",
"talentId": {
"10451": 4531,
"10452": 4532,
"10453": 4539
},
"talentKey": {
"10451": "a",
"10452": "e",
"10453": "q"
}
},
"10000046": {
"name": "胡桃",
"talentId": {
"10461": 4631,
"10462": 4632,
"10463": 4639
},
"talentKey": {
"10461": "a",
"10462": "e",
"10463": "q"
}
},
"10000047": {
"name": "枫原万叶",
"talentId": {
"10471": 4731,
"10472": 4732,
"10475": 4739
},
"talentKey": {
"10471": "a",
"10472": "e",
"10475": "q"
}
},
"10000048": {
"name": "烟绯",
"talentId": {
"10481": 4831,
"10482": 4832,
"10485": 4839
},
"talentKey": {
"10481": "a",
"10482": "e",
"10485": "q"
}
},
"10000049": {
"name": "宵宫",
"talentId": {
"10491": 4931,
"10492": 4932,
"10495": 4939
},
"talentKey": {
"10491": "a",
"10492": "e",
"10495": "q"
}
},
"10000050": {
"name": "托马",
"talentId": {
"10501": 5031,
"10502": 5032,
"10505": 5039
},
"talentKey": {
"10501": "a",
"10502": "e",
"10505": "q"
}
},
"10000051": {
"name": "优菈",
"talentId": {
"10511": 5131,
"10512": 5132,
"10515": 5139
},
"talentKey": {
"10511": "a",
"10512": "e",
"10515": "q"
}
},
"10000052": {
"name": "雷电将军",
"talentId": {
"10521": 5231,
"10522": 5232,
"10525": 5239
},
"talentKey": {
"10521": "a",
"10522": "e",
"10525": "q"
}
},
"10000053": {
"name": "早柚",
"talentId": {
"10531": 5331,
"10532": 5332,
"10535": 5339
},
"talentKey": {
"10531": "a",
"10532": "e",
"10535": "q"
}
},
"10000054": {
"name": "珊瑚宫心海",
"talentId": {
"10541": 5431,
"10542": 5432,
"10545": 5439
},
"talentKey": {
"10541": "a",
"10542": "e",
"10545": "q"
}
},
"10000055": {
"name": "五郎",
"talentId": {
"10551": 5531,
"10552": 5532,
"10555": 5539
},
"talentKey": {
"10551": "a",
"10552": "e",
"10555": "q"
}
},
"10000056": {
"name": "九条裟罗",
"talentId": {
"10561": 5631,
"10562": 5632,
"10565": 5639
},
"talentKey": {
"10561": "a",
"10562": "e",
"10565": "q"
}
},
"10000057": {
"name": "荒泷一斗",
"talentId": {
"10571": 5731,
"10572": 5732,
"10575": 5739
},
"talentKey": {
"10571": "a",
"10572": "e",
"10575": "q"
}
},
"10000058": {
"name": "八重神子",
"talentId": {
"10581": 5831,
"10582": 5832,
"10585": 5839
},
"talentKey": {
"10581": "a",
"10582": "e",
"10585": "q"
}
},
"10000059": {
"name": "鹿野院平藏",
"talentId": {
"10591": 5931,
"10592": 5932,
"10595": 5939
},
"talentKey": {
"10591": "a",
"10592": "e",
"10595": "q"
}
},
"10000060": {
"name": "夜兰",
"talentId": {
"10606": 6031,
"10607": 6032,
"10610": 6039
},
"talentKey": {
"10606": "a",
"10607": "e",
"10610": "q"
}
},
"10000062": {
"name": "埃洛伊",
"talentId": {
"10621": 6231,
"10622": 6232,
"10625": 6239
},
"talentKey": {
"10621": "a",
"10622": "e",
"10625": "q"
}
},
"10000063": {
"name": "申鹤",
"talentId": {
"10631": 6331,
"10632": 6332,
"10635": 6339
},
"talentKey": {
"10631": "a",
"10632": "e",
"10635": "q"
}
},
"10000064": {
"name": "云堇",
"talentId": {
"10641": 6431,
"10642": 6432,
"10643": 6439
},
"talentKey": {
"10641": "a",
"10642": "e",
"10643": "q"
}
},
"10000065": {
"name": "久岐忍",
"talentId": {
"10651": 6531,
"10652": 6532,
"10655": 6539
},
"talentKey": {
"10651": "a",
"10652": "e",
"10655": "q"
}
},
"10000066": {
"name": "神里绫人",
"talentId": {
"10661": 6631,
"10662": 6632,
"10665": 6639
},
"talentKey": {
"10661": "a",
"10662": "e",
"10665": "q"
}
},
"10000067": {
"name": "柯莱",
"talentId": {
"10671": 6731,
"10672": 6732,
"10675": 6739
},
"talentKey": {
"10671": "a",
"10672": "e",
"10675": "q"
}
},
"10000068": {
"name": "多莉",
"talentId": {
"10681": 6831,
"10682": 6832,
"10685": 6839
},
"talentKey": {
"10681": "a",
"10682": "e",
"10685": "q"
}
},
"10000069": {
"name": "提纳里",
"talentId": {
"10691": 6931,
"10692": 6932,
"10695": 6939
},
"talentKey": {
"10691": "a",
"10692": "e",
"10695": "q"
}
},
"10000070": {
"name": "妮露",
"talentId": {
"10701": 7031,
"10702": 7032,
"10705": 7039
},
"talentKey": {
"10701": "a",
"10702": "e",
"10705": "q"
}
},
"10000071": {
"name": "赛诺",
"talentId": {
"10711": 7131,
"10712": 7132,
"10715": 7139
},
"talentKey": {
"10711": "a",
"10712": "e",
"10715": "q"
}
},
"10000072": {
"name": "坎蒂丝",
"talentId": {
"10721": 7231,
"10722": 7232,
"10725": 7239
},
"talentKey": {
"10721": "a",
"10722": "e",
"10725": "q"
}
},
"10000073": {
"name": "纳西妲",
"talentId": {
"10731": 7331,
"10732": 7332,
"10735": 7339
},
"talentKey": {
"10731": "a",
"10732": "e",
"10735": "q"
}
},
"10000074": {
"name": "莱依拉",
"talentId": {
"10741": 7431,
"10742": 7432,
"10745": 7439
},
"talentKey": {
"10741": "a",
"10742": "e",
"10745": "q"
}
},
"10000075": {
"name": "流浪者",
"talentId": {
"10751": 7531,
"10752": 7532,
"10755": 7539
},
"talentKey": {
"10751": "a",
"10752": "e",
"10755": "q"
}
},
"10000076": {
"name": "珐露珊",
"talentId": {
"10761": 7631,
"10762": 7632,
"10765": 7639
},
"talentKey": {
"10761": "a",
"10762": "e",
"10765": "q"
}
},
"10000077": {
"name": "瑶瑶",
"talentId": {
"10771": 7731,
"10772": 7732,
"10775": 7739
},
"talentKey": {
"10771": "a",
"10772": "e",
"10775": "q"
}
},
"10000078": {
"name": "艾尔海森",
"talentId": {
"10781": 7831,
"10782": 7832,
"10785": 7839
},
"talentKey": {
"10781": "a",
"10782": "e",
"10785": "q"
}
},
"10000079": {
"name": "迪希雅",
"talentId": {
"10791": 7931,
"10792": 7932,
"10795": 7939
},
"talentKey": {
"10791": "a",
"10792": "e",
"10795": "q"
}
},
"10000080": {
"name": "米卡",
"talentId": {
"10801": 8031,
"10802": 8032,
"10805": 8039
},
"talentKey": {
"10801": "a",
"10802": "e",
"10805": "q"
}
}
}

View File

@ -1,422 +0,0 @@
import abbr from './abbr.js'
import lodash from 'lodash'
import fixData from './fixData.js'
let costumes = {
: [200301],
芭芭拉: [201401],
刻晴: [204201],
凝光: [202701],
迪卢克: [201601],
菲谢尔: [203101],
神里绫华: [200201],
丽莎: [200601]
}
const CharData = {
getBasic ($, id, name = '', _id = id) {
let ret = {}
console.log(id, _id)
let fix = fixData[_id || id] || {}
ret.id = fix.id || 10000000 + id * 1
let basic = $('.genshin_table.main_table')
let title = function (title) {
return basic.find(`td:contains('${title}'):last`).next('td').text().trim()
}
ret.name = name || title('Name')
ret.abbr = abbr[ret.name] || ret.name
ret.title = fix.title || title('Title')
ret.star = basic.find('td:contains(\'Rarity\')').next('td').find('.cur_icon').length
ret.elem = title('Element').toLowerCase()
ret.allegiance = title('Occupation')
ret.weapon = title('Weapon').toLowerCase()
ret.birth = title('Month of Birth') + '-' + title('Day of Birth')
ret.astro = title('Constellation')
ret.desc = title('Description')
ret.cncv = fix.cncv || title('Chinese')
ret.jpcv = fix.jpcv || title('Japanese')
ret.costume = costumes[ret.name] || false
ret.ver = 1
return ret
},
getDetailAttr ($) {
// 采集属性信息
let stat = $('.genshin_table.stat_table:first')
let attrs = []
let colIdxs = {}
const titleMap = {
HP: 'hpBase',
Atk: 'atkBase',
Def: 'defBase'
}
const bonusMap = {
Atk: 'atkPct',
HP: 'hpPct',
Def: 'defPct',
CritDMG: 'cdmg',
CritRate: 'cpct',
ER: 'recharge',
EM: 'mastery',
Geo: 'dmg',
Hydro: 'dmg',
Anemo: 'dmg',
Dendro: 'dmg',
Pyro: 'dmg',
Cryo: 'dmg',
Elec: 'dmg',
Heal: 'heal',
Phys: 'phy'
}
stat.find('tr:first td:lt(8)').each(function (i) {
let title = $(this).text()
let titleRet = /^Bonuse?\s(\w+)%*$/.exec(title)
if (titleRet && titleRet[1]) {
attrs.push(bonusMap[titleRet[1]] || titleRet[1])
colIdxs[i] = true
} else if (titleMap[title]) {
attrs.push(titleMap[title])
colIdxs[i] = true
}
})
let lvs = []
let lvStat = {}
stat.find('tr:gt(0)').each(function (i) {
let tr = $(this)
let lvl = tr.find('td:first').text()
lvs.push(lvl)
let data = []
tr.find('td:lt(8)').each(function (i) {
if (!colIdxs[i]) {
return
}
data.push((lodash.trim($(this).text(), '%') * 1) || 0)
})
lvStat[lvl] = data
})
return {
keys: attrs,
details: lvStat
}
},
getDetail ({ $, id, name, setIdx = '', elem = '' }) {
let cont = setIdx ? $(`#skillset_${setIdx}`) : $('#char_skills')
cont.imgs = $.imgs
let iconPath = elem ? `${elem}/icons` : 'icons'
let talent = CharData.getTalents($, cont, name, iconPath)
let talentData = CharData.getTalentData(talent)
let passive = CharData.getPassive($, cont, name, iconPath)
let cons = CharData.getCons($, cont, iconPath)
let attr = CharData.getDetailAttr($)
return {
id,
name,
talent,
talentData,
cons,
passive,
attr
}
},
// 获取正文
getDesc (dt) {
dt = dt || ''
dt = dt.replace(/<color=[^>]*>/g, '')
dt = dt.replace(/<\/color=[^>]*>/g, '')
dt = dt.replace(/<span class=[^>]*>/g, '<strong>')
dt = dt.replace(/<\/span>/g, '</strong>')
dt = dt.split('<br>')
let desc = []
let isEmpty = true
lodash.forEach(dt, (txt, i) => {
txt = lodash.trim(txt)
if (!txt) {
isEmpty = true
return
} else if (txt.length < 15 && isEmpty) {
txt = `<h3>${txt}</h3>`
}
desc.push(txt)
isEmpty = false
})
return desc
},
// 获取单个天赋数据
getTalent ($, cont, imgKey, eq, onlyLv1 = false) {
let info = cont.find(`.genshin_table.skill_table:eq(${eq})`)
let name = info.find('tr:first td:eq(1)').text()
let icon = info.find('tr:first td:first img').attr('src')
let idRet = /s_(\d+)01.webp/.exec(icon)
let id = 0
if (idRet && idRet[1]) {
id = idRet[1] * 1
}
if (onlyLv1) {
$.imgs.add(imgKey, icon)
}
// 说明
let desc = CharData.getDesc(info.find('tr:eq(1) td').html())
// detail
let detail = cont.find(`.genshin_table.skill_dmg_table:eq(${eq})`)
let lvs = []
let details = []
detail.find('tr:first td').each(function (i) {
if (onlyLv1 && i > 1) {
return false
}
if (i > 0) {
lvs.push($(this).text())
}
})
detail.find('tr:gt(0)').each(function () {
let name = $(this).find('td:eq(0)').text()
let values = []
let values2 = []
let isSame = true
let unit = ''
$(this).find('td:gt(0)').each(function (i) {
if (onlyLv1 && i > 0) {
return false
}
let val = lodash.trim($(this).text())
let v = val.replace(/(生命值上限|最大生命值)/, 'HP')
v = v.replace(/(防御力)/, '防御')
v = v.replace('元素精通', '精通')
v = v.replace('攻击力', '攻击')
values.push(v)
if (i > 0 && values[0] !== val) {
isSame = false
}
let ur = /^(.*)(生命值上限|防御力|最大生命值|攻击力|生命值上限 \/ 层|当前生命值| \/ 层)(\s*\*\s*\d)?$/.exec(val)
if (ur && ur[1] && ur[2]) {
values2.push(ur[1] + (ur[3] || ''))
unit = ur[2]
} else {
ur = /^(每点元素能量|每个猫爪|每朵|每个|[12]名角色)(.*)$/.exec(val)
if (ur && ur[1] && ur[2]) {
values2.push(ur[2])
unit = ur[1]
} else {
ur = /^(每层)(.*)(攻击力?)$/.exec(val)
if (ur && ur[1] && ur[2] && ur[3]) {
values2.push(ur[2])
unit = ur[1] + ' ' + ur[3]
} else {
unit = ''
}
}
}
})
let detail = {
name,
unit,
isSame,
values: unit ? values2 : values
}
if (unit === '1名角色') {
detail.name2 = name.replace('', '1')
} else if (unit === '2名角色') {
detail.name2 = name.replace('', '2')
}
details.push(detail)
})
return {
id,
name,
desc,
tables: details
}
},
// 获取天赋
getTalents ($, cont, name, iconPath) {
return {
a: CharData.getTalent($, cont, `${iconPath}/talent-a`, 0),
e: CharData.getTalent($, cont, `${iconPath}/talent-e`, 1),
q: CharData.getTalent($, cont, `${iconPath}/talent-q`, name === '莫娜' || name === '神里绫华' ? 3 : 2)
}
},
// 获取被动天赋
getPassive ($, cont, name, iconPath) {
let tables = cont.find('span.delim h3:contains("Passive Skills")').parent().nextUntil('span.delim')
let ret = []
tables.each(function () {
let ds = {}
$.imgs.add(`${iconPath}/passive-${ret.length}`, $(this).find('img').attr('src'))
ds.name = $(this).find('tr:first td:eq(1)').text()
ds.desc = CharData.getDesc($(this).find('tr:eq(1) td:first').html())
ret.push(ds)
})
if (name === '莫娜' || name === '神里绫华') {
ret.push(CharData.getTalent($, cont, `${iconPath}/passive-${ret.length}`, 2, true))
}
return ret
},
// 获取命座数据
getCons ($, cont, iconPath) {
let tables = cont.find('span.delim h3:contains("Constellations")').parent().nextAll('.skill_table')
let ret = {}
tables.each(function (idx) {
let ds = {}
$.imgs.add(`${iconPath}/cons-${idx + 1}`, $(this).find('img').attr('src'))
ds.name = $(this).find('tr:first td:eq(1)').text()
ds.desc = CharData.getDesc($(this).find('tr:eq(1) td:first').html())
ret[idx + 1] = ds
})
return ret
},
// 获取角色图片素材
getImgs ($) {
let urls = {}
$('#char_gallery a>span.gallery_cont_span').each(function () {
urls[$(this).text()] = $(this).parent().attr('href')
})
let img = function (title, key) {
if (urls[title]) {
$.imgs.add(key, urls[title])
}
}
img('Icon', 'imgs/face')
img('Side Icon', 'imgs/side')
img('Gacha Card', 'imgs/gacha')
img('Gacha Splash', 'imgs/splash')
if ($._nid) {
$.imgs.add('imgs/banner', `img/i_${$._nid}_back.webp`)
$.imgs.add('imgs/card', `img/i_${$._nid}_profile.webp`)
}
},
// 获取命座加成天赋
getConsTalent (talent, cons) {
if (!talent || !cons) {
return { e: 3, q: 5 }
}
let e = talent.e.name
let q = talent.q.name
let c3 = (cons['3']?.desc || []).join('')
let c5 = (cons['5']?.desc || []).join('')
return {
e: c3.includes(e) ? 3 : 5,
q: c5.includes(q) ? 5 : 3
}
},
// 获取素材
getMaterials ($, mData) {
let basic = $('.genshin_table.main_table')
let ret = {}
lodash.forEach([{
title: 'Character Ascension Materials',
keys: 'gem,gem,gem,gem,boss,specialty,normal,normal,normal',
group: { gem: 3, normal: 8 }
}, {
title: 'Skill Ascension Materials',
keys: 'talent,talent,talent,weekly',
group: { talent: 2 }
}], ({ title, keys, group }) => {
let imgs = basic.find(`td:contains('${title}')`).next('td').find('a')
keys = keys.split(',')
let temp = {}
imgs.each(function (idx) {
let key = keys[idx]
if (key) {
let a = $(this)
let img = $(this).find('img')
let name = img.attr('alt')
let idRet = /i_([n\d]+)\//.exec(a.attr('href')) || []
let starRet = /rar_bg_(\d)/.exec(a.find('>div').attr('class'))
let id = idRet[1] || 0
id = id[0] === 'n' ? id : id * 1
let star = starRet[1] * 1 || 0
if (id) {
$.imgs.add2(name, key, `img/i_${id}.webp`)
} else {
console.log('fail', a.attr('href'))
}
ret[key] = name
let ds = {
id,
name,
type: key,
star
}
if (group[key]) {
temp[name] = ds
if (group[key] === idx) {
mData[name] = {
id,
name,
type: key,
star,
items: temp
}
temp = {}
}
} else {
mData[name] = ds
}
}
})
})
return ret
},
getTalentData (talentData) {
let ret = {}
lodash.forEach(['a', 'e', 'q'], (key) => {
let map = {}
lodash.forEach(talentData[key].tables, (tr) => {
if (tr.isSame) {
return true
}
lodash.forEach(tr.values, (val) => {
// eslint-disable-next-line no-control-regex
val = val.replace(/[^\x00-\xff]/g, '').trim()
val = val.replace(/[a-zA-Z]/g, '').trim()
let valArr = []
let valArr2 = []
lodash.forEach(val.split('/'), (v, idx) => {
let valNum = 0
lodash.forEach(v.split('+'), (v) => {
v = v.split('*')
let v1 = v[0].replace('%', '').trim()
valNum += v1 * (v[1] || 1)
valArr2.push(v1 * 1)
if (v[1]) {
valArr2.push(v[1] * 1)
}
})
valArr.push(valNum)
})
let name = tr.name2 || tr.name
map[name] = map[name] || []
if (isNaN(valArr[0])) {
map[name].push(false)
} else if (valArr.length === 1) {
map[name].push(valArr[0])
} else {
map[name].push(valArr)
}
if (valArr2.length > 1) {
map[name + '2'] = map[name + '2'] || []
map[name + '2'].push(valArr2)
}
})
})
ret[key] = map
})
return ret
}
}
export default CharData

View File

@ -1,259 +0,0 @@
import abbr from './abbr.js'
import lodash from 'lodash'
import { Data } from '#miao'
let costumes = {
: [200301], // 琴
芭芭拉: [201401], // 芭芭拉
刻晴: [204201], // 刻晴
凝光: [202701], // 凝光
迪卢克: [201601], // 迪卢克
菲谢尔: [203101], // 菲谢尔
}
const fixData = {
4: {
id: 20000000,
title: '异界的旅人',
cncv: '宴宁/鹿喑',
jpcv: '悠木碧/堀江瞬'
},
5: {
title: '异界的旅人'
},
7: {
title: '异界的旅人'
}
}
const elemMap = { Water: 'hydro', Grass: 'dendro', Ice: 'cryo', Fire: 'pyro', Stone: 'geo' }
const weaponMap = { pole: 'polearm', sword_one_hand: 'sword' }
const CharData = {
getBasic (ds) {
let fe = ds.fetter || {}
let w = Data.regRet(/WEAPON_(.*)$/, ds.weaponType, 1).toLowerCase()
let ret = {
id: ds.id,
name: ds.name,
abbr: abbr[ds.name] || ds.name,
title: fe.title || '',
star: ds.rank,
elem: elemMap[ds.element] || ds.element,
allegiance: fe.native || '',
weapon: weaponMap[w] || w,
birth: ds.birthday.join('-'),
astro: fe.constellation || '',
desc: fe.detail || '',
cncv: fe.cv?.CHS || '',
jpcv: fe.cv?.JP || '',
costume: costumes[ds.name] || false,
source: 'amber',
ver: 1
}
ret.title = ret.title === '' ? '' : ret.title
ret.desc = ret.desc === '' ? '测试角色' : ret.title
return ret
},
getDetailAttr (ds) {
return {
details: { 90: {} }
}
},
getDetail (ds) {
let id = ds.id
let name = ds.name
let talent = CharData.getTalents(ds)
let passive = CharData.getPassive(ds)
let cons = CharData.getCons(ds)
let attr = CharData.getDetailAttr(ds)
return {
id,
name,
talent,
cons,
passive,
attr
}
},
// 获取正文
getDesc (dt) {
dt = dt || ''
dt = dt.replace(/<color=[^>]*>/g, '')
dt = dt.replace(/<\/color(=?[^>])*>/g, '')
dt = dt.replace(/<span class=[^>]*>/g, '<strong>')
dt = dt.replace(/<\/span>/g, '</strong>')
dt = dt.split('\\n')
let desc = []
let isEmpty = true
lodash.forEach(dt, (txt, i) => {
txt = lodash.trim(txt)
if (!txt) {
isEmpty = true
return
} else if (txt.length < 15 && isEmpty) {
txt = `<h3>${txt}</h3>`
}
desc.push(txt)
isEmpty = false
})
return desc
},
// 获取单个天赋数据
getTalent (ds) {
let name = ds.name
let icon = ds.icon
// 说明
let desc = CharData.getDesc(ds.description)
let ret = {}
let titles = []
let details = []
let formater = {
F1P: (t) => (t * 100).toFixed(2) * 1 + '%',
P: (t) => (t * 100).toFixed(2) * 1 + '%',
F1: (t) => t.toFixed(1) * 1,
F2: (t) => t.toFixed(2) * 1,
I: (t) => parseInt(t)
}
lodash.forEach(ds.promote, function (ds) {
lodash.forEach(ds.description, (txt, idx) => {
if (!txt) {
return
}
let [title, tpl] = txt.split('|')
if (!ret[title]) {
ret[title] = []
titles.push(title)
}
let value = []
if (tpl) {
lodash.forEach(tpl.split('}'), (txt) => {
if (txt.trim()) {
let txtRet = /(.*){param(\d+):(F1P|F1|F2|I|P)/.exec(txt)
if (txtRet) {
let pIdx = txtRet[2] - 1
let val = formater[txtRet[3]](ds.params[pIdx])
value.push(txtRet[1] + val)
} else {
value.push(txt)
}
}
})
}
ret[title].push(value.join(''))
})
})
lodash.forEach(titles, (name) => {
let values = []
let values2 = []
let isSame = true
let unit = ''
lodash.forEach(ret[name], (val, i) => {
let v = val.replace(/(生命值上限|最大生命值)/, 'HP')
v = v.replace('/', ' / ').replace('+', ' + ').replace('*', ' * ')
v = v.replace(/(防御力)/, '防御')
values.push(v)
if (i > 0 && values[0] !== val) {
isSame = false
}
let ur = /^(.*)(生命值上限|防御力|最大生命值|攻击力|生命值上限 \/ 层|当前生命值| \/ 层)(\s*\*\s*\d)?$/.exec(val)
if (ur && ur[1] && ur[2]) {
values2.push(ur[1] + (ur[3] || ''))
unit = ur[2]
} else {
ur = /^(每点元素能量|每个猫爪|每朵|每个)(.*)$/.exec(val)
if (ur && ur[1] && ur[2]) {
values2.push(ur[2])
unit = ur[1]
} else {
ur = /^(每层)(.*)(攻击力)$/.exec(val)
if (ur && ur[1] && ur[2] && ur[3]) {
values2.push(ur[2])
unit = ur[1] + ' ' + ur[3]
} else {
unit = ''
}
}
}
})
details.push({
name,
unit,
isSame,
values: unit ? values2 : values
})
})
return {
name,
desc,
tables: details
}
},
// 获取天赋
getTalents (ds) {
return {
a: CharData.getTalent(ds.talent[0]),
e: CharData.getTalent(ds.talent[1]),
q: CharData.getTalent(ds.talent[3])
}
},
// 获取被动天赋
getPassive (ds) {
let ret = []
for (let idx in ds.talent) {
if (idx < 4) {
continue
}
let tmp = ds.talent[idx]
ret.push({
name: tmp.name,
desc: CharData.getDesc(tmp.description)
})
}
return ret
},
// 获取命座数据
getCons (ds) {
let ret = {}
lodash.forEach(ds.constellation, (tmp, idx) => {
ret[idx * 1 + 1] = {
name: tmp.name,
desc: CharData.getDesc(tmp.description)
}
})
return ret;
},
// 获取命座加成天赋
getConsTalent (talent, cons) {
if (!talent || !cons) {
return { e: 3, q: 5 }
}
let e = talent.e.name
let q = talent.q.name
let c3 = (cons['3']?.desc || []).join('')
let c5 = (cons['5']?.desc || []).join('')
return {
e: c3.includes(e) ? 3 : 5,
q: c5.includes(q) ? 5 : 3
}
}
}
export default CharData

View File

@ -1,56 +0,0 @@
import lodash from 'lodash'
const CharMeta = {
getMeta ({ $, id, name, setIdx = '', elem = '', detail = {}, attr }) {
return {
talent: CharMeta.getTalentMeta(detail.talent)
}
},
getTalentMeta (talentData) {
let ret = {}
lodash.forEach(['a', 'e', 'q'], (key) => {
let map = {}
lodash.forEach(talentData[key].tables, (tr) => {
if (tr.isSame) {
return true
}
lodash.forEach(tr.values, (val) => {
// eslint-disable-next-line no-control-regex
val = val.replace(/[^\x00-\xff]/g, '').trim()
val = val.replace(/[a-zA-Z]/g, '').trim()
let valArr = []
let valArr2 = []
lodash.forEach(val.split('/'), (v, idx) => {
let valNum = 0
lodash.forEach(v.split('+'), (v) => {
v = v.split('*')
let v1 = v[0].replace('%', '').trim()
valNum += v1 * (v[1] || 1)
valArr2.push(v1 * 1)
})
valArr.push(valNum)
})
let name = tr.name2 || tr.name
map[name] = map[name] || []
if (isNaN(valArr[0])) {
map[name].push(false)
} else if (valArr.length === 1) {
map[name].push(valArr[0])
} else {
map[name].push(valArr)
}
if (valArr2.length > 1) {
map[name + '2'] = map[name + '2'] || []
map[name + '2'].push(valArr2)
}
})
})
ret[key] = map
})
return ret
}
}
export default CharMeta

View File

@ -1,59 +0,0 @@
import fs from 'fs'
import request from 'request'
import { Data } from '#miao'
import HttpsProxyAgent from 'https-proxy-agent'
let agent = new HttpsProxyAgent('http://localhost:4780')
request.defaults({
agent
})
const _path = process.cwd()
const _root = _path + '/plugins/miao-plugin/'
const _cRoot = _root + 'resources/meta/character/'
export default class ImgDown {
constructor (name) {
this.name = name
this.imgs = []
}
add (key, url) {
this.imgs.push({
url,
file: `${this.name}/${key}.webp`
})
}
add2 (name, type, url) {
this.imgs.push({
url,
file: `../material/${type}/${name}.webp`
})
}
async _down (ds) {
if (fs.existsSync(`${_cRoot}/${ds.file}`)) {
// console.log(`已存在,跳过 ${ds.file}`)
return true
}
try {
let stream = fs.createWriteStream(`${_cRoot}/${ds.file}`)
await request('https://genshin.honeyhunterworld.com/' + ds.url).pipe(stream)
return new Promise((resolve) => {
stream.on('finish', () => {
console.log(`图像下载成功: ${ds.file}`)
resolve()
})
})
} catch (e) {
console.log(`图像下载失败: ${ds.file}`)
console.log(e)
return false
}
}
async download () {
await Data.asyncPool(5, this.imgs, this._down)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,236 +0,0 @@
import lodash from 'lodash'
const WeaponData = {
getBasic ($) {
let ret = {}
let basic = $('.genshin_table.main_table:first')
let title = function (title) {
return basic.find(`td:contains('${title}'):last`).next('td').text().trim()
}
ret.affixTitle = title('Weapon Affix')
ret.star = basic.find('td:contains(\'Rarity\')').next('td').find('.cur_icon').length
ret.desc = title('Description')
return ret
},
getDetailAttr ($) {
// 采集属性信息
let stat = $('.genshin_table.stat_table:first')
let attrs = []
let colIdxs = {}
const titleMap = {
HP: 'hpBase',
Atk: 'atkBase',
Def: 'defBase'
}
const bonusMap = {
Atk: 'atkPct',
HP: 'hpPct',
Def: 'defPct',
CritDMG: 'cdmg',
CritRate: 'cpct',
ER: 'recharge',
EM: 'mastery',
Geo: 'dmg',
Hydro: 'dmg',
Anemo: 'dmg',
Dendro: 'dmg',
Pyro: 'dmg',
Cryo: 'dmg',
Elec: 'dmg',
Heal: 'heal',
Phys: 'phy'
}
stat.find('tr:first td:lt(8)').each(function (i) {
let title = $(this).text()
let titleRet = /^Bonuse?\s(\w+)%*$/.exec(title)
if (titleRet && titleRet[1]) {
attrs.push(bonusMap[titleRet[1]] || titleRet[1])
colIdxs[i] = bonusMap[titleRet[1]] || titleRet[1]
} else if (titleMap[title]) {
attrs.push(titleMap[title])
colIdxs[i] = titleMap[title]
}
})
let lvs = []
let atkBase = {}
let bonusAttr = {}
stat.find('tr:gt(0)').each(function (i) {
let tr = $(this)
let lvl = tr.find('td:first').text()
lvs.push(lvl)
tr.find('td:lt(4)').each(function (i) {
let title = colIdxs[i]
if (!title) {
return
}
if (title === 'atkBase') {
atkBase[lvl] = $(this).text().trim('%') * 1
} else {
bonusAttr[lvl] = lodash.trim($(this).text(), '%') * 1
}
})
})
return {
atk: atkBase,
bonusKey: attrs[1],
bonusData: bonusAttr
}
},
getDetail ($, { id, name }, mData) {
let attr = WeaponData.getDetailAttr($)
let materials = WeaponData.getMaterials($, mData)
let affixData = WeaponData.getAffix($, name)
console.log(affixData)
return {
id,
name,
...WeaponData.getBasic($),
attr,
materials,
affixData
}
},
// 获取正文
getDesc (dt) {
dt = dt || ''
dt = dt.replace(/<color=[^>]*>/g, '')
dt = dt.replace(/<\/color=[^>]*>/g, '')
dt = dt.replace(/<span class=[^>]*>/g, '<strong>')
dt = dt.replace(/<\/span>/g, '</strong>')
dt = dt.replace(/<[^>]*>/g, '')
dt = dt.replace(/<\/[^>]*>/g, '')
dt = dt.split('<br>')
let desc = []
let isEmpty = true
lodash.forEach(dt, (txt, i) => {
txt = lodash.trim(txt)
if (!txt) {
isEmpty = true
return
} else if (txt.length < 15 && isEmpty) {
txt = `${txt}`
}
desc.push(txt)
isEmpty = false
})
return desc
},
// 获取素材
getMaterials ($, mData) {
let basic = $('.genshin_table.main_table')
let ret = {}
lodash.forEach([{
title: 'Weapon Ascension Materials',
keys: 'weapon,monster,normal,weapon,monster,normal,weapon,monster,normal,weapon',
group: { weapon: 9, monster: 7, normal: 8 }
}], ({ title, keys, group }) => {
let imgs = basic.find(`td:contains('${title}')`).next('td').find('a')
keys = keys.split(',')
let temp = {}
imgs.each(function (idx) {
let key = keys[idx]
if (key) {
let a = $(this)
let img = $(this).find('img')
let name = img.attr('alt')
let idRet = /i_([n\d]+)\//.exec(a.attr('href')) || []
let starRet = /rar_bg_(\d)/.exec(a.find('>div').attr('class'))
let id = idRet[1] || 0
id = (id[0] === 'n' ? id.replace(/^n/, '') : id) * 1
let star = starRet[1] * 1 || 0
if (id) {
$.imgs.add2(name, key, `img/i_n${id}.webp`)
} else {
console.log('fail', a.attr('href'))
}
ret[key] = name
let ds = {
id,
name,
type: key,
star
}
if (group[key]) {
temp[key] = temp[key] || {}
temp[key][name] = ds
if (group[key] === idx) {
mData[name] = {
id,
name,
type: key,
star,
items: temp[key]
}
temp[key] = {}
}
} else {
mData[name] = ds
}
}
})
})
return ret
},
getAffix ($, name) {
let affix = {}
let cont = $('.genshin_table.affix_table tr:gt(0)')
cont.each(function () {
let tr = $(this)
affix[tr.find('td:first').text()] = WeaponData.getDesc(tr.find('td:eq(1)').text()).join('')
})
if (name === '白铁大剑') {
console.log(affix)
}
let tmpl = []
lodash.forEach(affix, (txt) => {
let tpls = txt.match(/([^\d]+)([/\d% \\.]+|$)/g)
lodash.forEach(tpls, (tpl, idx) => {
let test = /^([^\d/%]+)([/\d% \\.]*)$/.exec(tpl)
if (test) {
if (!tmpl[idx]) {
tmpl[idx] = {
txt: test[1],
data: [test[2]]
}
} else {
if (test[1] !== tmpl[idx].txt) {
console.log('error:', tmpl[idx].txt, test[1], tpl)
}
tmpl[idx].data.push(test[2])
}
} else {
console.log('error')
}
})
})
let tpls = []
let datas = {}
let idx = 0
lodash.forEach(tmpl, (ds) => {
let { txt, data } = ds
let isSame = true
for (let v of data) {
if (v !== data[0]) {
isSame = false
}
}
if (isSame) {
tpls.push(`${txt}${data[0]}`)
} else {
tpls.push(`${txt}$[${idx}]`)
datas[idx] = data
idx++
}
})
return {
text: tpls.join(''),
datas
}
}
}
export default WeaponData

View File

@ -1,14 +0,0 @@
export default {
达达利亚: '公子',
神里绫华: '绫华',
神里绫人: '绫人',
枫原万叶: '万叶',
雷电将军: '雷神',
珊瑚宫心海: '心海',
荒泷一斗: '一斗',
八重神子: '八重',
九条裟罗: '九条',
罗莎莉亚: '罗莎',
鹿野院平藏: '平藏',
艾尔海森: '海森'
}

View File

@ -1,20 +0,0 @@
export default {
4: {
id: 20000000,
title: '异界的旅人',
cncv: '宴宁/鹿喑',
jpcv: '悠木碧/堀江瞬'
},
5: {
title: '异界的旅人'
},
7: {
title: '异界的旅人'
},
73: {
title: '白草净华'
},
74: {
title: '绮思晚星'
}
}

View File

@ -1,152 +0,0 @@
import fetch from 'node-fetch'
import cheerio from 'cheerio'
import lodash from 'lodash'
import { Data } from '#miao'
import fs from 'fs'
import request from 'request'
import WeaponData from './sprider/WeaponData.js'
import ImgDownloader from './sprider/ImgDown.js'
let ret = {}
const types = ['sword', 'claymore', 'polearm', 'bow', 'catalyst']
for (let type of types) {
ret[type] = Data.readJSON(`resources/meta/weapon/${type}/data.json`, 'miao')
}
let mData = Data.readJSON('resources/meta/material/data.json', 'miao')
let weaponIdMap = Data.readJSON('tools/meta/weapon.json', 'miao')
let getWeaponTypeData = async function (type) {
let url = `https://genshin.honeyhunterworld.com/fam_${type}/?lang=CHS`
console.log('req: ' + url)
let req = await fetch(url, {
method: 'GET',
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.20',
referer: 'https://genshin.honeyhunterworld.com/fam_chars/?lang=CHS',
'sec-ch-ua': '"Microsoft Edge";v = "105", " Not;A Brand";v = "99", "Chromium";v = "105"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': 'Windows',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': 1
}
})
let txt = await req.text()
let sTxt = /sortable_data.push\((\[.*?\])[\n\s]*\)/.exec(txt)
console.log('1', sTxt[1])
if (sTxt && sTxt[1]) {
let tmp = eval(sTxt[1])
lodash.forEach(tmp, (ds) => {
let a = cheerio.load(ds[1])('a')
let name = a.text()
console.log(a.attr('href'))
let idRet = /i_(.*)\//.exec(a.attr('href'))
let star = cheerio.load(ds[2])('img').length
let wid = idRet && idRet[1] ? idRet[1] : ''
ret[type] = ret[type] || {}
let tmp = {
id: weaponIdMap[name] || '',
name,
star
}
if (wid !== 'n' + tmp.id) {
tmp.wid = wid
}
console.log(tmp)
ret[type][name] = tmp
})
}
}
let getWeaponData = async function (type, ds) {
let { id, name } = ds
let url = `https://genshin.honeyhunterworld.com/i_n${id}/?lang=CHS`
console.log(`req:[${name}], ${url}`)
let req = await fetch(url, {
method: 'GET',
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.20',
referer: 'https://genshin.honeyhunterworld.com/fam_chars/?lang=CHS',
'sec-ch-ua': '"Microsoft Edge";v = "105", " Not;A Brand";v = "99", "Chromium";v = "105"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': 'Windows',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': 1
}
})
let txt = await req.text()
let $ = cheerio.load(txt)
let imgs = new ImgDownloader(name)
$.imgs = imgs
let ret = WeaponData.getDetail($, ds, mData)
await $.imgs.download()
return ret
}
async function down (t, n) {
for (let type of types) {
if (type !== t) {
continue
}
await getWeaponTypeData(type)
Data.createDir(`resources/meta/weapon/${type}`, 'miao')
Data.writeJSON({ name: `resources/meta/weapon/${type}/data.json`, data: ret[type], rn: true, root: 'miao' })
let imgs = []
await Data.asyncPool(6, lodash.keys(ret[type]), async (name) => {
if (n && n !== name) {
return
}
let ds = ret[type][name]
Data.createDir(`resources/meta/weapon/${type}/${ds.name}`, 'miao')
let data = await getWeaponData(type, ds)
Data.writeJSON({ name: `resources/meta/weapon/${type}/${ds.name}/data.json`, data, rn: true, root: 'miao' })
lodash.forEach({
icon: '',
awaken: '_awaken_icon',
gacha: '_gacha_icon'
}, (affix, key) => {
imgs.push({
url: `img/i_${ds.id}${affix}.webp`,
file: `${type}/${ds.name}/${key}.webp`
})
})
})
const _path = process.cwd()
const _root = _path + '/plugins/miao-plugin/'
const _wRoot = _root + 'resources/meta/weapon/'
await Data.asyncPool(5, imgs, async function (ds) {
if (fs.existsSync(`${_wRoot}/${ds.file}`)) {
// console.log(`已存在,跳过 ${ds.file}`)
return true
}
try {
let stream = fs.createWriteStream(`${_wRoot}/${ds.file}.tmp`)
await request('https://genshin.honeyhunterworld.com/' + ds.url).pipe(stream)
return new Promise((resolve) => {
stream.on('finish', () => {
fs.rename(`${_wRoot}/${ds.file}.tmp`, `${_wRoot}/${ds.file}`, () => {
console.log(`图像下载成功: ${ds.file}`)
resolve()
})
})
})
} catch (e) {
console.log(`图像下载失败: ${ds.file}`)
console.log(e)
return false
}
})
}
Data.writeJSON({ name: 'resources/meta/material/data.json', data: mData, rn: true, root: 'miao' })
}
// 'sword', 'claymore', 'polearm', 'bow', 'catalyst'
await down('catalyst', '')