components及models重构

This commit is contained in:
yoimiya-kokomi 2022-08-18 18:13:42 +08:00
parent a75ed26a8a
commit af816f17e8
62 changed files with 1168 additions and 944 deletions

View File

@ -1,5 +1,5 @@
import lodash from 'lodash'
import Data from '../components/Data.js'
import {Data} from '../components/index.js'
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
const plugin = 'miao-plugin'

View File

@ -1,12 +1,11 @@
import fs from 'fs'
import lodash from 'lodash'
import { exec } from 'child_process'
import { Cfg } from '../components/index.js'
import Common from '../components/Common.js'
import { Cfg, Common } from '../components/index.js'
let cfgMap = {
角色: 'char.char',
面板: 'char.profile-data',
面板: 'char.profile',
老婆: 'char.wife',
戳一戳: 'char.poke',
小清新: 'char.se',
@ -84,7 +83,7 @@ export async function sysCfg (e, { render }) {
let cfg = {
chars: getStatus('char.char'),
profile: getStatus('char.profile-data'),
profile: getStatus('char.profile'),
wife: getStatus('char.wife'),
poke: getStatus('char.poke'),
se: getStatus('char.se', false),
@ -243,7 +242,7 @@ export async function profileCfg (e, { render }) {
cfg[key] = getStatus(`profile.${key}.status`, true)
})
let groups = Cfg.get('profile-data.groups', {})
let groups = Cfg.get('profile.groups', {})
lodash.forEach(lodash.keys(groups), (group, idx) => {
if (lodash.isUndefined(groups[group])) {
return

View File

@ -3,7 +3,7 @@ import { renderAvatar } from './character/avatar-card.js'
import { getTargetUid, getProfile, profileHelp, getProfileAll, inputProfile } from './character/profile-common.js'
import { profileArtis } from './character/profile-artis.js'
import { renderProfile } from './character/profile-detail.js'
import { Character } from '../components/models.js'
import { Character } from '../models/index.js'
//
export { getProfileAll, getProfile, profileHelp }

View File

@ -1,4 +1,4 @@
import { Artifact, Character } from '../../components/models.js'
import { Artifact, Character } from '../../models/index.js'
import { Cfg, Data, Common, Profile } from '../../components/index.js'
import lodash from 'lodash'
import { segment } from 'oicq'
@ -29,7 +29,7 @@ export async function renderAvatar (e, avatar, render, renderType = 'card') {
if (char.isCustom) {
avatar = { id: char.id, name: char.name, detail: false }
} else {
let profile = await Profile.get(uid, char.id, true)
let profile = Profile.get(uid, char.id, true)
if (profile) {
// 优先使用Profile数据
avatar = profile

View File

@ -1,7 +1,7 @@
// #老婆
import lodash from 'lodash'
import { Cfg } from '../../components/index.js'
import { Character } from '../../components/models.js'
import { Character } from '../../models/index.js'
import { getAvatarList, renderAvatar } from './avatar-card.js'
const relationMap = {

View File

@ -5,8 +5,8 @@ import { segment } from 'oicq'
import MD5 from 'md5'
import fetch from 'node-fetch'
import lodash from 'lodash'
import Data from '../../components/Data.js'
import { Character } from '../../components/models.js'
import { Data } from '../../components/index.js'
import { Character } from '../../models/index.js'
const resPath = process.cwd() + '/plugins/miao-plugin/resources/'
let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/

View File

@ -3,9 +3,9 @@
*
* */
import lodash from 'lodash'
import { Profile, Common, Format } from '../../components/index.js'
import { Profile, Common } from '../../components/index.js'
import { getTargetUid, profileHelp, autoGetProfile } from './profile-common.js'
import { Artifact } from '../../components/models.js'
import { Artifact } from '../../models/index.js'
/*
* 角色圣遗物面板
@ -21,14 +21,14 @@ export async function profileArtis (e, { render }) {
return
}
let charCfg = Artifact.getCharCfg(profile.name)
let { artis, totalMark, totalMarkClass, usefulMark } = getArtis(profile.name, profile.artis)
if (!profile.artis || profile.artis.length === 0) {
if (!profile.hasArtis()) {
e.reply('未能获得圣遗物详情,请重新获取面板信息后查看')
return true
}
let charCfg = profile.getCharCfg()
let { artis, mark: totalMark, markClass: totalMarkClass, usefulMark } = profile.getArtisMark()
let { attrMap } = Artifact.getMeta()
// 渲染图像
@ -62,37 +62,17 @@ export async function profileArtisList (e, { render }) {
return true
}
lodash.forEach(profiles || [], (ds) => {
let name = ds.name
if (!name || name === '空' || name === '荧') {
lodash.forEach(profiles || [], (profile) => {
let name = profile.name
if (!profile.hasData || !profile.hasArtis()) {
return
}
let usefulMark
let charCfg = Artifact.getCharCfg(name)
usefulMark = charCfg.titleWeight
/* 处理圣遗物 */
if (ds.artis) {
let newScore = Artifact.getArtisMark(name, ds.artis)
lodash.forEach(ds.artis, (arti, idx) => {
if (!arti.name) {
return
}
idx = idx.replace('arti', '')
let mark = newScore[idx]
arti.mark = Format.comma(mark, 1)
arti._mark = mark
arti.markClass = Artifact.getMarkClass(mark)
arti.main = Artifact.formatArti(arti.main)
arti.attrs = Artifact.formatArti(arti.attrs)
arti.usefulMark = usefulMark
arti.avatar = name
artis.push(arti)
})
}
let profileArtis = profile.getArtisMark()
lodash.forEach(profileArtis.artis, (arti, idx) => {
arti.usefulMark = profileArtis.usefulMark
arti.avatar = name
artis.push(arti)
})
})
if (artis.length === 0) {
@ -111,32 +91,3 @@ export async function profileArtisList (e, { render }) {
artis
}, { e, render, scale: 1.4 })
}
/*
* 获取圣遗物评分及详情
* */
export function getArtis (char, artisData) {
let charCfg = Artifact.getCharCfg(char)
let newScore = Artifact.getArtisMark(char, artisData)
let totalMark = 0
let artis = []
lodash.forEach(artisData, (arti, idx) => {
idx = idx.replace('arti', '')
let ds = arti
let mark = newScore[idx]
totalMark += mark
ds.mark = Format.comma(mark, 1)
ds.markClass = Artifact.getMarkClass(mark)
ds.main = Artifact.formatArti(arti.main, charCfg.mark, true)
ds.attrs = Artifact.formatArti(arti.attrs, charCfg.mark, false)
artis[idx * 1 - 1] = ds
})
return {
artis,
totalMark,
totalMarkClass: Artifact.getMarkClass(totalMark / 5),
usefulMark: charCfg.titleWeight
}
}

View File

@ -3,10 +3,9 @@
* */
import lodash from 'lodash'
import { segment } from 'oicq'
import { profileList } from './profile-list.js';
import Profile from '../../components/Profile.js'
import { Character } from '../../components/models.js'
import { isV3 } from '../../components/Changelog.js'
import { profileList } from './profile-list.js'
import { Profile, Version } from '../../components/index.js'
import { Character } from '../../models/index.js'
/*
* 获取面板查询的 目标uid
@ -36,7 +35,7 @@ export async function getTargetUid (e) {
return uid
}
}
if (!isV3) {
if (!Version.isV3) {
let botQQ = global.BotConfig ? global.BotConfig.account.qq : false
if (e.at && e.at !== botQQ) {
uid = await getUid(e.at)
@ -133,7 +132,7 @@ export async function autoGetProfile (e, uid, avatar, callback) {
return { err: true }
}
let profile = await Profile.get(uid, char.id)
let profile = Profile.get(uid, char.id)
if (!profile) {
if (await refresh()) {
return { err: true }

View File

@ -1,7 +1,6 @@
import lodash from 'lodash'
import { autoRefresh } from './profile-common.js'
import { Calc, Common, Format, Profile } from '../../components/index.js'
import { getArtis } from './profile-artis.js'
import { Common, Format, Profile } from '../../components/index.js'
export async function renderProfile (e, char, render, mode = 'profile', params = {}) {
let selfUser = await e.checkAuth({
@ -27,7 +26,7 @@ export async function renderProfile (e, char, render, mode = 'profile', params =
return refreshRet
}
let profile = await Profile.get(uid, char.id)
let profile = Profile.get(uid, char.id)
if (!profile) {
if (await refresh()) {
@ -58,21 +57,19 @@ export async function renderProfile (e, char, render, mode = 'profile', params =
atkPlus: c(a.atk - a.atkBase),
def: c(a.def),
defPlus: c(a.def - a.defBase),
cRate: p(a.cRate),
cDmg: p(a.cDmg),
cpct: p(a.cpct),
cdmg: p(a.cdmg),
mastery: c(a.mastery),
recharge: p(a.recharge),
dmgBonus: p(Math.max(a.dmgBonus * 1 || 0, a.phyBonus * 1 || 0))
dmg: p(Math.max(a.dmg * 1 || 0, a.phy * 1 || 0))
}
let { artis, totalMark, totalMarkClass, usefulMark } = getArtis(char.name, profile.artis)
let { artis, mark: totalMark, markClass: totalMarkClass, usefulMark } = profile.getArtisMark()
let enemyLv = await selfUser.getCfg('char.enemyLv', 91)
let dmgMsg = []
let dmgData = []
let dmgCalc = await Calc.calcData({
profile,
char,
let dmgCalc = await profile.calcDmg({
enemyLv,
mode,
...params

View File

@ -1,7 +1,6 @@
import lodash from 'lodash'
import { autoRefresh, getTargetUid } from './profile-common.js'
import { Common, Profile } from '../../components/index.js'
import { Character } from '../../components/models.js'
export async function profileList (e, { render }) {
let uid = await getTargetUid(e)
@ -21,18 +20,14 @@ export async function profileList (e, { render }) {
msg = '获取角色面板数据成功'
newChar = e.newChar
}
lodash.forEach(profiles || [], (ds) => {
if (!['enka', 'input2', 'miao'].includes(ds.dataSource)) {
lodash.forEach(profiles || {}, (profile) => {
if (!profile.hasData) {
return
}
let { id } = ds
let char = Character.get(id)
let char = profile.char
let tmp = char.getData('id,name,abbr,element,star')
if (tmp.name === '荧' || tmp.name === '空') {
return
}
tmp.source = ds.dataSource
tmp.level = ds.lv || 1
tmp.source = profile.dataSource
tmp.level = profile.level || 1
tmp.isNew = 0
if (newChar[char.name]) {
tmp.isNew = 1

View File

@ -1,6 +1,6 @@
import lodash from 'lodash'
import { Common, Profile } from '../../components/index.js'
import { Artifact, Avatars } from '../../components/models.js'
import { Common, Profile, Data } from '../../components/index.js'
import { Avatars } from '../../models/index.js'
export async function profileStat (e, { render }) {
// 缓存时间,单位小时
@ -40,11 +40,12 @@ export async function profileStat (e, { render }) {
let avatarRet = []
lodash.forEach(talentData, (avatar) => {
let { talent, id, name } = avatar
let { talent, id } = avatar
avatar.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3
avatarRet.push(avatar)
if (profiles[id]?.artis) {
avatar.artisMark = Artifact.getTotalMark(name, profiles[id].artis)
if (profiles[id]) {
let mark = profiles[id].getArtisMark(false)
avatar.artisMark = Data.getData(mark, 'mark,markClass,names')
}
})

View File

@ -1,8 +1,6 @@
import { Cfg } from '../components/index.js'
import lodash from 'lodash'
import { currentVersion, changelogs } from '../components/Changelog.js'
import Common from '../components/Common.js'
import fs from 'fs'
import { Cfg, Version, Common } from '../components/index.js'
const _path = process.cwd()
const helpPath = `${_path}/plugins/miao-plugin/resources/help`
@ -12,7 +10,8 @@ export async function help (e, { render }) {
return false
}
let custom = {}; let help = {}
let custom = {};
let help = {}
if (fs.existsSync(`${helpPath}/help-cfg.js`)) {
help = await import(`file://${helpPath}/help-cfg.js?version=${new Date().getTime()}`)
} else if (fs.existsSync(`${helpPath}/help-list.js`)) {
@ -46,7 +45,8 @@ export async function help (e, { render }) {
if (!icon) {
help.css = 'display:none'
} else {
let x = (icon - 1) % 10; let y = (icon - x - 1) / 10
let x = (icon - 1) % 10;
let y = (icon - x - 1) / 10
help.css = `background-position:-${x * 50}px -${y * 50}px`
}
})
@ -63,8 +63,8 @@ export async function help (e, { render }) {
export async function versionInfo (e, { render }) {
return await Common.render('help/version-info', {
currentVersion,
changelogs,
currentVersion: Version.version,
changelogs: Version.changelogs,
elem: 'cryo'
}, { e, render, scale: 1.2 })
}

View File

@ -2,13 +2,11 @@
* 胡桃数据库的统计
*
* */
import { HutaoApi, Character } from '../components/models.js'
import { Cfg } from '../components/index.js'
import lodash from 'lodash'
import fs from 'fs'
import Common from '../components/Common.js'
import Abyss from '../components/models/Abyss.js'
import Avatars from '../components/models/Avatars.js'
import { Cfg, Common } from '../components/index.js'
import { Abyss, Avatars, Character } from '../models/index.js'
import HutaoApi from './stat/HutaoApi.js'
export async function consStat (e, { render }) {
if (Cfg.isDisable(e, 'wiki.stat')) {

View File

@ -1,9 +1,8 @@
import { segment } from 'oicq'
import { Character } from '../components/models.js'
import lodash from 'lodash'
import Calendar from '../components/Calendar.js'
import Common from '../components/Common.js'
import { Cfg } from '../components/index.js'
import Calendar from './wiki/calendar.js'
import { Cfg, Common } from '../components/index.js'
import { Character } from '../models/index.js'
// eslint-disable-next-line no-unused-vars
let action = {
@ -17,7 +16,8 @@ export async function wiki (e, { render }) {
return false
}
let reg = /#?(.+)(命座|命之座|天赋|技能|资料|照片|写真|图片|图像)$/; let msg = e.msg
let reg = /#?(.+)(命座|命之座|天赋|技能|资料|照片|写真|图片|图像)$/;
let msg = e.msg
let ret = reg.exec(msg)
if (!ret || !ret[1] || !ret[2]) {

View File

@ -1,6 +1,6 @@
import fetch from 'node-fetch'
import moment from 'moment'
import { Character } from './models.js'
import { Character } from '../../models/index.js'
import lodash from 'lodash'
const ignoreIds = [495, // 有奖问卷调查开启!

View File

@ -1,6 +1,6 @@
import { Cfg } from './index.js'
import Cfg from './Cfg.js'
import { Version } from './index.js'
import { segment } from 'oicq'
import { currentVersion, yunzaiVersion, isV3 } from './Changelog.js'
export const render = async function (path, params, cfg) {
let paths = path.split('/')
@ -14,19 +14,19 @@ export const render = async function (path, params, cfg) {
elemLayout: layoutPath + 'elem.html',
sys: {
scale: Cfg.scale(cfg.scale || 1),
copyright: `Created By Yunzai-Bot<span class="version">${yunzaiVersion}</span> & Miao-Plugin<span class="version">${currentVersion}</span>`
copyright: `Created By Yunzai-Bot<span class="version">${Version.yunzai}</span> & Miao-Plugin<span class="version">${Version.version}</span>`
}
})
let ret = true
if (base64) {
ret = isV3 ? await e.reply(base64) : await e.reply(segment.image(`base64://${base64}`))
ret = Version.isV3 ? await e.reply(base64) : await e.reply(segment.image(`base64://${base64}`))
}
return cfg.retMsgId ? ret : true
}
export const todoV3 = function (e) {
if (isV3) {
if (Version.isV3) {
e.reply('本功能暂时不支持V3版Yunzai...')
return true
}

View File

@ -68,6 +68,24 @@ let Data = {
return {}
},
async import (name) {
return await Data.importModule('plugins/miao-plugin/components/optional-lib/', `${name}.js`)
},
async importCfg (key) {
let sysCfg = await Data.importModule('plugins/miao-plugin/config/system', `${key}.js`)
let diyCfg = await Data.importModule('plugins/miao-plugin/config/', `${key}.js`)
if (diyCfg.isSys) {
console.error(`miao-plugin: config/${key}.js无效已忽略`)
console.error(`如需配置请复制config/${key}_default.js为config/${key}.js请勿复制config/system下的系统文件`)
diyCfg = {}
}
return {
sysCfg,
diyCfg
}
},
/*
* 返回一个从 target 中选中的属性的对象
*
@ -173,6 +191,7 @@ let Data = {
}
}
},
eachStr: (arr, fn) => {
if (lodash.isString(arr)) {
arr = arr.replace(/\s*(;||、|)\s*/, ',')

View File

@ -1,62 +1,30 @@
import fs from 'fs'
import lodash from 'lodash'
import Format from './Format.js'
import Character from './models/Character.js'
import Miao from './profile-data/miao.js'
import Enka from './profile-data/enka.js'
import Data from './Data.js'
import { Character, ProfileReq, ProfileData } from '../models/index.js'
const _path = process.cwd()
let sysCfg = await Data.importModule('plugins/miao-plugin/config/system', 'profile.js')
let diyCfg = await Data.importModule('plugins/miao-plugin/config/', 'profile.js')
const userPath = `${_path}/data/UserData/`
if (!fs.existsSync(userPath)) {
fs.mkdirSync(userPath)
}
function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
function getServ (uid) {
return (diyCfg.profileApi || sysCfg.profileApi)({ uid, Miao, Enka, diyCfg })
}
const requestInterval = diyCfg.requestInterval || sysCfg.requestInterval || 5
ProfileReq.regServ({ Miao, Enka })
let Profile = {
async request (uid, e) {
if (uid.toString().length !== 9) {
return false
}
let Serv = getServ(uid)
let cdTime = await Profile.inCd(uid)
if (cdTime) {
e.reply(`请求过快,请${cdTime}秒后重试..`)
return false
}
await Profile.setCd(uid, 20) // 发起请求设置20s cd
e.reply('开始获取数据,可能会需要一定时间~')
await sleep(500)
let req = new ProfileReq({ e, uid })
let data
try {
data = await Serv.request({ uid, e, sysCfg, diyCfg, setCd: Profile.setCd })
data = await req.request()
if (!data) {
return false
}
// enka服务测冷却时间5分钟
let cdTime = requestInterval * 60
if (data.ttl) {
cdTime = Math.max(cdTime, data.ttl * 1)
delete data.ttl
}
await Profile.setCd(uid, cdTime) // 根据设置设置cd
return Profile.save(uid, data, Serv.key)
return Profile.save(uid, data)
} catch (err) {
console.log(err)
e.reply('请求失败')
@ -64,24 +32,7 @@ let Profile = {
}
},
async setCd (uid, cdTime = 5 * 60) {
let ext = new Date() * 1 + cdTime * 1000
await redis.set(`miao:role-all:${uid}`, ext + '', { EX: cdTime })
},
async inCd (uid) {
let ext = await redis.get(`miao:role-all:${uid}`)
if (!ext || isNaN(ext)) {
return false
}
let cd = new Date() * 1 - ext
if (cd < 0) {
return Math.ceil(0 - cd / 1000)
}
return false
},
save (uid, data, dataSource = 'enka') {
save (uid, data) {
let userData = {}
const userFile = `${userPath}/${uid}.json`
if (fs.existsSync(userFile)) {
@ -101,21 +52,6 @@ let Profile = {
return data
},
saveCharData (uid, ds) {
if (!uid || !ds.id) {
return
}
let userData = {}
const userFile = `${userPath}/${uid}.json`
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
userData.chars = userData.chars || {}
userData.chars[ds.id] = ds
fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ')
return ds
},
_get (uid, charId) {
const userFile = `${userPath}/${uid}.json`
let userData = {}
@ -128,21 +64,17 @@ let Profile = {
return false
},
async get (uid, charId, onlyAvailable = false) {
if (onlyAvailable) {
let data = await Profile.get(uid, charId)
if (data && data.dataSource && data.dataSource !== 'input') {
return data
get (uid, charId, onlyHasData = false) {
let data = Profile._get(uid, charId)
if (data) {
let profile = new ProfileData(data)
if (onlyHasData && !profile.hasData) {
return false
}
return profile
} else {
return false
}
let data = Profile._get(uid, charId)
let Serv = getServ(uid)
if (Serv.getCharData && data && data.id) {
return await Serv.getCharData(uid, data, Profile.saveCharData, { sysCfg, diyCfg })
}
return data
},
getAll (uid) {
@ -152,48 +84,13 @@ let Profile = {
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
if (userData && userData.chars) {
return userData.chars
}
return false
},
formatArti (ds, markCfg = false, isMain = false) {
if (lodash.isArray(ds[0])) {
let ret = []
lodash.forEach(ds, (d) => {
ret.push(Profile.formatArti(d, markCfg, isMain))
let ret = {}
lodash.forEach(userData.chars, (ds, id) => {
ret[id] = new ProfileData(ds)
})
return ret
}
let title = ds[0]
let val = ds[1]
let num = ds[1]
if (!title || title === 'undefined') {
return []
}
if (/伤害加成/.test(title) && val < 1) {
val = Format.pct(val * 100)
num = num * 100
} else if (/伤害加成|大|暴|充能|治疗/.test(title)) {
val = Format.pct(val)
} else {
val = Format.comma(val, 1)
}
if (/元素伤害加成/.test(title)) {
title = title.replace('元素伤害', '伤')
} else if (title === '物理伤害加成') {
title = '物伤加成'
}
let mark = 0
if (markCfg) {
mark = Format.comma(markCfg[title] * num || 0)
if (isMain) {
mark = mark / 4
}
}
return { title, val, mark }
return false
},
inputProfile (uid, e) {
@ -286,8 +183,8 @@ let Profile = {
},
getServName (uid) {
let Serv = getServ(uid)
return Serv.getName({ uid, diyCfg, sysCfg })
let Serv = ProfileReq.getServ(uid)
return Serv.name
}
}
export default Profile

View File

@ -73,4 +73,17 @@ try {
const yunzaiVersion = packageJson.version
const isV3 = yunzaiVersion[0] === '3'
export { currentVersion, yunzaiVersion, isV3, changelogs }
let Version = {
isV3,
get version () {
return currentVersion
},
get yunzai () {
return yunzaiVersion
},
get changelogs () {
return changelogs
}
}
export default Version

View File

@ -1,10 +1,8 @@
import Data from './Data.js'
import Cfg from './Cfg.js'
import Profile from './Profile.js'
import Common from './Common.js'
import Format from './Format.js'
import Calc from './Calc.js'
import Common from './Common.js'
import Cfg from './Cfg.js'
import Version from './Version.js'
import Profile from './Profile.js'
import * as Models from './models.js'
export { Data, Cfg, Profile, Common, Format, Models, Calc }
export { Data, Cfg, Format, Common, Version, Profile }

View File

@ -1,6 +0,0 @@
import Character from './models/Character.js'
import HutaoApi from './models/HutaoApi.js'
import Artifact from './models/Artifact.js'
import Avatars from './models/Avatars.js'
export { Character, HutaoApi, Artifact, Avatars }

View File

@ -1,273 +0,0 @@
import { attrValue, attrNameMap, attrMap, mainAttr, subAttr, usefulAttr }
from '../../resources/meta/reliquaries/reliquaries-mark-new.js'
import { Character } from '../models.js'
import lodash from 'lodash'
import Format from '../Format.js'
import _Data from '../Data.js'
import Data from '../Data.js';
let _path = process.cwd()
let artis = _Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
let artisMap = {}
lodash.forEach(artis, (ds) => {
artisMap[ds.name] = ds
})
let charCfg = {}
let Artifact = {
getCharCfg (name) {
if (charCfg[name]) {
return charCfg[name]
}
let attrWeight = usefulAttr[name] || { atk: 75, cp: 100, cd: 100 }
let attrMark = {}
let char = Character.get(name)
let baseAttr = char?.lvStat?.detail['90'] || [400, 500, 300]
lodash.forEach(attrWeight, (weight, attr) => {
attrMark[attr] = weight / attrValue[attr]
})
// let baseAttr = [400, 500, 300];
if (attrMark.hp) {
attrMark.hpPlus = attrMark.hp / baseAttr[0] * 100
}
if (attrMark.atk) {
// 以520作为武器白值均值计算
attrMark.atkPlus = attrMark.atk / (baseAttr[1] * 1 + 520) * 100
}
if (attrMark.def) {
attrMark.defPlus = attrMark.def / baseAttr[2] * 100
}
let maxMark = Artifact.getMaxMark(attrWeight)
let titleMark = {}
let titleWeight = {}
lodash.forEach(attrMark, (mark, attr) => {
let aTitle = attrMap[attr].title
if (/小/.test(aTitle)) {
return
}
titleMark[aTitle] = mark
titleWeight[aTitle] = attrWeight[attr] || 0
if (/大/.test(aTitle)) {
let sTitle = aTitle.replace('大', '小')
titleWeight[sTitle] = titleWeight[aTitle]
}
})
charCfg[name] = {
weight: attrWeight,
mark: attrMark,
titleMap: titleMark,
titleWeight,
maxMark
}
return charCfg[name]
},
getMaxAttr (charAttr = {}, list2 = [], maxLen = 1, banAttr = '') {
let tmp = []
lodash.forEach(list2, (attr) => {
if (attr === banAttr) return
if (!charAttr[attr]) return
tmp.push({ attr, mark: charAttr[attr] })
})
tmp = lodash.sortBy(tmp, 'mark')
tmp = tmp.reverse()
let ret = []
lodash.forEach(tmp, (ds) => ret.push(ds.attr))
return ret.slice(0, maxLen)
},
getMaxMark (attrWeight) {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
let totalMark = 0;
let mMark = 0
let mAttr = ''
if (idx === 1) {
mAttr = 'hpPlus'
} else if (idx === 2) {
mAttr = 'atkPlus'
} else if (idx >= 3) {
mAttr = Artifact.getMaxAttr(attrWeight, mainAttr[idx])[0]
mMark = attrWeight[mAttr]
totalMark += attrWeight[mAttr] * 2
}
let sAttr = Artifact.getMaxAttr(attrWeight, subAttr, 4, mAttr)
lodash.forEach(sAttr, (attr, aIdx) => {
totalMark += attrWeight[attr] * (aIdx === 0 ? 6 : 1)
})
ret[idx] = totalMark
ret['m' + idx] = mMark
}
return ret
},
getAttr (ds) {
let title = ds[0]
let attr = attrNameMap[title]
if (/元素伤害/.test(title)) {
attr = 'dmg'
} else if (/物理|物伤/.test(title)) {
attr = 'phy'
}
return attr
},
getAttrMark (attrMark, ds) {
if (!ds || !ds[1]) {
return 0
}
let attr = Artifact.getAttr(ds)
let val = ds[1]
return (attrMark[attr] || 0) * val
},
getMark (charCfg, posIdx, mainAttr, subAttr) {
let ret = 0
let { mark, maxMark, weight } = charCfg
let mAttr = Artifact.getAttr(mainAttr)
let fixPct = 1
if (posIdx >= 3) {
fixPct = Math.max(0, Math.min(1, (weight[mAttr] || 0) / (maxMark['m' + posIdx])))
ret += Artifact.getAttrMark(mark, mainAttr) / 4
}
lodash.forEach(subAttr, (ds) => {
ret += Artifact.getAttrMark(mark, ds)
})
return ret * (1 + fixPct) / 2 / maxMark[posIdx] * 66
},
getArtisMark (charName = '', artis = {}) {
let charCfg = Artifact.getCharCfg(charName)
let ret = {}
lodash.forEach(artis, (ds, idx) => {
idx = idx.replace('arti', '')
ret[idx] = Artifact.getMark(charCfg, idx, ds.main, ds.attrs)
})
return ret
},
getTotalMark (charName = '', artis) {
let artisMark = Artifact.getArtisMark(charName, artis)
let mark = 0
for (let k in artisMark) {
if (artisMark[k]) {
mark += artisMark[k]
}
}
let sets = {}
let setMap = {}
lodash.forEach(artis, (arti) => {
let setName = Artifact.getSetByArti(arti.name)?.name || 'N/A'
if (setName) {
sets[setName] = (sets[setName] || 0) + 1
}
})
for (let set in sets) {
if (sets[set] >= 4) {
setMap[set] = 4
} else if (sets[set] >= 2) {
setMap[set] = 2
}
}
let setsRet = []
lodash.forEach(setMap, (v, k) => {
let name = Artifact.getArtiBySet(k)
if (name) {
setsRet.push(name)
}
})
return {
mark: (mark || 0).toFixed(1),
markClass: Artifact.getMarkClass(mark / 5),
sets: setsRet
}
},
getMarkClass (mark) {
let pct = mark
let scoreMap = [['D', 10], ['C', 16.5], ['B', 23.1], ['A', 29.7], ['S', 36.3], ['SS', 42.9], ['SSS', 49.5], ['ACE', 56.1], ['ACE²', 66]]
for (let idx = 0; idx < scoreMap.length; idx++) {
if (pct < scoreMap[idx][1]) {
return scoreMap[idx][0]
}
}
},
getSetByArti (name) {
for (let idx in artisMap) {
for (let idx2 in artisMap[idx].sets) {
if (artisMap[idx].sets[idx2].name === name) {
return artisMap[idx]
}
}
}
return false
},
getArtiBySet (name, idx = 1) {
let set = artisMap[name]
if (!set) {
return ''
}
return set.sets[`arti${idx}`].name
},
getMeta () {
return {
attrMap
}
},
formatArti (ds, markCfg = false, isMain = false) {
if (lodash.isArray(ds[0])) {
let ret = []
lodash.forEach(ds, (d) => {
ret.push(Artifact.formatArti(d, markCfg, isMain))
})
return ret
}
let title = ds[0];
let key = '';
let val = ds[1];
let num = ds[1]
if (!title || title === 'undefined') {
return []
}
if (/伤害加成/.test(title) && val < 1) {
val = Format.pct(val * 100)
num = num * 100
} else if (/伤害加成|大|暴|充能|治疗/.test(title)) {
val = Format.pct(val)
} else {
val = Format.comma(val, 1)
}
if (/元素伤害加成/.test(title)) {
title = title.replace('元素伤害', '伤')
key = 'dmg'
} else if (title === '物理伤害加成') {
title = '物伤加成'
key = 'phy'
}
key = key || attrNameMap[title]
let mark = markCfg[key] * num
if (markCfg) {
if (isMain) {
mark = mark / 4 + 0.01
}
mark = Format.comma(mark || 0)
}
return { title, val, mark }
}
}
export default Artifact

View File

@ -1,7 +0,0 @@
import Base from './Base.js'
export default class ProfileData extends Base {
constructor (data) {
super()
}
}

View File

@ -1,94 +0,0 @@
import { attrMark, maxMark, attrMap, usefulAttr } from '../../resources/meta/reliquaries/reliquaries-mark.js'
import lodash from 'lodash'
// let meta = Data.readJSON("../../resources/meta/reliquaries", "data.json");
let meta = {}
let Reliquaries = {
getUseful (char) {
let attrKey = usefulAttr[char] || ''
attrKey = attrKey.split(',')
let attrTitles = []; let retMap = {}
lodash.forEach(attrKey, (key) => {
let attr = attrMap[key]
if (attr) {
attrTitles.push(attr.title)
lodash.forEach(attr.attr.split(','), (k) => {
retMap[k] = attrMark[k]
})
}
})
return {
titles: attrTitles,
mark: retMap
}
},
getMaxMark (char, banTitle = '') {
let markMap = Reliquaries.getUseful(char).mark
let markList = []
lodash.forEach(markMap, (m, title) => {
if (title !== banTitle) {
markList.push(maxMark[title])
}
})
markList = markList.sort((a, b) => b - a)
let retMaxMark = markList[0]
lodash.forEach(markList, (mark, idx) => {
if (idx > 0 && idx < 4) {
retMaxMark += mark / 6
}
})
return retMaxMark
},
getMark (char = '', data = []) {
let total = 0
let markMap = Reliquaries.getUseful(char).mark
lodash.forEach(data, (ret) => {
ret = ret || []
let title = ret[0]; let val = ret[1]
if (title && val) {
if (markMap[title]) {
total += markMap[title] * val
}
}
})
return total
},
getMarkScore (mark, maxMark) {
let pct = mark / maxMark
let scoreMap = [
['D', 0.15],
['C', 0.25],
['B', 0.35],
['A', 0.45],
['S', 0.55],
['SS', 0.65],
['SSS', 0.75],
['ACE', 0.85],
['ACE²', 1]
]
for (let idx = 0; idx < scoreMap.length; idx++) {
if (pct < scoreMap[idx][1]) {
return scoreMap[idx][0]
}
}
},
getSet (name) {
for (let idx in meta) {
if (meta[idx].name === name) {
return meta[idx]
}
}
}
}
export default Reliquaries

View File

@ -1,19 +1,10 @@
import lodash from 'lodash'
import Character from '../models/Character.js'
import meta from './enka-meta.js'
import cmeta from './enka-char.js'
import _Data from '../Data.js'
import moment from 'moment'
import enkaMeta from './enka-meta.js'
import charMeta from './enka-char.js'
import { Character, Artifact, ProfileData } from '../../models/index.js'
moment.locale('zh-cn')
let _path = process.cwd()
let relis = _Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
let relisMap = {}
lodash.forEach(relis, (ds) => {
relisMap[ds.name] = ds
})
const artiIdx = {
EQUIP_BRACER: 1,
@ -44,7 +35,7 @@ const attrMap = {
CHARGE_EFFICIENCY: '充能效率'
}
let Data = {
let EnkaData = {
getData (uid, data) {
let ret = {
uid,
@ -60,8 +51,8 @@ let Data = {
})
lodash.forEach(data.avatarInfoList, (ds) => {
let char = Data.getAvatar(ds)
ret.chars[char.id] = char
let char = EnkaData.getAvatar(ds)
ret.chars[char.id] = char // .toData()
})
if (data.ttl) {
@ -72,21 +63,18 @@ let Data = {
},
getAvatar (data) {
let char = Character.get(data.avatarId)
let now = moment()
let ret = {
id: data.avatarId,
name: char ? char.name : '',
dataSource: 'enka',
updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: data.propMap['4001'].val * 1,
fetter: data.fetterInfo.expLevel,
attr: Data.getAttr(data.fightPropMap),
weapon: Data.getWeapon(data.equipList),
artis: Data.getArtifact(data.equipList),
let profile = new ProfileData({ id: char.id })
profile.setBasic({
level: data.propMap['4001'].val * 1,
cons: data.talentIdList ? data.talentIdList.length : 0,
talent: Data.getTalent(char.id, data.skillLevelMap, data.proudSkillExtraLevelMap || {})
}
return Data.dataFix(ret)
fetter: data.fetterInfo.expLevel,
dataSource: 'enka'
})
profile.setAttr(EnkaData.getAttr(data.fightPropMap))
profile.setWeapon(EnkaData.getWeapon(data.equipList))
profile.setArtis(EnkaData.getArtifact(data.equipList))
profile.setTalent(EnkaData.getTalent(char.id, data.skillLevelMap), 'original')
return EnkaData.dataFix(profile)
},
getAttr (data) {
let ret = {}
@ -98,15 +86,15 @@ let Data = {
hp: 2000,
hpBase: 1,
mastery: 28,
cRate: {
cpct: {
src: 20,
pct: true
},
cDmg: {
cdmg: {
src: 22,
pct: true
},
hInc: {
heal: {
src: 26,
pct: true
},
@ -133,8 +121,8 @@ let Data = {
maxDmg = Math.max(data[key] * 1, maxDmg)
})
// phy 30
ret.dmgBonus = maxDmg * 100
ret.phyBonus = data['30'] * 100
ret.dmg = maxDmg * 100
ret.phy = data['30'] * 100
return ret
},
@ -154,19 +142,18 @@ let Data = {
return [attrMap[id], d.statValue]
}
lodash.forEach(data, (ds) => {
let flat = ds.flat || {}; let sub = flat.reliquarySubstats || []
let flat = ds.flat || {}
let sub = flat.reliquarySubstats || []
let idx = artiIdx[flat.equipType]
if (!idx) {
return
}
let setName = meta[flat.setNameTextMapHash] || ''
let setCfg = relisMap[setName] || { name: '', sets: {} }
let artiCfg = setCfg.sets[`arti${idx}`] || { name: '' }
let setName = enkaMeta[flat.setNameTextMapHash] || ''
ret[`arti${idx}`] = {
name: artiCfg.name,
set: setCfg.name,
name: Artifact.getArtiBySet(setName, idx),
set: setName,
level: Math.min(20, ((ds.reliquary && ds.reliquary.level) || 1) - 1),
main: get(flat.reliquaryMainstat),
attrs: [
@ -189,16 +176,17 @@ let Data = {
})
let { weapon, flat } = ds
return {
name: meta[flat.nameTextMapHash],
name: enkaMeta[flat.nameTextMapHash],
star: flat.rankLevel,
level: weapon.level,
promote: weapon.promoteLevel,
affix: (lodash.values(weapon.affixMap)[0] || 0) + 1
}
},
getTalent (charid, ds = {}, ext = {}) {
let cm = cmeta[charid] || {}
let cn = cm.Skills || {}; let ce = cm.ProudMap
getTalent (charid, ds = {}) {
let cm = charMeta[charid] || {}
let cn = cm.Skills || {}
let ce = cm.ProudMap
let idx = 1
let idxMap = { 1: 'a', 2: 'e', 3: 'q', a: 'a', s: 'e', e: 'q' }
lodash.forEach(cn, (n, id) => {
@ -213,45 +201,30 @@ let Data = {
lodash.forEach(ds, (lv, id) => {
let key = idxMap[id]
ret[key] = {
level_original: lv,
level_current: lv
original: lv
}
})
lodash.forEach(ext, (lv, id) => {
let key = idxMap[id]
if (ret[key]) {
ret[key].level_current = ret[key].level_current + lv
}
})
return ret
},
dataFix (ret) {
if (ret._fix) {
return ret
}
let { attr, talent, id } = ret
let { attr, id } = ret
id = id * 1
switch (id) {
case 10000052:
// 雷神被动加成fix
attr.dmgBonus = Math.max(0, attr.dmgBonus - (attr.recharge - 100) * 0.4)
attr.dmg = Math.max(0, attr.dmg - (attr.recharge - 100) * 0.4)
break
case 10000041:
// 莫娜被动fix
attr.dmgBonus = Math.max(0, attr.dmgBonus - attr.recharge * 0.2)
attr.dmg = Math.max(0, attr.dmg - attr.recharge * 0.2)
break
}
if (id !== 10000033) {
let a = talent.a || {}
if (a.level_current > 10) {
a.level_current = 10
a.level_original = 10
}
}
ret._fix = true
return ret
}
}
export default Data
export default EnkaData

View File

@ -1,41 +1,31 @@
import fetch from 'node-fetch'
import EnkaData from './enka-data.js'
import Data from '../Data.js'
import { Data } from '../index.js'
import { ProfileServ } from '../../models/index.js'
let Enka = {
key: 'enka',
cd: 5,
async request ({ e, uid, avatar, diyCfg, sysCfg, setCd }) {
let url = diyCfg?.enkaApi?.url || sysCfg.enkaApi.url
let profileApi = diyCfg?.enkaApi?.listApi || sysCfg.enkaApi.listApi
let api = profileApi({ url, uid, avatar })
if (diyCfg?.enkaApi?.apiKey) {
api += '?key=' + diyCfg.enkaApi.apiKey
export default new ProfileServ({
id: 'enka',
cfgKey: 'enkaApi',
// 处理请求参数
async request (api) {
let params = { headers: { 'User-Agent': this.getCfg('userAgent') } }
let proxy = this.getCfg('proxyAgent')
if (proxy) {
let { HttpsProxyAgent } = await Data.import('https-proxy-agent')
params.agent = new HttpsProxyAgent(proxy)
}
let config = { headers: { 'User-Agent': diyCfg?.enkaApi?.userAgent || sysCfg.enkaApi.userAgent } }
if (diyCfg?.enkaApi?.proxyAgent) {
let { HttpsProxyAgent } = await Data.importModule('./plugins/miao-plugin/components/profile-data/', 'enka-proxy.js')
config.agent = new HttpsProxyAgent(diyCfg.enkaApi.proxyAgent)
}
let req = await fetch(api, config)
let data = await req.json()
return { api, params }
},
// 处理服务返回
async response (data, req) {
if (!data.playerInfo) {
e.reply(`请求失败:${data.msg || '可能是面板服务并发过高,请稍后重试'}`)
return false
return req.err(`请求失败:${data.msg}` || 'error', 60)
}
let details = data.avatarInfoList
if (!details || details.length === 0 || !details[0].propMap) {
e.reply('请打开游戏内角色展柜的【显示详情】后等待5分钟重新获取面板')
await setCd(uid, 5 * 60)
return false
return req.err('no-avatar', 5 * 60)
}
return EnkaData.getData(uid, data)
},
getName ({ uid, diyCfg, sysCfg }) {
let url = diyCfg?.enkaApi?.url || sysCfg.enkaApi.url
url = url.replace('https://', '').replace('/', '').trim()
return url
return EnkaData.getData(req.uid, data)
}
}
export default Enka
})

View File

@ -0,0 +1,2 @@
let MiaoData = {}
export default MiaoData

View File

@ -1,4 +1,4 @@
import _Data from '../Data.js'
import { Data } from '../index.js'
import lodash from 'lodash'
const _path = process.cwd()
@ -11,7 +11,7 @@ export const artiIdx = {
理之冠: 5
}
let relis = _Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
let relis = Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
let setMap = {}
lodash.forEach(relis, (ds) => {

View File

@ -1,32 +1,12 @@
import fetch from 'node-fetch'
import lodash from 'lodash'
import Character from '../models/Character.js'
import moment from 'moment'
import { artiIdx, artiSetMap, attrMap } from './miao-meta.js'
import { Character, ProfileServ } from '../../models/index.js'
import cmeta from './enka-char.js'
import { artiIdx, artiSetMap, attrMap } from './miao-meta.js'
let Miao = {
key: 'miao',
cd: 1,
async request ({ e, uid, avatar = '', diyCfg, sysCfg }) {
let url = diyCfg?.miaoApi?.url || sysCfg.miaoApi.url
let token = diyCfg?.miaoApi?.token || sysCfg.miaoApi.token
let profileApi = diyCfg?.miaoApi?.listApi || sysCfg.miaoApi.listApi
let api = profileApi({ url, uid, avatar, token })
let data
let req = await fetch(api)
data = await req.json()
if (data.status !== 0) {
e.reply(data.msg || '请求失败')
return false
}
data = data.data
if (!data.showAvatarInfoList || data.showAvatarInfoList.length === 0) {
e.reply('请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板')
return false
}
return Miao.getData(uid, data)
},
name: 'MiaoApi',
getData (uid, data) {
let ret = {
@ -93,15 +73,15 @@ let Miao = {
def: 'defense',
defBase: 'baseDEF',
mastery: 'elementMastery',
cRate: {
cpct: {
src: 'critRate',
pct: true
},
cDmg: {
cdmg: {
src: 'critDamage',
pct: true
},
hInc: {
heal: {
src: 'heal',
pct: true
},
@ -124,8 +104,8 @@ let Miao = {
lodash.forEach('fire,elec,water,grass,wind,rock,ice'.split(','), (key) => {
maxDmg = Math.max(hurt[key] * 100, maxDmg)
})
ret.dmgBonus = maxDmg
ret.phyBonus = hurt.physical * 100
ret.dmg = maxDmg
ret.phy = hurt.physical * 100
return ret
},
getWeapon (weapon) {
@ -216,4 +196,18 @@ let Miao = {
}
}
export default Miao
export default new ProfileServ({
key: 'miao',
name: 'MiaoApi',
cfgKey: 'miaoApi',
async response (data, req) {
if (data.status !== 0) {
return req.err(data.msg || 'error', 60)
}
data = data.data
if (!data.showAvatarInfoList || data.showAvatarInfoList.length === 0) {
return req.err('empty', 5 * 60)
}
return Miao.getData(req.uid, data)
}
})

View File

@ -172,3 +172,5 @@ export const abbr = {
渡过烈火的贤人: '渡火贤人',
冰风迷途的勇士: '冰风勇士'
}
export const isSys = true

View File

@ -3,7 +3,8 @@
* 如需自定义配置请复制修改上一级profile_default.js
* */
export const profileApi = ({ uid, Miao, Enka, diyCfg }) => {
export const getProfileServ = ({ uid, serv, diyCfg }) => {
let { Miao, Enka } = serv
let token = diyCfg?.miaoApi?.token
if (token && token.length === 32) {
return Miao
@ -13,19 +14,24 @@ export const profileApi = ({ uid, Miao, Enka, diyCfg }) => {
export const miaoApi = {
url: 'http://49.232.91.210/profile',
token: 'miao-token',
listApi: ({ url, uid, token }) => {
return `${url}/data?uid=${uid}&token=${token}`
listApi: ({ url, uid, diyCfg }) => {
return `${url}/data?uid=${uid}&token=${diyCfg.token}`
}
}
export const enkaApi = {
url: 'https://enka.network/',
userAgent: 'Miao-Plugin/3.0',
listApi: ({ url, uid }) => {
return `${url}u/${uid}/__data.json`
listApi: ({ url, uid, diyCfg }) => {
let api = `${url}u/${uid}/__data.json`
if (diyCfg?.apiKey) {
api += '?key=' + diyCfg.apiKey
}
return api
}
}
/* 请求面板的冷却时间,单位分钟 */
export const requestInterval = 5
export const isSys = true

View File

@ -1,25 +1,24 @@
// 适配V3 Yunzai将index.js移至app/index.js
import { currentVersion, isV3 } from './components/Changelog.js'
import Data from './components/Data.js'
import { Data, Version } from './components/index.js'
export * from './apps/index.js'
let index = { miao: {} }
if (isV3) {
if (Version.isV3) {
index = await Data.importModule('/plugins/miao-plugin/adapter', 'index.js')
}
export const miao = index.miao || {}
if (Bot?.logger?.info) {
Bot.logger.info(`---------^_^---------`)
Bot.logger.info(`喵喵插件${currentVersion}初始化~`)
Bot.logger.info(`喵喵插件${Version.version}初始化~`)
} else {
console.log(`喵喵插件${currentVersion}初始化~`)
console.log(`喵喵插件${Version.version}初始化~`)
}
setTimeout(async function () {
let msgStr = await redis.get('miao:restart-msg')
let relpyPrivate = async function () {
}
if (!isV3) {
if (!Version.isV3) {
let common = await Data.importModule('/lib', 'common.js')
if (common && common.default && common.default.relpyPrivate) {
relpyPrivate = common.default.relpyPrivate
@ -29,7 +28,7 @@ setTimeout(async function () {
let msg = JSON.parse(msgStr)
await relpyPrivate(msg.qq, msg.msg)
await redis.del('miao:restart-msg')
let msgs = [`当前喵喵版本: ${currentVersion}`, '您可使用 #喵喵版本 命令查看更新信息']
let msgs = [`当前喵喵版本: ${Version.version}`, '您可使用 #喵喵版本 命令查看更新信息']
await relpyPrivate(msg.qq, msgs.join('\n'))
}
}, 1000)

View File

@ -1,7 +1,7 @@
import Base from '../models/Base.js'
import lodash from 'lodash'
import Data from '../Data.js'
import moment from 'moment'
import Base from '../models/Base.js'
import { Data } from '../components/index.js'
moment.locale('zh-cn')
@ -67,12 +67,12 @@ export default class Abyss extends Base {
getAvatars () {
let ret = {}
lodash.forEach(this.reveral, (ds) => {
if(ds.id) {
if (ds.id) {
ret[ds.id] = true
}
})
lodash.forEach(this.stat, (ds) => {
if(ds.id) {
if (ds.id) {
ret[ds.id] = true
}
})
@ -80,12 +80,12 @@ export default class Abyss extends Base {
let levels = floor?.levels || {}
lodash.forEach(levels, (level) => {
lodash.forEach(level.up?.avatars || [], (id) => {
if(id){
if (id) {
ret[id] = true
}
})
lodash.forEach(level.down?.avatars || [], (id) => {
if(id){
if (id) {
ret[id] = true
}
})

48
models/Artifact.js Normal file
View File

@ -0,0 +1,48 @@
import { attrMap }
from '../resources/meta/reliquaries/reliquaries-mark-new.js'
import lodash from 'lodash'
import { Data } from '../components/index.js'
let artisMap = {}
async function init () {
let _path = process.cwd()
let artis = Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
lodash.forEach(artis, (ds) => {
artisMap[ds.name] = ds
})
}
await init()
let Artifact = {
// 根据圣遗物名称获取套装
getSetByArti (name) {
for (let idx in artisMap) {
for (let idx2 in artisMap[idx].sets) {
if (artisMap[idx].sets[idx2].name === name) {
return artisMap[idx]
}
}
}
return false
},
// 获取指定圣遗物套装指定位置的名字
getArtiBySet (name, idx = 1) {
let set = artisMap[name]
if (!set) {
return ''
}
return set.sets[`arti${idx}`].name
},
getMeta () {
return {
attrMap
}
}
}
export default Artifact

View File

@ -1,9 +1,7 @@
import Base from './Base.js'
import lodash from 'lodash'
import Data from '../Data.js'
import Artifact from './Artifact.js'
import Character from './Character.js'
import Common from '../Common.js'
import { Data, Common } from '../components/index.js'
import { Artifact, Character } from './index.js'
export default class Avatars extends Base {
constructor (uid, datas = []) {
@ -24,27 +22,20 @@ export default class Avatars extends Base {
data.star = 5
}
let artis = {}
let sets = {}
let setCount = {}
lodash.forEach(avatar.reliquaries, (arti) => {
artis[arti.pos] = Data.getData(arti, 'name,level,set:set.name')
sets[arti.set.name] = (sets[arti.set.name] || 0) + 1
setCount[arti.set.name] = (setCount[arti.set.name] || 0) + 1
})
data.artis = artis
data.set = {}
for (let set in sets) {
if (sets[set] >= 4) {
data.set[set] = 4
} else if (sets[set] >= 2) {
data.set[set] = 2
data.sets = {}
data.names = []
for (let set in setCount) {
if (setCount[set] >= 2) {
data.sets[set] = setCount[set] >= 4 ? 4 : 2
data.names.push(Artifact.getArtiBySet(set))
}
}
data.sets = []
lodash.forEach(data.set, (v, k) => {
let name = Artifact.getArtiBySet(k)
if (name) {
data.sets.push(name)
}
})
avatars[data.id] = data
})
this.avatars = avatars

View File

@ -1,15 +1,13 @@
import { Data } from '../index.js'
import { Data } from '../components/index.js'
export default class Base {
constructor () {
this.name = ''
}
toString () {
return this.name
return this?.name || ''
}
getData (arrList = '', cfg = {}) {
arrList = arrList || this._dataKey || ''
return Data.getData(this, arrList, cfg)
}

View File

@ -1,8 +1,8 @@
import Base from './Base.js'
import lodash from 'lodash'
import fs from 'fs'
import Data from '../Data.js'
import sizeOf from 'image-size'
import Base from './Base.js'
import { Data } from '../components/index.js'
let aliasMap = {}
let idMap = {}
@ -12,10 +12,8 @@ const _path = process.cwd()
const metaPath = `${_path}/plugins/miao-plugin/resources/meta/character/`
async function init () {
let sysCfg = await Data.importModule('plugins/miao-plugin/config/system', 'character.js')
let custom = await Data.importModule('plugins/miao-plugin/config', 'character.js')
lodash.forEach([custom.customCharacters, sysCfg.characters], (roleIds) => {
let { sysCfg, diyCfg } = await Data.importCfg('character')
lodash.forEach([diyCfg.customCharacters, sysCfg.characters], (roleIds) => {
lodash.forEach(roleIds || {}, (aliases, id) => {
aliases = aliases || []
if (aliases.length === 0) {
@ -31,7 +29,7 @@ async function init () {
})
})
lodash.forEach([sysCfg.wifeData, custom.wifeData], (wifeData) => {
lodash.forEach([sysCfg.wifeData, diyCfg.wifeData], (wifeData) => {
lodash.forEach(wifeData || {}, (ids, type) => {
type = Data.def({ girlfriend: 0, boyfriend: 1, daughter: 2, son: 3 }[type], type)
if (!wifeMap[type]) {

181
models/ProfileArtis.js Normal file
View File

@ -0,0 +1,181 @@
/*
* 面板圣遗物
* */
import lodash from 'lodash'
import Base from './Base.js'
import { Artifact, Character } from './index.js'
import { Format } from '../components/index.js'
import ArtisMark from './profile-lib/ArtisMark.js'
import { attrMap, attrValue, usefulAttr } from '../resources/meta/reliquaries/reliquaries-mark-new.js'
let charCfg = {}
export default class ProfileArtis extends Base {
constructor (charid = 0, ds = false) {
super()
this.charid = charid
this.artis = {}
if (ds) {
this.setArtisSet(ds)
}
}
setArtisSet (ds) {
for (let key in ds) {
this.setArtis(key, ds[key] || {})
}
}
setArtis (idx = 1, ds = {}) {
idx = idx.toString().replace('arti', '')
let ret = {}
ret.name = ds.name || Artifact.getArtiBySet(ds.set, idx) || ''
ret.set = ds.set || Artifact.getSetByArti(ret.title) || ''
ret.level = ds.level || 1
ret.main = ArtisMark.formatAttr(ds.main || {})
ret.attrs = []
for (let attrIdx in ds.attrs || []) {
if (ds.attrs[attrIdx]) {
ret.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx]))
}
}
this.artis[idx] = ret
}
forEach (fn) {
lodash.forEach(this.artis, (ds, idx) => {
if (ds.name) {
fn(ds, idx)
}
})
}
get 1 () {
return this.artis[1]
}
get 2 () {
return this.artis[2]
}
get 3 () {
return this.artis[3]
}
get 4 () {
return this.artis[4]
}
get 5 () {
return this.artis[5]
}
get length () {
return lodash.keys(this.artis).length
}
toJSON () {
return this.getData('1,2,3,4,5')
}
getMarkDetail (withDetail = true) {
let charCfg = this.getCharCfg()
let artis = {}
let setCount = {}
let usefulMark = charCfg.titleWeight
let totalMark = 0
this.forEach((arti, idx) => {
let mark = ArtisMark.getMark(charCfg, idx, arti.main, arti.attrs)
totalMark += mark
setCount[arti.set] = (setCount[arti.set] || 0) + 1
if (!withDetail) {
artis[idx] = {
_mark: mark,
mark: Format.comma(mark, 1),
markClass: ArtisMark.getMarkClass(mark)
}
} else {
artis[idx] = {
name: arti.name,
set: arti.set,
level: arti.level,
_mark: mark,
mark: Format.comma(mark, 1),
markClass: ArtisMark.getMarkClass(mark),
main: ArtisMark.formatArti(arti.main, charCfg.mark, true),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.mark)
}
}
})
let sets = {}
let names = []
for (let set in setCount) {
if (setCount[set] >= 2) {
sets[set] = setCount[set] >= 4 ? 4 : 2
names.push(Artifact.getArtiBySet(set))
}
}
let ret = {
mark: Format.comma(totalMark, 1),
_mark: totalMark,
markClass: ArtisMark.getMarkClass(totalMark / 5),
artis,
sets,
names
}
if (withDetail) {
ret.usefulMark = usefulMark
}
return ret
}
getCharCfg () {
let char = Character.get(this.charid)
let name = char.name
if (charCfg[name]) {
return charCfg[name]
}
let attrWeight = usefulAttr[name] || { atk: 75, cp: 100, cd: 100 }
let attrMark = {}
let baseAttr = char?.lvStat?.detail['90'] || [400, 500, 300]
lodash.forEach(attrWeight, (weight, attr) => {
attrMark[attr] = weight / attrValue[attr]
})
// let baseAttr = [400, 500, 300];
if (attrMark.hp) {
attrMark.hpPlus = attrMark.hp / baseAttr[0] * 100
}
if (attrMark.atk) {
// 以520作为武器白值均值计算
attrMark.atkPlus = attrMark.atk / (baseAttr[1] * 1 + 520) * 100
}
if (attrMark.def) {
attrMark.defPlus = attrMark.def / baseAttr[2] * 100
}
let maxMark = ArtisMark.getMaxMark(attrWeight)
let titleMark = {}
let titleWeight = {}
lodash.forEach(attrMark, (mark, attr) => {
let aTitle = attrMap[attr].title
if (/小/.test(aTitle)) {
return
}
titleMark[aTitle] = mark
titleWeight[aTitle] = attrWeight[attr] || 0
if (/大/.test(aTitle)) {
let sTitle = aTitle.replace('大', '小')
titleWeight[sTitle] = titleWeight[aTitle]
}
})
charCfg[name] = {
weight: attrWeight,
mark: attrMark,
titleMap: titleMark,
titleWeight,
maxMark
}
return charCfg[name]
}
}

94
models/ProfileData.js Normal file
View File

@ -0,0 +1,94 @@
import lodash from 'lodash'
import Base from './Base.js'
import { Data } from '../components/index.js'
import { Character, ProfileArtis, ProfileDmg } from './index.js'
export default class ProfileData extends Base {
constructor (ds = {}) {
super()
let char = Character.get(ds.id)
if (!char) {
return false
}
this.id = char.id
this.char = char
this.setBasic(ds)
ds.attr && this.setAttr(ds.attr)
ds.weapon && this.setWeapon(ds.weapon)
this.artis = new ProfileArtis(this.id)
ds.artis && this.setArtis(ds.artis)
ds.talent && this.setTalent(ds.talent)
}
setBasic (ds = {}) {
this.level = ds.lv || ds.level || 1
this.cons = ds.cons || 0
this.fetter = ds.fetter || 0
this.dataSource = ds.dataSource || 'enka'
this.updateTime = ds.updateTime || new Date() * 1
}
setAttr (ds) {
this.attr = lodash.extend(Data.getData(ds, 'atk,atkBase,def,defBase,hp,hpBase,mastery,recharge'), {
heal: ds.heal || ds.hInc || 0,
cpct: ds.cpct || ds.cRate,
cdmg: ds.cdmg || ds.cDmg,
dmg: ds.dmg || ds.dmgBonus || 0,
phy: ds.phy || ds.phyBonus || 0
})
}
setWeapon (ds = {}) {
this.weapon = {
name: ds.name,
star: ds.rank || ds.star || 1,
level: ds.level || ds.lv || 1,
promote: ds.promote || 1,
affix: ds.affix
}
}
setArtis (ds = false) {
if (ds) {
this.artis.setArtisSet(ds)
}
}
setTalent (ds = {}, mode = 'level') {
this.talent = this.char.getAvatarTalent(ds, this.cons, mode)
}
get name () {
return this.char?.name || ''
}
get hasData () {
if (!['enka', 'input2', 'miao'].includes(this.dataSource)) {
return false
}
if (['空', '荧'].includes(this.name)) {
return false
}
return true
}
hasArtis () {
return this.hasData && this.artis.length > 0
}
toJSON () {
return this.getData('id,name,level,cons,fetter,attr,weapon,talent,artis,updateTime,dataSource')
}
getArtisMark (withDetail = true) {
return this.artis.getMarkDetail(withDetail)
}
async calcDmg ({ enemyLv = 91, mode = 'profile', dmgIdx = 0 }) {
if (!this.dmg) {
this.dmg = new ProfileDmg(this)
}
return await this.dmg.calcData({ enemyLv, mode, dmgIdx })
}
}

146
models/ProfileDmg.js Normal file
View File

@ -0,0 +1,146 @@
import Base from './Base.js'
import { Character } from './index.js'
import lodash from 'lodash'
import { attrMap } from './profile-lib/calc-meta.js'
import Calc from './profile-lib/Calc.js'
export default class ProfileDmg extends Base {
constructor (profile = false) {
super()
this.profile = profile
if (profile && profile.id) {
let { id } = profile
this.char = Character.get(id)
}
}
async calcData ({ enemyLv = 91, mode = 'profile', dmgIdx = 0 }) {
if (!this.char || !this.profile) {
return false
}
let { profile, char } = this
let charCalcData = await Calc.getCharCalcRule(this.char.name)
if (!charCalcData) {
return false
}
let talent = Calc.talent(profile, char)
let meta = {
cons: profile.cons * 1,
talent
}
let { buffs, details, defParams, mainAttr, defDmgIdx, enemyName } = charCalcData
defParams = defParams || {}
let originalAttr = Calc.attr(profile)
let weaponBuffs = await Calc.weapon(profile.weapon.name)
let reliBuffs = await Calc.reliquaries(profile.artis)
buffs = lodash.concat(buffs, weaponBuffs, reliBuffs)
lodash.forEach(buffs, (buff) => {
buff.sort = lodash.isUndefined(buff.sort) ? 1 : buff.sort
})
buffs = lodash.sortBy(buffs, ['sort'])
let { msg } = Calc.calcAttr({ originalAttr, buffs, meta, params: defParams || {} })
let ret = []
let detailMap = []
let dmgRet = []
let dmgDetail = {}
lodash.forEach(details, (detail, detailSysIdx) => {
if (lodash.isFunction(detail)) {
let { attr } = Calc.calcAttr({ originalAttr, buffs, meta })
let ds = lodash.merge({ talent }, Calc.getDs(attr, meta))
detail = detail({ ...ds, attr, profile })
}
let params = lodash.merge({}, defParams, detail.params || {})
let { attr } = Calc.calcAttr({ originalAttr, buffs, meta, params, talent: detail.talent || '' })
if (detail.check && !detail.check(Calc.getDs(attr, meta, params))) {
return
}
if (detail.cons && meta.cons < detail.cons * 1) {
return
}
let ds = lodash.merge({ talent }, Calc.getDs(attr, meta, params))
let dmg = Calc.getDmgFn({ ds, attr, profile, enemyLv, showDetail: detail.showDetail })
let basicDmgRet
if (detail.dmg) {
basicDmgRet = detail.dmg(ds, dmg)
detail.userIdx = detailMap.length
detailMap.push(detail)
ret.push({
title: detail.title,
...basicDmgRet
})
}
})
if (mode === 'dmg') {
let detail
if (dmgIdx && detailMap[dmgIdx - 1]) {
detail = detailMap[dmgIdx - 1]
} else if (!lodash.isUndefined(defDmgIdx) && details[defDmgIdx]) {
detail = details[defDmgIdx]
} else {
detail = detailMap[0]
}
dmgDetail = {
title: detail.title,
userIdx: detail.userIdx,
basicRet: lodash.merge({}, ret[detail.userIdx]),
attr: []
}
mainAttr = mainAttr.split(',')
let params = lodash.merge({}, defParams, detail.params || {})
let basicDmg = dmgDetail.basicRet
lodash.forEach(mainAttr, (reduceAttr) => {
dmgDetail.attr.push(attrMap[reduceAttr])
let rowData = []
lodash.forEach(mainAttr, (incAttr) => {
if (incAttr === reduceAttr) {
rowData.push({ type: 'na' })
return
}
let { attr } = Calc.calcAttr({
originalAttr,
buffs,
meta,
params,
incAttr,
reduceAttr,
talent: detail.talent || ''
})
let ds = lodash.merge({ talent }, Calc.getDs(attr, meta, params))
let dmg = Calc.getDmgFn({ ds, attr, profile, enemyLv })
if (detail.dmg) {
let dmgCalcRet = detail.dmg(ds, dmg)
rowData.push({
type: dmgCalcRet.avg === basicDmg.avg ? 'avg' : (dmgCalcRet.avg > basicDmg.avg ? 'gt' : 'lt'),
...dmgCalcRet
})
}
})
dmgRet.push(rowData)
})
}
return {
ret,
msg,
dmgRet,
enemyName,
dmgCfg: dmgDetail
}
}
}

88
models/ProfileReq.js Normal file
View File

@ -0,0 +1,88 @@
import Base from './Base.js'
import ProfileServ from './ProfileServ.js'
import fetch from 'node-fetch'
function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
export default class ProfileReq extends Base {
constructor ({ e, uid }) {
super()
this.e = e
this.uid = uid
}
async setCd (seconds = 60) {
let ext = new Date() * 1 + seconds * 1000
await redis.set(`miao:profile-req:${this.uid}`, ext + '', { EX: seconds })
}
async inCd () {
let ext = await redis.get(`miao:role-all:${this.uid}`)
if (!ext || isNaN(ext)) {
return false
}
let cd = new Date() * 1 - ext
if (cd < 0) {
return Math.ceil(0 - cd / 1000)
}
return false
}
err (msg = '', cd = 0) {
const msgs = {
error: '请求失败,可能是服务负载较高,请稍后重试...',
empty: '请将角色放置在【游戏内】角色展柜并打开【显示详情】等待5分钟重新获取面板'
}
msg = msgs[msg] || msg
if (msg) {
this.e.reply(msg)
}
// 设置CD
if (cd) {
this.setCd(cd)
}
return false
}
msg (msg) {
this.e.reply(msg)
}
async request () {
let Serv = ProfileReq.getServ(this.uid)
let reqParam = await Serv.getReqParam(this.uid)
let cdTime = await this.inCd()
if (cdTime) {
return this.err(`请求过快,请${cdTime}秒后重试..`)
}
await this.setCd(20)
this.msg('开始获取数据,可能会需要一定时间~')
await sleep(100)
// 发起请求
console.log('reqParam', reqParam)
let req = await fetch(reqParam.url, reqParam.params || {})
let data = await req.json()
data = await Serv.response(data, this)
console.log(data)
// 设置CD
cdTime = Serv.getCdTime(data)
if (cdTime) {
await this.setCd(cdTime)
}
return data
}
}
ProfileReq.serv = {}
ProfileReq.regServ = function (serv) {
for (let key in serv) {
ProfileReq.serv[key] = serv[key]
}
}
ProfileReq.getServ = function (uid) {
return ProfileServ.getServ({ uid, serv: ProfileReq.serv })
}

78
models/ProfileServ.js Normal file
View File

@ -0,0 +1,78 @@
import lodash from 'lodash'
import Base from './Base.js'
import { Data } from '../components/index.js'
let { sysCfg, diyCfg } = await Data.importCfg('profile')
export default class ProfileServ extends Base {
constructor (cfg) {
super()
this._name = cfg.name
this.cfgKey = cfg.cfgKey || cfg.id
this.diyCfg = diyCfg[this.cfgKey]
this.sysCfg = sysCfg[this.cfgKey]
this._cfg = cfg
}
get name () {
let url = this.getCfg('url')
return this._name || url.replace('https://', '').replace('/', '').trim()
}
// 获取当前面板服务配置
getCfg (key, def = '') {
if (!lodash.isUndefined(this.diyCfg[key])) {
return this.diyCfg[key]
}
if (!lodash.isUndefined(this.sysCfg[key])) {
return this.sysCfg[key]
}
return def
}
// 请求当前面板服务
async getReqParam (uid) {
let url = this.getCfg('url')
let profileApi = this.getCfg('listApi')
let cfg = this._cfg
let api = profileApi({
url,
uid: uid,
diyCfg: this.diyCfg
})
let param = {}
// 获取请求参数
if (cfg.request) {
param = await cfg.request.call(this, api)
}
return {
url: param.api || api,
param: param.config || {}
}
}
async response (data, req) {
// 处理返回
let cfg = this._cfg
if (cfg.response) {
return await cfg.response.call(this, data, req)
}
}
getCdTime (data) {
const requestInterval = diyCfg.requestInterval || sysCfg.requestInterval || 5
let cdTime = requestInterval * 60
if (data.ttl) {
cdTime = Math.max(cdTime, data.ttl * 1)
delete data.ttl
}
return cdTime
}
}
ProfileServ.getServ = function ({ uid, serv }) {
console.log(diyCfg)
return (diyCfg.getProfileServ || sysCfg.getProfileServ)({ uid, serv, diyCfg })
}

11
models/index.js Normal file
View File

@ -0,0 +1,11 @@
import Character from './Character.js'
import Artifact from './Artifact.js'
import Avatars from './Avatars.js'
import Abyss from './Abyss.js'
import ProfileServ from './ProfileServ.js'
import ProfileReq from './ProfileReq.js'
import ProfileData from './ProfileData.js'
import ProfileArtis from './ProfileArtis.js'
import ProfileDmg from './ProfileDmg.js'
export { Abyss, Character, Artifact, Avatars, ProfileServ, ProfileReq, ProfileData, ProfileArtis, ProfileDmg }

View File

@ -0,0 +1,160 @@
import lodash from 'lodash'
import { Format } from '../../components/index.js'
import { attrNameMap, mainAttr, subAttr } from '../../resources/meta/reliquaries/reliquaries-mark-new.js'
let ArtisMark = {
formatAttr (ds) {
if (!ds) {
return {}
}
if (lodash.isArray(ds) && ds[0] && ds[1]) {
return {
title: ds[0],
value: ds[1]
}
}
if (!ds.value) {
return {}
}
return {
title: ds.title || ds.name || ds.key || ds.id || '',
value: ds.value || ''
}
},
formatArti (ds, markCfg = false, isMain = false) {
if (ds[0] && ds[0].title) {
let ret = []
lodash.forEach(ds, (d) => {
ret.push(ArtisMark.formatArti(d, markCfg, isMain))
})
return ret
}
let title = ds.title || ds[0]
let key = ''
let val = ds.value || ds[1]
let num = ds.value || ds[1]
if (!title || title === 'undefined') {
return []
}
if (/伤害加成/.test(title) && val < 1) {
val = Format.pct(val * 100)
num = num * 100
} else if (/伤害加成|大|暴|充能|治疗/.test(title)) {
val = Format.pct(val)
} else {
val = Format.comma(val, 1)
}
if (/元素伤害加成/.test(title)) {
title = title.replace('元素伤害', '伤')
key = 'dmg'
} else if (title === '物理伤害加成') {
title = '物伤加成'
key = 'phy'
}
key = key || attrNameMap[title]
let ret = { title, value: val }
if (markCfg) {
let mark = markCfg[key] * num
if (isMain) {
mark = mark / 4 + 0.01
}
ret.mark = Format.comma(mark || 0)
ret._mark = mark || 0
}
return ret
},
getMarkClass (mark) {
let pct = mark
let scoreMap = [['D', 10], ['C', 16.5], ['B', 23.1], ['A', 29.7], ['S', 36.3], ['SS', 42.9], ['SSS', 49.5], ['ACE', 56.1], ['ACE²', 66]]
for (let idx = 0; idx < scoreMap.length; idx++) {
if (pct < scoreMap[idx][1]) {
return scoreMap[idx][0]
}
}
},
getMark (charCfg, posIdx, mainAttr, subAttr) {
let ret = 0
let { mark, maxMark, weight } = charCfg
let mAttr = ArtisMark.getAttr(mainAttr)
let fixPct = 1
if (posIdx >= 3) {
fixPct = Math.max(0, Math.min(1, (weight[mAttr] || 0) / (maxMark['m' + posIdx])))
ret += ArtisMark.getAttrMark(mark, mainAttr) / 4
}
lodash.forEach(subAttr, (ds) => {
ret += ArtisMark.getAttrMark(mark, ds)
})
return ret * (1 + fixPct) / 2 / maxMark[posIdx] * 66
},
getAttr (ds) {
let title = ds.title || ds[0] || ''
let attr = attrNameMap[title]
if (/元素伤害/.test(title)) {
attr = 'dmg'
} else if (/物理|物伤/.test(title)) {
attr = 'phy'
}
return attr
},
getAttrMark (attrMark, ds) {
if (!ds) {
return 0
}
let attr = ArtisMark.getAttr(ds)
if (!attr) {
return 0
}
let val = ds.value || ds[1]
return (attrMark[attr] || 0) * val
},
getMaxMark (attrWeight) {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
let totalMark = 0
let mMark = 0
let mAttr = ''
if (idx === 1) {
mAttr = 'hpPlus'
} else if (idx === 2) {
mAttr = 'atkPlus'
} else if (idx >= 3) {
mAttr = ArtisMark.getMaxAttr(attrWeight, mainAttr[idx])[0]
mMark = attrWeight[mAttr]
totalMark += attrWeight[mAttr] * 2
}
let sAttr = ArtisMark.getMaxAttr(attrWeight, subAttr, 4, mAttr)
lodash.forEach(sAttr, (attr, aIdx) => {
totalMark += attrWeight[attr] * (aIdx === 0 ? 6 : 1)
})
ret[idx] = totalMark
ret['m' + idx] = mMark
}
return ret
},
getMaxAttr (charAttr = {}, list2 = [], maxLen = 1, banAttr = '') {
let tmp = []
lodash.forEach(list2, (attr) => {
if (attr === banAttr) return
if (!charAttr[attr]) return
tmp.push({ attr, mark: charAttr[attr] })
})
tmp = lodash.sortBy(tmp, 'mark')
tmp = tmp.reverse()
let ret = []
lodash.forEach(tmp, (ds) => ret.push(ds.attr))
return ret.slice(0, maxLen)
}
}
export default ArtisMark

View File

@ -1,10 +1,9 @@
import fs from 'fs'
import lodash from 'lodash'
import Format from './Format.js'
import { Character } from './models.js'
import { eleBaseDmg, eleMap, attrMap } from './calc/calc-meta.js'
import { Mastery } from './calc/mastery.js'
import { Format } from '../../components/index.js'
import { Character } from '../index.js'
import { eleBaseDmg, eleMap, attrMap } from './calc-meta.js'
import Mastery from './Mastery.js'
let Calc = {
@ -45,8 +44,6 @@ let Calc = {
let ret = {}
let { attr } = profile
ret.dataSource = profile.dataSource || 'miao'
// 基础属性
lodash.forEach('atk,def,hp'.split(','), (key) => {
ret[key] = {
@ -56,28 +53,12 @@ let Calc = {
}
})
lodash.forEach('mastery,recharge'.split(','), (key) => {
lodash.forEach('mastery,recharge,cpct,cdmg,heal,dmg,phy'.split(','), (key) => {
ret[key] = {
base: attr[key] * 1 || 0,
plus: 0,
pct: 0
}
})
lodash.forEach({ cRate: 'cpct', cDmg: 'cdmg', hInc: 'heal' }, (val, key) => {
ret[val] = {
base: attr[key] * 1 || 0,
plus: 0,
pct: 0,
inc: 0
}
})
lodash.forEach('dmg,phy'.split(','), (key) => {
ret[key] = {
base: attr[key + 'Bonus'] * 1 || 0,
plus: 0,
pct: 0
inc: 0 // 护盾增效&治疗增效
}
})
@ -136,7 +117,7 @@ let Calc = {
lodash.forEach(['a', 'e', 'q'], (key) => {
let td = talentData[key] || {}
let lv = td.level || td.level_current * 1 || 1
let lv = (td.level || td.level_current || 1) * 1
let map = {}
@ -367,7 +348,7 @@ let Calc = {
}
// 防御区
let lv = profile.lv
let lv = profile.lv || profile.level
let defNum = (lv + 100) / ((lv + 100) + (enemyLv + 100) * (1 - enemyDef) * (1 - enemyIgnore))
// 抗性区
@ -503,7 +484,7 @@ let Calc = {
if (detail.check && !detail.check(Calc.getDs(attr, meta, params))) {
return
}
if (detail.cons && meta.cons * 1 < detail.cons * 1) {
if (detail.cons && meta.cons < detail.cons * 1) {
return
}
let ds = lodash.merge({ talent }, Calc.getDs(attr, meta, params))

View File

@ -1,6 +1,6 @@
import { erType } from './calc-meta.js'
export const Mastery = {
let Mastery = {
getType () {
@ -22,3 +22,4 @@ export const Mastery = {
return 1
}
}
export default Mastery

View File

@ -0,0 +1,2 @@
let ProfileInput = {}
export default ProfileInput

View File

@ -21,7 +21,7 @@
<div class="cont">
<div class="item arti-stat">
<div><strong class="mark-{{totalMarkClass}}">{{totalMarkClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{(totalMark).toFixed(1)}}</strong><span>圣遗物总分</span></div>
<div><strong>{{totalMark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
</div>
@ -29,13 +29,13 @@
<div class="artis">
<% for(let idx = 0; idx<5; idx++) {
<% for(let idx = 1; idx<=5; idx++) {
let ds = artis[idx]
%>
{{if idx === 0 }}
{{if idx === 1 }}
<div class="item no-bg"></div>
{{/if}}
<div class="item arti">
<div class="item arti {{idx}}">
{{if ds && ds.name && ds.main && ds.main.title && ds.main.title!="undefined"}}
<div class="arti-icon">
<img src="{{_res_path}}/meta/reliquaries/icon/{{ds.name}}.png"/>
@ -48,7 +48,7 @@
<ul class="detail attr">
<li class="arti-main">
<span class="title">{{ds.main.title}}</span>
<span class="val">+{{ds.main.val}}</span>
<span class="val">+{{ds.main.value}}</span>
{{if idx >1 }}
<span class="mark">{{ mark( ds.main.mark / 6 ) }}</span>
{{else}}
@ -59,8 +59,8 @@
{{if attr.title}}
<li class="{{usefulMark[attr.title]*1 > 79.9 ?`great`:(usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}"><span
class="title">{{attr.title}} </span><span
class="val">+{{attr.val}}</span>
<span class="mark">{{ ( 46.6 / 6 / 100 * attr.mark ).toFixed(1) }}</span>
class="val">+{{attr.value}}</span>
<span class="mark">{{ ( 46.6 / 6 / 100 * attr._mark ).toFixed(1) }}</span>
</li>
{{/if}}
{{/each}}

View File

@ -24,12 +24,12 @@
<span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span>
</div>
<ul class="detail attr">
<li class="arti-main"><span class="title">{{ds.main.title}}</span><span class="val">+{{ds.main.val}}</span></li>
<li class="arti-main"><span class="title">{{ds.main.title}}</span><span class="val">+{{ds.main.value}}</span></li>
{{each ds.attrs attr}}
{{if attr.title}}
<li class="{{ds.usefulMark[attr.title]*1 > 79.9 ?`great`:(ds.usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}">
<span class="title">{{attr.title}}</span><span
class="val">+{{attr.val}}</span></li>
class="val">+{{attr.value}}</span></li>
{{/if}}
{{/each}}
</ul>

View File

@ -34,10 +34,10 @@
<li><i class="i-atk"></i>攻击力<strong>{{attr.atk}}</strong><span>(+{{attr.atkPlus}})</span></li>
<li><i class="i-def"></i>防御力<strong>{{attr.def}}</strong><span>(+{{attr.defPlus}})</span></li>
<li><i class="i-mastery"></i>元素精通<strong>{{attr.mastery}}</strong></li>
<li><i class="i-cr"></i>暴击率<strong>{{attr.cRate}}</strong></li>
<li><i class="i-cd"></i>暴击伤害<strong>{{attr.cDmg}}</strong></li>
<li><i class="i-cr"></i>暴击率<strong>{{attr.cpct}}</strong></li>
<li><i class="i-cd"></i>暴击伤害<strong>{{attr.cdmg}}</strong></li>
<li><i class="i-re"></i>元素充能<strong>{{attr.recharge}}</strong></li>
<li><i class="i-dmg"></i>伤害加成<strong>{{attr.dmgBonus}}</strong></li>
<li><i class="i-dmg"></i>伤害加成<strong>{{attr.dmg}}</strong></li>
</ul>
</div>
<div class="char-cons">
@ -69,7 +69,7 @@
<div><strong>{{totalMark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
{{each artis ds}}
{{each artis ds idx}}
<div class="item arti">
{{if ds && ds.name && ds.main && ds.main.title && ds.main.title!="undefined"}}
<div class="arti-icon">
@ -81,12 +81,12 @@
<span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span>
</div>
<ul class="detail attr">
<li class="arti-main"><span class="title">{{ds.main.title}}</span><span class="val">+{{ds.main.val}}</span></li>
<li class="arti-main"><span class="title">{{ds.main.title}}</span><span class="val">+{{ds.main.value}}</span></li>
{{each ds.attrs attr}}
{{if attr.title}}
<li class="{{usefulMark[attr.title]*1 > 79.9 ?`great`:(usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}"><span
class="title">{{attr.title}} </span><span
class="val">+{{attr.val}}</span></li>
class="val">+{{attr.value}}</span></li>
{{/if}}
{{/each}}
</ul>

View File

@ -329,4 +329,4 @@
text-align: right;
padding: 8px;
}
/*# sourceMappingURL=profile-stat.css.map */
/*# sourceMappingURL=profile-lib-stat.css.map */

View File

@ -67,9 +67,9 @@
{{/if}}
</div>
<div class="td-artis">
<div class="item item-banner avatar-artis artis{{avatar?.artisMark?.sets?.length||avatar.sets.length}}">
<div class="item item-banner avatar-artis artis{{avatar?.artisMark?.names?.length||avatar.names.length}}">
<div class="artis item-icon">
{{each avatar?.artisMark?.sets || avatar?.sets || [] name}}
{{each avatar?.artisMark?.names || avatar?.names || [] name}}
<span class="img"
style="background-image:url({{_res_path}}/meta/reliquaries/icon/{{name}}.png)"></span>
{{/each}}

View File

@ -30,9 +30,9 @@
<span class="cons cons-{{weapon.affix}}">{{weapon.affix}}</span>
</div>
</div>
<div class="item avatar-artis artis{{avatar.sets.length}}">
<div class="item avatar-artis artis{{avatar.names.length}}">
<div class="artis item-icon">
{{each avatar.sets name}}
{{each avatar.names name}}
<span class="img"
style="background-image:url({{_res_path}}/meta/reliquaries/icon/{{name}}.png)"></span>
{{/each}}

View File

@ -17,10 +17,9 @@ export const details = [{
export const mainAttr = 'atk,hp,cpct,recharge'
export const buffs = [{
title: '莫娜被动:基于元素充能效率获得水元素伤害[_dmg]%',
title: '莫娜被动:基于元素充能效率获得水元素伤害[dmg]%',
data: {
_dmg: ({ calc, attr }) => calc(attr.recharge) * 0.2,
dmg: ({ calc, attr }) => attr.dataSource === 'shin' ? 0 : calc(attr.recharge) * 0.2
dmg: ({ calc, attr }) => calc(attr.recharge) * 0.2
}
}, {
title: '莫娜1命命中星异状态下的敌人水元素相关反应效果提升15%',

View File

@ -47,10 +47,8 @@ export const buffs = [
qIgnore: 60
}
}, {
title: '雷神被动:基于元素充能获得[_dmg]%雷伤加成',
title: '雷神被动:基于元素充能获得[dmg]%雷伤加成',
data: {
_dmg: ({ attr }) => Math.max(attr.recharge.base + attr.recharge.plus - 100, 0) * 0.4,
dmg: ({ attr }) =>
attr.dataSource === 'shin' ? 0 : Math.max(attr.recharge.base + attr.recharge.plus - 100, 0) * 0.4
dmg: ({ attr }) => Math.max(attr.recharge.base + attr.recharge.plus - 100, 0) * 0.4
}
}]

View File

@ -40,7 +40,7 @@ lodash.forEach(readDir, (c) => {
// 正面
// 角色条
img(char, char.imgs.profile, "profile-data.png");
img(char, char.imgs.profile, "profile.png");
// 名片
img(char, char.imgs.party, "party.png");
// img(char, char.imgs.char, "char.png");

View File

@ -1,148 +1,146 @@
import Data from "../components/Data.js";
import lodash from "lodash";
import { Character } from "../components/models.js";
import fs from "fs";
import lodash from 'lodash'
import { Character } from '../models/index.js'
import { Data } from '../components/index.js'
import fs from 'fs'
import { roleId, abbr } from "../../../config/genshin/roleId.js";
import { roleId, abbr } from '../../../config/genshin/roleId.js'
let roleIdMap = {};
let roleIdMap = {}
lodash.forEach(roleId, (names, id) => {
roleIdMap[names[0]] = id;
roleIdMap[names[0]] = id
})
let _root = process.cwd();
let characterMeta = [];//Data.readJSON("./plugins/miao-plugin/components/meta", "characters.json");
let characters = {};
let pathName = process.cwd() + "/plugins/miao-plugin/resources/meta/character/";
let _root = process.cwd()
let characterMeta = []// Data.readJSON("./plugins/miao-plugin/components/meta", "characters.json");
let characters = {}
let pathName = process.cwd() + '/plugins/miao-plugin/resources/meta/character/'
// 获取指定角色的Meta信息
const getMetaData = function (name) {
if (!characterMeta[name]) {
return {};
return {}
}
const metaCfg = { lowerFirstKey: true },
meta = characterMeta[name];
const metaCfg = { lowerFirstKey: true }
const meta = characterMeta[name]
// 处理基础信息
let ret = Data.getData(meta, "Name,Key,Title,desc:Description,astro:AstrolabeName", metaCfg);
let ret = Data.getData(meta, 'Name,Key,Title,desc:Description,astro:AstrolabeName', metaCfg)
ret.star = /4star/.test(meta.Star) ? 4 : 5;
ret.star = /4star/.test(meta.Star) ? 4 : 5
let weaponid = /s_(\d*).png$/.exec(meta.Weapon);
let weaponid = /s_(\d*).png$/.exec(meta.Weapon)
if (weaponid) {
ret.weapon = {
233101: "长柄武器",
33101: "单手剑",
43101: "法器",
163101: "双手剑",
213101: "弓"
233101: '长柄武器',
33101: '单手剑',
43101: '法器',
163101: '双手剑',
213101: '弓'
}[weaponid[1]]
}
// 处理图像信息
//ret.img = Data.getData(meta, "Weapon,Element,City,Profile,GachaCard,GachaSplash,Source", metaCfg);
// ret.img = Data.getData(meta, "Weapon,Element,City,Profile,GachaCard,GachaSplash,Source", metaCfg);
// 处理元素
let elemRet = /([^\/]*).png$/.exec(meta.Element);
console.log(elemRet[1]);
let elemRet = /([^\/]*).png$/.exec(meta.Element)
console.log(elemRet[1])
if (elemRet && elemRet[1]) {
ret.elem = elemRet[1];
ret.element = elemName[ret.elem];
ret.elem = elemRet[1]
ret.element = elemName[ret.elem]
}
// 处理属性
ret.stat = Data.getData(meta, "hp:BaseHP,atk:BaseATK,def:BaseDEF,growStat:AscensionStat,growValue:AscensionStatValue", metaCfg);
ret.lvStat = lodash.map(meta.CharStat, (d) => Data.getData(d, "Name,Values", metaCfg));
ret.stat = Data.getData(meta, 'hp:BaseHP,atk:BaseATK,def:BaseDEF,growStat:AscensionStat,growValue:AscensionStatValue', metaCfg)
ret.lvStat = lodash.map(meta.CharStat, (d) => Data.getData(d, 'Name,Values', metaCfg))
if (/Mende/.test(meta.City)) {
ret.city = "蒙德"
ret.city = '蒙德'
} else if (/Liyue/.test(meta.City)) {
ret.city = "璃月";
ret.city = '璃月'
} else if (/Daoqi/.test(meta.City)) {
ret.city = "稻妻";
ret.city = '稻妻'
}
// 处理材料
let itemKey = lodash.map("talent,boss,gemStone,Local,monster,weekly".split(","), (a) => `${a}:${lodash.upperFirst(a)}.Name`);
let itemKey = lodash.map('talent,boss,gemStone,Local,monster,weekly'.split(','), (a) => `${a}:${lodash.upperFirst(a)}.Name`)
ret.item = Data.getData(meta, itemKey, metaCfg)
// 处理天赋
ret.talent = {
a: getTalentData(meta.NormalAttack),
e: getTalentData(meta.TalentE),
q: getTalentData(meta.TalentQ),
};
q: getTalentData(meta.TalentQ)
}
// 处理其他天赋
ret.passive = lodash.map(meta.PassiveTalents, (d) => Data.getData(d, "Name,desc:Description", metaCfg))
ret.passive = lodash.map(meta.PassiveTalents, (d) => Data.getData(d, 'Name,desc:Description', metaCfg))
// 处理命座信息
let cons = {};
let cons = {}
lodash.forEach(meta.Constellation, (data, key) => {
cons[key.replace("Constellation", "")] = Data.getData(data, "Name,desc:Description", metaCfg);
cons[key.replace('Constellation', '')] = Data.getData(data, 'Name,desc:Description', metaCfg)
})
ret.cons = cons;
return ret;
ret.cons = cons
return ret
}
// 获取Meta中的天赋信息
const getTalentData = function (data) {
let ret = Data.getData(data, "Name,desc:Description", { lowerFirstKey: true });
let attr = [], table = [], tableKeys;
let ret = Data.getData(data, 'Name,desc:Description', { lowerFirstKey: true })
let attr = []; let table = []; let tableKeys
lodash.forEach(data.Table, (tr) => {
let tmp = { name: tr.Name }, isTable = true, isDef = false, lastVal;
let tmp = { name: tr.Name }; let isTable = true; let isDef = false; let lastVal
// 检查当前行是否是表格数据
lodash.forEach(tr.Values, (v) => {
// 如果为空则退出循环
if (v === "") {
isTable = false;
return false;
if (v === '') {
isTable = false
return false
}
if (typeof (lastVal) === "undefined") {
if (typeof (lastVal) === 'undefined') {
// 设定初始值
lastVal = v;
lastVal = v
} else if (lastVal != v) {
// 如果与初始值不一样,则标记退出循环
isDef = true;
return false;
isDef = true
return false
}
});
})
if (isTable && isDef) {
if (!tableKeys) {
tableKeys = lodash.keys(tr.Values);
tableKeys = lodash.keys(tr.Values)
}
tmp.value = lodash.map(tableKeys, (k) => tr.Values[k])
table.push(tmp);
table.push(tmp)
} else {
tmp.value = lastVal;
tmp.value = lastVal
attr.push(tmp)
}
})
ret.attr = attr;
ret.table = table;
ret.tableKeys = tableKeys;
return ret;
ret.attr = attr
ret.table = table
ret.tableKeys = tableKeys
return ret
}
lodash.forEach(characterMeta, (c) => {
let meta = Character.getMetaData(c.Name);
let meta = Character.getMetaData(c.Name)
let data = {
id: roleIdMap[meta.name],
key: meta.key,
name: meta.name,
abbr: abbr[meta.name] || meta.name,
city: meta.city
};
}
lodash.defaults(data, meta)
Data.createDir(pathName, data.name)
fs.writeFileSync(`${pathName}${data.name}/data.json`, JSON.stringify(data, "", "\t"));
characters[data.id] = { id: data.id, key: data.key, name: meta.name };
fs.writeFileSync(`${pathName}${data.name}/data.json`, JSON.stringify(data, '', '\t'))
characters[data.id] = { id: data.id, key: data.key, name: meta.name }
})
fs.writeFileSync(`${pathName}index.json`, JSON.stringify(characters, "", "\t"));
fs.writeFileSync(`${pathName}index.json`, JSON.stringify(characters, '', '\t'))

View File

@ -1,6 +1,5 @@
import Profile from '../components/Profile.js'
import Calc from '../components/Calc.js'
import { Character } from '../components/models.js'
import Calc from '../models/profile-lib/Calc.js'
import { Character } from '../models/index.js'
import Miao from '../components/profile-data/miao.js'
export async function calcDmg (inputData, enemyLv = 86) {

View File

@ -27,7 +27,7 @@ lodash.forEach(readDir, (c) => {
// 正面
// 角色条
img(char, char.imgs.profile, "profile-data.png");
img(char, char.imgs.profile, "profile.png");
// 名片
img(char, char.imgs.party, "party.png");
// img(char, char.imgs.char, "char.png");